summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/bus.c10
-rw-r--r--drivers/acpi/power.c36
-rw-r--r--drivers/ata/ahci.c10
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/bluetooth/btusb.c12
-rw-r--r--drivers/bluetooth/hci_ath.c2
-rw-r--r--drivers/char/mwave/mwavedd.c16
-rw-r--r--drivers/char/pcmcia/synclink_cs.c131
-rw-r--r--drivers/char/ttyprintk.c33
-rw-r--r--drivers/clk/Kconfig13
-rw-r--r--drivers/clk/Makefile9
-rw-r--r--drivers/clk/clk-ls1x.c111
-rw-r--r--drivers/clk/clk-max77686.c244
-rw-r--r--drivers/clk/clk-prima2.c1171
-rw-r--r--drivers/clk/clk.c57
-rw-r--r--drivers/clk/mmp/Makefile9
-rw-r--r--drivers/clk/mmp/clk-apbc.c152
-rw-r--r--drivers/clk/mmp/clk-apmu.c97
-rw-r--r--drivers/clk/mmp/clk-frac.c153
-rw-r--r--drivers/clk/mmp/clk-mmp2.c449
-rw-r--r--drivers/clk/mmp/clk-pxa168.c346
-rw-r--r--drivers/clk/mmp/clk-pxa910.c320
-rw-r--r--drivers/clk/mmp/clk.h35
-rw-r--r--drivers/clk/mxs/clk-imx23.c55
-rw-r--r--drivers/clk/mxs/clk-imx28.c113
-rw-r--r--drivers/clk/ux500/Makefile12
-rw-r--r--drivers/clk/ux500/clk-prcc.c164
-rw-r--r--drivers/clk/ux500/clk-prcmu.c252
-rw-r--r--drivers/clk/ux500/clk.h48
-rw-r--r--drivers/clk/ux500/u8500_clk.c477
-rw-r--r--drivers/clk/ux500/u8540_clk.c21
-rw-r--r--drivers/clk/ux500/u9540_clk.c21
-rw-r--r--drivers/clk/versatile/Makefile1
-rw-r--r--drivers/clk/versatile/clk-realview.c114
-rw-r--r--drivers/crypto/caam/key_gen.c1
-rw-r--r--drivers/dma/omap-dma.c2
-rw-r--r--drivers/extcon/extcon-max77693.c19
-rw-r--r--drivers/gpio/gpio-omap.c15
-rw-r--r--drivers/gpio/gpio-pxa.c77
-rw-r--r--drivers/gpio/gpio-samsung.c63
-rw-r--r--drivers/gpio/gpio-twl4030.c90
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c3
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c3
-rw-r--r--drivers/gpu/drm/exynos/Kconfig2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c52
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c11
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c6
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_device.c2
-rw-r--r--drivers/gpu/drm/i810/i810_dma.c3
-rw-r--r--drivers/gpu/drm/i810/i810_drv.c3
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c3
-rw-r--r--drivers/gpu/drm/i915/intel_display.c6
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c11
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c31
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c3
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c15
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_gpio.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c4
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c163
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c8
-rw-r--r--drivers/gpu/drm/savage/savage_drv.c3
-rw-r--r--drivers/gpu/drm/sis/sis_drv.c3
-rw-r--r--drivers/gpu/drm/tdfx/tdfx_drv.c3
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c3
-rw-r--r--drivers/gpu/drm/via/via_drv.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/Kconfig8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c8
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c73
-rw-r--r--drivers/hwmon/ina2xx.c30
-rw-r--r--drivers/hwmon/twl4030-madc-hwmon.c9
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c6
-rw-r--r--drivers/i2c/busses/Kconfig6
-rw-r--r--drivers/i2c/busses/Makefile5
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c11
-rw-r--r--drivers/i2c/busses/i2c-i801.c3
-rw-r--r--drivers/i2c/busses/i2c-mxs.c13
-rw-r--r--drivers/i2c/busses/i2c-pnx.c53
-rw-r--r--drivers/i2c/i2c-core.c22
-rw-r--r--drivers/iio/adc/at91_adc.c2
-rw-r--r--drivers/input/keyboard/Kconfig2
-rw-r--r--drivers/input/keyboard/omap-keypad.c154
-rw-r--r--drivers/input/misc/ab8500-ponkey.c4
-rw-r--r--drivers/isdn/capi/capi.c3
-rw-r--r--drivers/isdn/gigaset/interface.c7
-rw-r--r--drivers/isdn/hardware/mISDN/avmfritz.c3
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c3
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c3
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c3
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c3
-rw-r--r--drivers/isdn/i4l/isdn_tty.c41
-rw-r--r--drivers/isdn/mISDN/hwchannel.c9
-rw-r--r--drivers/media/video/omap/omap_vout.c1
-rw-r--r--drivers/media/video/omap3isp/isp.c2
-rw-r--r--drivers/mfd/88pm800.c5
-rw-r--r--drivers/mfd/88pm805.c3
-rw-r--r--drivers/mfd/88pm860x-core.c21
-rw-r--r--drivers/mfd/aat2870-core.c2
-rw-r--r--drivers/mfd/ab3100-core.c2
-rw-r--r--drivers/mfd/ab8500-core.c10
-rw-r--r--drivers/mfd/arizona-core.c6
-rw-r--r--drivers/mfd/asic3.c6
-rw-r--r--drivers/mfd/cs5535-mfd.c2
-rw-r--r--drivers/mfd/da9052-core.c2
-rw-r--r--drivers/mfd/davinci_voicecodec.c2
-rw-r--r--drivers/mfd/db8500-prcmu.c44
-rw-r--r--drivers/mfd/dbx500-prcmu-regs.h4
-rw-r--r--drivers/mfd/htc-pasic3.c5
-rw-r--r--drivers/mfd/intel_msic.c4
-rw-r--r--drivers/mfd/janz-cmodio.c2
-rw-r--r--drivers/mfd/jz4740-adc.c3
-rw-r--r--drivers/mfd/lm3533-core.c7
-rw-r--r--drivers/mfd/lpc_ich.c24
-rw-r--r--drivers/mfd/lpc_sch.c6
-rw-r--r--drivers/mfd/max77686.c2
-rw-r--r--drivers/mfd/max77693-irq.c36
-rw-r--r--drivers/mfd/max77693.c16
-rw-r--r--drivers/mfd/max8925-core.c12
-rw-r--r--drivers/mfd/max8997.c2
-rw-r--r--drivers/mfd/max8998.c8
-rw-r--r--drivers/mfd/mc13xxx-core.c2
-rw-r--r--drivers/mfd/mfd-core.c12
-rw-r--r--drivers/mfd/palmas.c3
-rw-r--r--drivers/mfd/rc5t583.c2
-rw-r--r--drivers/mfd/rdc321x-southbridge.c3
-rw-r--r--drivers/mfd/sec-core.c8
-rw-r--r--drivers/mfd/sta2x11-mfd.c4
-rw-r--r--drivers/mfd/stmpe.c2
-rw-r--r--drivers/mfd/t7l66xb.c2
-rw-r--r--drivers/mfd/tc3589x.c8
-rw-r--r--drivers/mfd/tc6387xb.c2
-rw-r--r--drivers/mfd/tc6393xb.c4
-rw-r--r--drivers/mfd/ti-ssp.c2
-rw-r--r--drivers/mfd/timberdale.c12
-rw-r--r--drivers/mfd/tps6105x.c2
-rw-r--r--drivers/mfd/tps6507x.c2
-rw-r--r--drivers/mfd/tps65090.c2
-rw-r--r--drivers/mfd/tps65217.c130
-rw-r--r--drivers/mfd/tps6586x.c3
-rw-r--r--drivers/mfd/tps65910.c2
-rw-r--r--drivers/mfd/tps65912-core.c2
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/twl4030-audio.c2
-rw-r--r--drivers/mfd/twl6040-core.c2
-rw-r--r--drivers/mfd/vx855.c2
-rw-r--r--drivers/mfd/wl1273-core.c2
-rw-r--r--drivers/mfd/wm831x-core.c16
-rw-r--r--drivers/mfd/wm8400-core.c2
-rw-r--r--drivers/mfd/wm8994-core.c4
-rw-r--r--drivers/misc/ibmasm/uart.c16
-rw-r--r--drivers/misc/pti.c128
-rw-r--r--drivers/mmc/card/sdio_uart.c24
-rw-r--r--drivers/mmc/host/omap.c1
-rw-r--r--drivers/mmc/host/omap_hsmmc.c1
-rw-r--r--drivers/mtd/nand/ams-delta.c8
-rw-r--r--drivers/mtd/nand/omap2.c301
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c87
-rw-r--r--drivers/mtd/onenand/omap2.c32
-rw-r--r--drivers/net/can/mcp251x.c11
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h11
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h25
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c8
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c18
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c21
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c15
-rw-r--r--drivers/net/ethernet/i825xx/znet.c13
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c106
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h76
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c116
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.c1
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c22
-rw-r--r--drivers/net/irda/irtty-sir.c10
-rw-r--r--drivers/net/usb/hso.c19
-rw-r--r--drivers/net/usb/qmi_wwan.c9
-rw-r--r--drivers/net/usb/sierra_net.c2
-rw-r--r--drivers/net/usb/usbnet.c16
-rw-r--r--drivers/net/wan/ixp4xx_hss.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c105
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c30
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c15
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h17
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c22
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h3
-rw-r--r--drivers/parport/parport_gsc.c1
-rw-r--r--drivers/parport/parport_serial.c11
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c58
-rw-r--r--drivers/platform/x86/acer-wmi.c2
-rw-r--r--drivers/platform/x86/apple-gmux.c24
-rw-r--r--drivers/platform/x86/asus-laptop.c10
-rw-r--r--drivers/platform/x86/asus-wmi.c4
-rw-r--r--drivers/platform/x86/eeepc-laptop.c10
-rw-r--r--drivers/platform/x86/samsung-laptop.c4
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c13
-rw-r--r--drivers/power/avs/smartreflex.c2
-rw-r--r--drivers/pwm/pwm-tiecap.c7
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c29
-rw-r--r--drivers/regulator/tps65217-regulator.c124
-rw-r--r--drivers/rtc/rtc-ab8500.c6
-rw-r--r--drivers/rtc/rtc-pxa.c11
-rw-r--r--drivers/s390/char/con3215.c28
-rw-r--r--drivers/s390/char/sclp_tty.c1
-rw-r--r--drivers/s390/char/sclp_vt220.c1
-rw-r--r--drivers/s390/char/tty3270.c34
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c3
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c13
-rw-r--r--drivers/scsi/scsi_error.c10
-rw-r--r--drivers/scsi/scsi_lib.c5
-rw-r--r--drivers/scsi/scsi_scan.c10
-rw-r--r--drivers/spi/spi-omap-uwire.c3
-rw-r--r--drivers/staging/android/android_alarm.h4
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c7
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c7
-rw-r--r--drivers/staging/comedi/drivers/das08.c11
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c4
-rw-r--r--drivers/staging/iio/adc/ad7192.c2
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c2
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c2
-rw-r--r--drivers/staging/iio/meter/ade7753.c2
-rw-r--r--drivers/staging/iio/meter/ade7754.c2
-rw-r--r--drivers/staging/iio/meter/ade7759.c2
-rw-r--r--drivers/staging/ipack/devices/ipoctal.c14
-rw-r--r--drivers/staging/nvec/nvec.c2
-rw-r--r--drivers/staging/omapdrm/omap_connector.c41
-rw-r--r--drivers/staging/ozwpan/ozcdev.c3
-rw-r--r--drivers/staging/rtl8712/recv_linux.c7
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c18
-rw-r--r--drivers/staging/speakup/serialio.h3
-rw-r--r--drivers/staging/tidspbridge/core/wdt.c2
-rw-r--r--drivers/staging/vt6656/dpc.c2
-rw-r--r--drivers/staging/vt6656/rxtx.c38
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c4
-rw-r--r--drivers/staging/zcache/zcache-main.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c11
-rw-r--r--drivers/target/target_core_alua.c7
-rw-r--r--drivers/target/target_core_device.c7
-rw-r--r--drivers/target/target_core_iblock.c17
-rw-r--r--drivers/target/target_core_pr.c8
-rw-r--r--drivers/target/target_core_pscsi.c29
-rw-r--r--drivers/target/target_core_spc.c35
-rw-r--r--drivers/target/target_core_transport.c148
-rw-r--r--drivers/tty/amiserial.c45
-rw-r--r--drivers/tty/bfin_jtag_comm.c1
-rw-r--r--drivers/tty/cyclades.c102
-rw-r--r--drivers/tty/ehv_bytechan.c9
-rw-r--r--drivers/tty/hvc/hvc_console.c31
-rw-r--r--drivers/tty/hvc/hvcs.c82
-rw-r--r--drivers/tty/hvc/hvsi.c2
-rw-r--r--drivers/tty/hvc/hvsi_lib.c2
-rw-r--r--drivers/tty/ipwireless/tty.c2
-rw-r--r--drivers/tty/isicom.c13
-rw-r--r--drivers/tty/moxa.c39
-rw-r--r--drivers/tty/mxser.c63
-rw-r--r--drivers/tty/n_gsm.c142
-rw-r--r--drivers/tty/n_r3964.c10
-rw-r--r--drivers/tty/n_tty.c29
-rw-r--r--drivers/tty/nozomi.c4
-rw-r--r--drivers/tty/pty.c234
-rw-r--r--drivers/tty/rocket.c22
-rw-r--r--drivers/tty/serial/68328serial.c23
-rw-r--r--drivers/tty/serial/8250/8250.c84
-rw-r--r--drivers/tty/serial/8250/8250.h34
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c22
-rw-r--r--drivers/tty/serial/8250/8250_dw.c38
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c26
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c26
-rw-r--r--drivers/tty/serial/8250/8250_pci.c205
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c28
-rw-r--r--drivers/tty/serial/8250/serial_cs.c30
-rw-r--r--drivers/tty/serial/Kconfig50
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/altera_uart.c6
-rw-r--r--drivers/tty/serial/amba-pl010.c15
-rw-r--r--drivers/tty/serial/amba-pl011.c89
-rw-r--r--drivers/tty/serial/bfin_uart.c2
-rw-r--r--drivers/tty/serial/crisv10.c45
-rw-r--r--drivers/tty/serial/ifx6x60.c4
-rw-r--r--drivers/tty/serial/imx.c35
-rw-r--r--drivers/tty/serial/ioc3_serial.c3
-rw-r--r--drivers/tty/serial/ioc4_serial.c5
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c8
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c823
-rw-r--r--drivers/tty/serial/m32r_sio.c36
-rw-r--r--drivers/tty/serial/max3100.c12
-rw-r--r--drivers/tty/serial/max3107.c1215
-rw-r--r--drivers/tty/serial/max3107.h441
-rw-r--r--drivers/tty/serial/max310x.c1260
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c8
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/msm_smd_tty.c8
-rw-r--r--drivers/tty/serial/mxs-auart.c7
-rw-r--r--drivers/tty/serial/of_serial.c13
-rw-r--r--drivers/tty/serial/omap-serial.c860
-rw-r--r--drivers/tty/serial/pch_uart.c4
-rw-r--r--drivers/tty/serial/pxa.c14
-rw-r--r--drivers/tty/serial/samsung.c46
-rw-r--r--drivers/tty/serial/sc26xx.c4
-rw-r--r--drivers/tty/serial/sccnxp.c985
-rw-r--r--drivers/tty/serial/serial_core.c223
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c8
-rw-r--r--drivers/tty/serial/sunsu.c8
-rw-r--r--drivers/tty/synclink.c86
-rw-r--r--drivers/tty/synclink_gt.c37
-rw-r--r--drivers/tty/synclinkmp.c58
-rw-r--r--drivers/tty/tty_io.c375
-rw-r--r--drivers/tty/tty_ioctl.c100
-rw-r--r--drivers/tty/tty_ldisc.c78
-rw-r--r--drivers/tty/tty_mutex.c71
-rw-r--r--drivers/tty/tty_port.c94
-rw-r--r--drivers/tty/vt/keyboard.c50
-rw-r--r--drivers/tty/vt/vt.c141
-rw-r--r--drivers/usb/chipidea/udc.c59
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/class/cdc-wdm.c12
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/dwc3/core.c9
-rw-r--r--drivers/usb/dwc3/ep0.c1
-rw-r--r--drivers/usb/dwc3/gadget.c19
-rw-r--r--drivers/usb/gadget/at91_udc.c6
-rw-r--r--drivers/usb/gadget/dummy_hcd.c41
-rw-r--r--drivers/usb/gadget/f_fs.c4
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c3
-rw-r--r--drivers/usb/gadget/u_serial.c7
-rw-r--r--drivers/usb/host/ehci-q.c12
-rw-r--r--drivers/usb/host/ohci-at91.c10
-rw-r--r--drivers/usb/host/pci-quirks.c42
-rw-r--r--drivers/usb/host/pci-quirks.h1
-rw-r--r--drivers/usb/host/xhci-hub.c42
-rw-r--r--drivers/usb/host/xhci-plat.c2
-rw-r--r--drivers/usb/host/xhci.c123
-rw-r--r--drivers/usb/host/xhci.h6
-rw-r--r--drivers/usb/musb/musb_host.c2
-rw-r--r--drivers/usb/musb/musbhsdma.c2
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c4
-rw-r--r--drivers/usb/serial/ark3116.c4
-rw-r--r--drivers/usb/serial/belkin_sa.c2
-rw-r--r--drivers/usb/serial/console.c4
-rw-r--r--drivers/usb/serial/cp210x.c8
-rw-r--r--drivers/usb/serial/cypress_m8.c40
-rw-r--r--drivers/usb/serial/digi_acceleport.c14
-rw-r--r--drivers/usb/serial/empeg.c2
-rw-r--r--drivers/usb/serial/f81232.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c24
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h29
-rw-r--r--drivers/usb/serial/io_edgeport.c12
-rw-r--r--drivers/usb/serial/io_ti.c12
-rw-r--r--drivers/usb/serial/ir-usb.c2
-rw-r--r--drivers/usb/serial/iuu_phoenix.c28
-rw-r--r--drivers/usb/serial/keyspan.c6
-rw-r--r--drivers/usb/serial/keyspan_pda.c4
-rw-r--r--drivers/usb/serial/kl5kusb105.c18
-rw-r--r--drivers/usb/serial/kobil_sct.c14
-rw-r--r--drivers/usb/serial/mct_u232.c4
-rw-r--r--drivers/usb/serial/metro-usb.c6
-rw-r--r--drivers/usb/serial/mos7720.c14
-rw-r--r--drivers/usb/serial/mos7840.c12
-rw-r--r--drivers/usb/serial/option.c6
-rw-r--r--drivers/usb/serial/oti6858.c10
-rw-r--r--drivers/usb/serial/pl2303.c6
-rw-r--r--drivers/usb/serial/quatech2.c4
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/spcp8x5.c12
-rw-r--r--drivers/usb/serial/ssu100.c4
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c10
-rw-r--r--drivers/usb/serial/usb-serial.c7
-rw-r--r--drivers/usb/serial/usb_wwan.c2
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/video/backlight/omap1_bl.c2
-rw-r--r--drivers/video/omap2/dss/dispc.c1
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c1
-rw-r--r--drivers/w1/masters/omap_hdq.c3
-rw-r--r--drivers/watchdog/omap_wdt.c5
407 files changed, 12798 insertions, 5309 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9628652e080c..e0596954290b 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -237,6 +237,16 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state)
} else if (result == ACPI_STATE_D3_HOT) {
result = ACPI_STATE_D3;
}
+
+ /*
+ * If we were unsure about the device parent's power state up to this
+ * point, the fact that the device is in D0 implies that the parent has
+ * to be in D0 too.
+ */
+ if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN
+ && result == ACPI_STATE_D0)
+ device->parent->power.state = ACPI_STATE_D0;
+
*state = result;
out:
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fc1803414629..40e38a06ba85 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -107,6 +107,7 @@ struct acpi_power_resource {
/* List of devices relying on this power resource */
struct acpi_power_resource_device *devices;
+ struct mutex devices_lock;
};
static struct list_head acpi_power_resource_list;
@@ -225,7 +226,6 @@ static void acpi_power_on_device(struct acpi_power_managed_device *device)
static int __acpi_power_on(struct acpi_power_resource *resource)
{
- struct acpi_power_resource_device *device_list = resource->devices;
acpi_status status = AE_OK;
status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
@@ -238,19 +238,15 @@ static int __acpi_power_on(struct acpi_power_resource *resource)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
resource->name));
- while (device_list) {
- acpi_power_on_device(device_list->device);
-
- device_list = device_list->next;
- }
-
return 0;
}
static int acpi_power_on(acpi_handle handle)
{
int result = 0;
+ bool resume_device = false;
struct acpi_power_resource *resource = NULL;
+ struct acpi_power_resource_device *device_list;
result = acpi_power_get_context(handle, &resource);
if (result)
@@ -266,10 +262,25 @@ static int acpi_power_on(acpi_handle handle)
result = __acpi_power_on(resource);
if (result)
resource->ref_count--;
+ else
+ resume_device = true;
}
mutex_unlock(&resource->resource_lock);
+ if (!resume_device)
+ return result;
+
+ mutex_lock(&resource->devices_lock);
+
+ device_list = resource->devices;
+ while (device_list) {
+ acpi_power_on_device(device_list->device);
+ device_list = device_list->next;
+ }
+
+ mutex_unlock(&resource->devices_lock);
+
return result;
}
@@ -355,7 +366,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev,
if (acpi_power_get_context(res_handle, &resource))
return;
- mutex_lock(&resource->resource_lock);
+ mutex_lock(&resource->devices_lock);
prev = NULL;
curr = resource->devices;
while (curr) {
@@ -372,7 +383,7 @@ static void __acpi_power_resource_unregister_device(struct device *dev,
prev = curr;
curr = curr->next;
}
- mutex_unlock(&resource->resource_lock);
+ mutex_unlock(&resource->devices_lock);
}
/* Unlink dev from all power resources in _PR0 */
@@ -414,10 +425,10 @@ static int __acpi_power_resource_register_device(
power_resource_device->device = powered_device;
- mutex_lock(&resource->resource_lock);
+ mutex_lock(&resource->devices_lock);
power_resource_device->next = resource->devices;
resource->devices = power_resource_device;
- mutex_unlock(&resource->resource_lock);
+ mutex_unlock(&resource->devices_lock);
return 0;
}
@@ -462,7 +473,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
return ret;
no_power_resource:
- printk(KERN_WARNING PREFIX "Invalid Power Resource to register!");
+ printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!");
return -ENODEV;
}
EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
@@ -721,6 +732,7 @@ static int acpi_power_add(struct acpi_device *device)
resource->device = device;
mutex_init(&resource->resource_lock);
+ mutex_init(&resource->devices_lock);
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 50d5dea0ff59..7862d17976b7 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -268,6 +268,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
+ /* JMicron 362B and 362C have an AHCI function with IDE class code */
+ { PCI_VDEVICE(JMICRON, 0x2362), board_ahci_ign_iferr },
+ { PCI_VDEVICE(JMICRON, 0x236f), board_ahci_ign_iferr },
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
@@ -393,6 +396,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
{ PCI_DEVICE(0x1b4b, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
+ { PCI_DEVICE(0x1b4b, 0x9192),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
{ PCI_DEVICE(0x1b4b, 0x91a3),
.driver_data = board_ahci_yes_fbs },
@@ -400,7 +405,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */
/* Asmedia */
- { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */
+ { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */
+ { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */
+ { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
+ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 11f36e502136..fc2de5528dcc 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -86,6 +86,7 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C) },
+ { USB_DEVICE(0x0489, 0xE036) },
{ } /* Terminating entry */
};
@@ -109,6 +110,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cef3bac1a543..654e248763ef 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -52,6 +52,9 @@ static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Apple-specific (Broadcom) devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
+
/* Broadcom SoftSailing reporting vendor specific */
{ USB_DEVICE(0x0a5c, 0x21e1) },
@@ -94,16 +97,14 @@ static struct usb_device_id btusb_table[] = {
/* Broadcom BCM20702A0 */
{ USB_DEVICE(0x0489, 0xe042) },
- { USB_DEVICE(0x0a5c, 0x21e3) },
- { USB_DEVICE(0x0a5c, 0x21e6) },
- { USB_DEVICE(0x0a5c, 0x21e8) },
- { USB_DEVICE(0x0a5c, 0x21f3) },
- { USB_DEVICE(0x0a5c, 0x21f4) },
{ USB_DEVICE(0x413c, 0x8197) },
/* Foxconn - Hon Hai */
{ USB_DEVICE(0x0489, 0xe033) },
+ /*Broadcom devices with vendor specific id */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+
{ } /* Terminating entry */
};
@@ -141,6 +142,7 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 12172a6a95c4..0bc8a6a6a148 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
return status;
/* Disable Automatic RTSCTS */
- memcpy(&ktermios, tty->termios, sizeof(ktermios));
+ ktermios = tty->termios;
ktermios.c_cflag &= ~CRTSCTS;
tty_set_termios(tty, &ktermios);
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 1d82d5838f0c..164544afd680 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
static int register_serial_portandirq(unsigned int port, int irq)
{
- struct uart_port uart;
+ struct uart_8250_port uart;
switch ( port ) {
case 0x3f8:
@@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
} /* switch */
/* irq is okay */
- memset(&uart, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
- uart.uartclk = 1843200;
- uart.iobase = port;
- uart.irq = irq;
- uart.iotype = UPIO_PORT;
- uart.flags = UPF_SHARE_IRQ;
- return serial8250_register_port(&uart);
+ uart.port.uartclk = 1843200;
+ uart.port.iobase = port;
+ uart.port.irq = irq;
+ uart.port.iotype = UPIO_PORT;
+ uart.port.flags = UPF_SHARE_IRQ;
+ return serial8250_register_8250_port(&uart);
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0a484b4a1b02..3f57d5de3957 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1050,7 +1050,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- if (info->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
@@ -1344,7 +1344,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
- if (!tty || tty->termios->c_cflag & HUPCL) {
+ if (!tty || tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -1385,7 +1385,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
- if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
+ if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -1398,14 +1398,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
unsigned cflag;
int bits_per_char;
- if (!tty || !tty->termios)
+ if (!tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -1728,7 +1728,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1757,7 +1757,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
mgslpc_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -2293,8 +2293,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
tty->driver->name );
/* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
+ if ((tty->termios.c_cflag == old_termios->c_cflag)
+ && (RELEVANT_IFLAG(tty->termios.c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
@@ -2302,7 +2302,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -2311,9 +2311,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -2324,7 +2324,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
#if SYNCLINK_GENERIC_HDLC
hdlcdev_init(info);
#endif
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->p_dev->dev);
}
static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
last->next_device = info->next_device;
else
mgslpc_device_list = info->next_device;
+ tty_unregister_device(serial_driver, info->line);
#if SYNCLINK_GENERIC_HDLC
hdlcdev_exit(info);
#endif
@@ -2798,77 +2801,63 @@ static const struct tty_operations mgslpc_ops = {
.proc_fops = &mgslpc_proc_fops,
};
-static void synclink_cs_cleanup(void)
+static int __init synclink_cs_init(void)
{
int rc;
- while(mgslpc_device_list)
- mgslpc_remove_device(mgslpc_device_list);
-
- if (serial_driver) {
- if ((rc = tty_unregister_driver(serial_driver)))
- printk("%s(%d) failed to unregister tty driver err=%d\n",
- __FILE__,__LINE__,rc);
- put_tty_driver(serial_driver);
+ if (break_on_load) {
+ mgslpc_get_text_ptr();
+ BREAKPOINT();
}
- pcmcia_unregister_driver(&mgslpc_driver);
-}
-
-static int __init synclink_cs_init(void)
-{
- int rc;
-
- if (break_on_load) {
- mgslpc_get_text_ptr();
- BREAKPOINT();
- }
-
- if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
- return rc;
-
- serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
- if (!serial_driver) {
- rc = -ENOMEM;
- goto error;
- }
+ serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(serial_driver)) {
+ rc = PTR_ERR(serial_driver);
+ goto err;
+ }
- /* Initialize the tty_driver structure */
-
- serial_driver->driver_name = "synclink_cs";
- serial_driver->name = "ttySLP";
- serial_driver->major = ttymajor;
- 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 =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &mgslpc_ops);
-
- if ((rc = tty_register_driver(serial_driver)) < 0) {
- printk("%s(%d):Couldn't register serial driver\n",
- __FILE__,__LINE__);
- put_tty_driver(serial_driver);
- serial_driver = NULL;
- goto error;
- }
+ /* Initialize the tty_driver structure */
+ serial_driver->driver_name = "synclink_cs";
+ serial_driver->name = "ttySLP";
+ serial_driver->major = ttymajor;
+ 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 =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_set_operations(serial_driver, &mgslpc_ops);
+
+ rc = tty_register_driver(serial_driver);
+ if (rc < 0) {
+ printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
+ __FILE__, __LINE__);
+ goto err_put_tty;
+ }
- printk("%s %s, tty major#%d\n",
- driver_name, driver_version,
- serial_driver->major);
+ rc = pcmcia_register_driver(&mgslpc_driver);
+ if (rc < 0)
+ goto err_unreg_tty;
- return 0;
+ printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
+ serial_driver->major);
-error:
- synclink_cs_cleanup();
- return rc;
+ return 0;
+err_unreg_tty:
+ tty_unregister_driver(serial_driver);
+err_put_tty:
+ put_tty_driver(serial_driver);
+err:
+ return rc;
}
static void __exit synclink_cs_exit(void)
{
- synclink_cs_cleanup();
+ pcmcia_unregister_driver(&mgslpc_driver);
+ tty_unregister_driver(serial_driver);
+ put_tty_driver(serial_driver);
}
module_init(synclink_cs_init);
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 46b77ede84c0..af98f6d6509b 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
tmp[tpk_curr + 1] = '\0';
printk(KERN_INFO "%s%s", tpk_tag, tmp);
tpk_curr = 0;
- if (buf[i + 1] == '\n')
+ if ((i + 1) < count && buf[i + 1] == '\n')
i++;
break;
case '\n':
@@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
- void *rp;
- ttyprintk_driver = alloc_tty_driver(1);
- if (!ttyprintk_driver)
- return ret;
+ tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
+ mutex_init(&tpk_port.port_write_mutex);
+
+ ttyprintk_driver = tty_alloc_driver(1,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_UNNUMBERED_NODE);
+ if (IS_ERR(ttyprintk_driver))
+ return PTR_ERR(ttyprintk_driver);
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
@@ -191,9 +197,8 @@ static int __init ttyprintk_init(void)
ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
ttyprintk_driver->init_termios = tty_std_termios;
ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
- ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+ tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
ret = tty_register_driver(ttyprintk_driver);
if (ret < 0) {
@@ -201,22 +206,10 @@ static int __init ttyprintk_init(void)
goto error;
}
- /* create our unnumbered device */
- rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
- ttyprintk_driver->name);
- if (IS_ERR(rp)) {
- printk(KERN_ERR "Couldn't create ttyprintk device\n");
- ret = PTR_ERR(rp);
- goto error;
- }
-
- tty_port_init(&tpk_port.port);
- tpk_port.port.ops = &null_ops;
- mutex_init(&tpk_port.port_write_mutex);
-
return 0;
error:
+ tty_unregister_driver(ttyprintk_driver);
put_tty_driver(ttyprintk_driver);
ttyprintk_driver = NULL;
return ret;
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 7f0b5ca78516..bace9e98f75d 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -40,4 +40,17 @@ config COMMON_CLK_WM831X
Supports the clocking subsystem of the WM831x/2x series of
PMICs from Wolfson Microlectronics.
+config COMMON_CLK_VERSATILE
+ bool "Clock driver for ARM Reference designs"
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+ ---help---
+ Supports clocking on ARM Reference designs Integrator/AP,
+ Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+
+config COMMON_CLK_MAX77686
+ tristate "Clock driver for Maxim 77686 MFD"
+ depends on MFD_MAX77686
+ ---help---
+ This driver supports Maxim 77686 crystal oscillator clock.
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 42fb17367f78..e48e0da5a884 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,8 +9,15 @@ obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_U300) += clk-u300.o
-obj-$(CONFIG_ARCH_INTEGRATOR) += versatile/
+obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
+obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o
+ifeq ($(CONFIG_COMMON_CLK), y)
+obj-$(CONFIG_ARCH_MMP) += mmp/
+endif
+obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
+obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
+obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
diff --git a/drivers/clk/clk-ls1x.c b/drivers/clk/clk-ls1x.c
new file mode 100644
index 000000000000..f20b750235f6
--- /dev/null
+++ b/drivers/clk/clk-ls1x.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@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 <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include <loongson1.h>
+
+#define OSC 33
+
+static DEFINE_SPINLOCK(_lock);
+
+static int ls1x_pll_clk_enable(struct clk_hw *hw)
+{
+ return 0;
+}
+
+static void ls1x_pll_clk_disable(struct clk_hw *hw)
+{
+}
+
+static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ u32 pll, rate;
+
+ pll = __raw_readl(LS1X_CLK_PLL_FREQ);
+ rate = ((12 + (pll & 0x3f)) * 1000000) +
+ ((((pll >> 8) & 0x3ff) * 1000000) >> 10);
+ rate *= OSC;
+ rate >>= 1;
+
+ return rate;
+}
+
+static const struct clk_ops ls1x_pll_clk_ops = {
+ .enable = ls1x_pll_clk_enable,
+ .disable = ls1x_pll_clk_disable,
+ .recalc_rate = ls1x_pll_recalc_rate,
+};
+
+static struct clk * __init clk_register_pll(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags)
+{
+ struct clk_hw *hw;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the divider */
+ hw = kzalloc(sizeof(struct clk_hw), GFP_KERNEL);
+ if (!hw) {
+ pr_err("%s: could not allocate clk_hw\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &ls1x_pll_clk_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+ hw->init = &init;
+
+ /* register the clock */
+ clk = clk_register(dev, hw);
+
+ if (IS_ERR(clk))
+ kfree(hw);
+
+ return clk;
+}
+
+void __init ls1x_clk_init(void)
+{
+ struct clk *clk;
+
+ clk = clk_register_pll(NULL, "pll_clk", NULL, CLK_IS_ROOT);
+ clk_prepare_enable(clk);
+
+ clk = clk_register_divider(NULL, "cpu_clk", "pll_clk",
+ CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_CPU_SHIFT,
+ DIV_CPU_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+ clk_prepare_enable(clk);
+ clk_register_clkdev(clk, "cpu", NULL);
+
+ clk = clk_register_divider(NULL, "dc_clk", "pll_clk",
+ CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT,
+ DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+ clk_prepare_enable(clk);
+ clk_register_clkdev(clk, "dc", NULL);
+
+ clk = clk_register_divider(NULL, "ahb_clk", "pll_clk",
+ CLK_SET_RATE_PARENT, LS1X_CLK_PLL_DIV, DIV_DDR_SHIFT,
+ DIV_DDR_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock);
+ clk_prepare_enable(clk);
+ clk_register_clkdev(clk, "ahb", NULL);
+ clk_register_clkdev(clk, "stmmaceth", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 2);
+ clk_prepare_enable(clk);
+ clk_register_clkdev(clk, "apb", NULL);
+ clk_register_clkdev(clk, "serial8250", NULL);
+}
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
new file mode 100644
index 000000000000..ac5f5434cb9a
--- /dev/null
+++ b/drivers/clk/clk-max77686.c
@@ -0,0 +1,244 @@
+/*
+ * clk-max77686.c - Clock driver for Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@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.
+ *
+ * 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/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77686.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+enum {
+ MAX77686_CLK_AP = 0,
+ MAX77686_CLK_CP,
+ MAX77686_CLK_PMIC,
+ MAX77686_CLKS_NUM,
+};
+
+struct max77686_clk {
+ struct max77686_dev *iodev;
+ u32 mask;
+ struct clk_hw hw;
+ struct clk_lookup *lookup;
+};
+
+static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct max77686_clk, hw);
+}
+
+static int max77686_clk_prepare(struct clk_hw *hw)
+{
+ struct max77686_clk *max77686;
+ int ret;
+
+ max77686 = get_max77686_clk(hw);
+ if (!max77686)
+ return -ENOMEM;
+
+ ret = regmap_update_bits(max77686->iodev->regmap,
+ MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
+
+ return ret;
+}
+
+static void max77686_clk_unprepare(struct clk_hw *hw)
+{
+ struct max77686_clk *max77686;
+
+ max77686 = get_max77686_clk(hw);
+ if (!max77686)
+ return;
+
+ regmap_update_bits(max77686->iodev->regmap,
+ MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
+}
+
+static int max77686_clk_is_enabled(struct clk_hw *hw)
+{
+ struct max77686_clk *max77686;
+ int ret;
+ u32 val;
+
+ max77686 = get_max77686_clk(hw);
+ if (!max77686)
+ return -ENOMEM;
+
+ ret = regmap_read(max77686->iodev->regmap,
+ MAX77686_REG_32KHZ, &val);
+
+ if (ret < 0)
+ return -EINVAL;
+
+ return val & max77686->mask;
+}
+
+static struct clk_ops max77686_clk_ops = {
+ .prepare = max77686_clk_prepare,
+ .unprepare = max77686_clk_unprepare,
+ .is_enabled = max77686_clk_is_enabled,
+};
+
+static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
+ [MAX77686_CLK_AP] = {
+ .name = "32khz_ap",
+ .ops = &max77686_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [MAX77686_CLK_CP] = {
+ .name = "32khz_cp",
+ .ops = &max77686_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [MAX77686_CLK_PMIC] = {
+ .name = "32khz_pmic",
+ .ops = &max77686_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+};
+
+static int max77686_clk_register(struct device *dev,
+ struct max77686_clk *max77686)
+{
+ struct clk *clk;
+ struct clk_hw *hw = &max77686->hw;
+
+ clk = clk_register(dev, hw);
+
+ if (IS_ERR(clk))
+ return -ENOMEM;
+
+ max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
+ GFP_KERNEL);
+ if (IS_ERR(max77686->lookup))
+ return -ENOMEM;
+
+ max77686->lookup->con_id = hw->init->name;
+ max77686->lookup->clk = clk;
+
+ clkdev_add(max77686->lookup);
+
+ return 0;
+}
+
+static __devinit int max77686_clk_probe(struct platform_device *pdev)
+{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct max77686_clk **max77686_clks;
+ int i, ret;
+
+ max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
+ * MAX77686_CLKS_NUM, GFP_KERNEL);
+ if (IS_ERR(max77686_clks))
+ return -ENOMEM;
+
+ for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+ max77686_clks[i] = devm_kzalloc(&pdev->dev,
+ sizeof(struct max77686_clk), GFP_KERNEL);
+ if (IS_ERR(max77686_clks[i]))
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+ max77686_clks[i]->iodev = iodev;
+ max77686_clks[i]->mask = 1 << i;
+ max77686_clks[i]->hw.init = &max77686_clks_init[i];
+
+ ret = max77686_clk_register(&pdev->dev, max77686_clks[i]);
+ if (ret) {
+ switch (i) {
+ case MAX77686_CLK_AP:
+ dev_err(&pdev->dev, "Fail to register CLK_AP\n");
+ goto err_clk_ap;
+ break;
+ case MAX77686_CLK_CP:
+ dev_err(&pdev->dev, "Fail to register CLK_CP\n");
+ goto err_clk_cp;
+ break;
+ case MAX77686_CLK_PMIC:
+ dev_err(&pdev->dev, "Fail to register CLK_PMIC\n");
+ goto err_clk_pmic;
+ }
+ }
+ }
+
+ platform_set_drvdata(pdev, max77686_clks);
+
+ goto out;
+
+err_clk_pmic:
+ clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup);
+ kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk);
+err_clk_cp:
+ clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup);
+ kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk);
+err_clk_ap:
+out:
+ return ret;
+}
+
+static int __devexit max77686_clk_remove(struct platform_device *pdev)
+{
+ struct max77686_clk **max77686_clks = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < MAX77686_CLKS_NUM; i++) {
+ clkdev_drop(max77686_clks[i]->lookup);
+ kfree(max77686_clks[i]->hw.clk);
+ }
+ return 0;
+}
+
+static const struct platform_device_id max77686_clk_id[] = {
+ { "max77686-clk", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, max77686_clk_id);
+
+static struct platform_driver max77686_clk_driver = {
+ .driver = {
+ .name = "max77686-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = max77686_clk_probe,
+ .remove = __devexit_p(max77686_clk_remove),
+ .id_table = max77686_clk_id,
+};
+
+static int __init max77686_clk_init(void)
+{
+ return platform_driver_register(&max77686_clk_driver);
+}
+subsys_initcall(max77686_clk_init);
+
+static void __init max77686_clk_cleanup(void)
+{
+ platform_driver_unregister(&max77686_clk_driver);
+}
+module_exit(max77686_clk_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
+MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
new file mode 100644
index 000000000000..517874fa6858
--- /dev/null
+++ b/drivers/clk/clk-prima2.c
@@ -0,0 +1,1171 @@
+/*
+ * Clock tree for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#define SIRFSOC_CLKC_CLK_EN0 0x0000
+#define SIRFSOC_CLKC_CLK_EN1 0x0004
+#define SIRFSOC_CLKC_REF_CFG 0x0014
+#define SIRFSOC_CLKC_CPU_CFG 0x0018
+#define SIRFSOC_CLKC_MEM_CFG 0x001c
+#define SIRFSOC_CLKC_SYS_CFG 0x0020
+#define SIRFSOC_CLKC_IO_CFG 0x0024
+#define SIRFSOC_CLKC_DSP_CFG 0x0028
+#define SIRFSOC_CLKC_GFX_CFG 0x002c
+#define SIRFSOC_CLKC_MM_CFG 0x0030
+#define SIRFSOC_CLKC_LCD_CFG 0x0034
+#define SIRFSOC_CLKC_MMC_CFG 0x0038
+#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
+#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
+#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
+#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
+#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
+#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
+#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
+#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
+#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
+#define SIRFSOC_USBPHY_PLL_CTRL 0x0008
+#define SIRFSOC_USBPHY_PLL_POWERDOWN BIT(1)
+#define SIRFSOC_USBPHY_PLL_BYPASS BIT(2)
+#define SIRFSOC_USBPHY_PLL_LOCK BIT(3)
+
+static void *sirfsoc_clk_vbase, *sirfsoc_rsc_vbase;
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+/*
+ * SiRFprimaII clock controller
+ * - 2 oscillators: osc-26MHz, rtc-32.768KHz
+ * - 3 standard configurable plls: pll1, pll2 & pll3
+ * - 2 exclusive plls: usb phy pll and sata phy pll
+ * - 8 clock domains: cpu/cpudiv, mem/memdiv, sys/io, dsp, graphic, multimedia,
+ * display and sdphy.
+ * Each clock domain can select its own clock source from five clock sources,
+ * X_XIN, X_XINW, PLL1, PLL2 and PLL3. The domain clock is used as the source
+ * clock of the group clock.
+ * - dsp domain: gps, mf
+ * - io domain: dmac, nand, audio, uart, i2c, spi, usp, pwm, pulse
+ * - sys domain: security
+ */
+
+struct clk_pll {
+ struct clk_hw hw;
+ unsigned short regofs; /* register offset */
+};
+
+#define to_pllclk(_hw) container_of(_hw, struct clk_pll, hw)
+
+struct clk_dmn {
+ struct clk_hw hw;
+ signed char enable_bit; /* enable bit: 0 ~ 63 */
+ unsigned short regofs; /* register offset */
+};
+
+#define to_dmnclk(_hw) container_of(_hw, struct clk_dmn, hw)
+
+struct clk_std {
+ struct clk_hw hw;
+ signed char enable_bit; /* enable bit: 0 ~ 63 */
+};
+
+#define to_stdclk(_hw) container_of(_hw, struct clk_std, hw)
+
+static int std_clk_is_enabled(struct clk_hw *hw);
+static int std_clk_enable(struct clk_hw *hw);
+static void std_clk_disable(struct clk_hw *hw);
+
+static inline unsigned long clkc_readl(unsigned reg)
+{
+ return readl(sirfsoc_clk_vbase + reg);
+}
+
+static inline void clkc_writel(u32 val, unsigned reg)
+{
+ writel(val, sirfsoc_clk_vbase + reg);
+}
+
+/*
+ * std pll
+ */
+
+static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long fin = parent_rate;
+ struct clk_pll *clk = to_pllclk(hw);
+ u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
+ SIRFSOC_CLKC_PLL1_CFG0;
+
+ if (clkc_readl(regcfg2) & BIT(2)) {
+ /* pll bypass mode */
+ return fin;
+ } else {
+ /* fout = fin * nf / nr / od */
+ u32 cfg0 = clkc_readl(clk->regofs);
+ u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
+ u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
+ u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
+ WARN_ON(fin % MHZ);
+ return fin / MHZ * nf / nr / od * MHZ;
+ }
+}
+
+static long pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long fin, nf, nr, od;
+
+ /*
+ * fout = fin * nf / (nr * od);
+ * set od = 1, nr = fin/MHz, so fout = nf * MHz
+ */
+ rate = rate - rate % MHZ;
+
+ nf = rate / MHZ;
+ if (nf > BIT(13))
+ nf = BIT(13);
+ if (nf < 1)
+ nf = 1;
+
+ fin = *parent_rate;
+
+ nr = fin / MHZ;
+ if (nr > BIT(6))
+ nr = BIT(6);
+ od = 1;
+
+ return fin * nf / (nr * od);
+}
+
+static int pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pll *clk = to_pllclk(hw);
+ unsigned long fin, nf, nr, od, reg;
+
+ /*
+ * fout = fin * nf / (nr * od);
+ * set od = 1, nr = fin/MHz, so fout = nf * MHz
+ */
+
+ nf = rate / MHZ;
+ if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
+ return -EINVAL;
+
+ fin = parent_rate;
+ BUG_ON(fin < MHZ);
+
+ nr = fin / MHZ;
+ BUG_ON((fin % MHZ) || nr > BIT(6));
+
+ od = 1;
+
+ reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
+ clkc_writel(reg, clk->regofs);
+
+ reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
+ clkc_writel((nf >> 1) - 1, reg);
+
+ reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
+ while (!(clkc_readl(reg) & BIT(6)))
+ cpu_relax();
+
+ return 0;
+}
+
+static struct clk_ops std_pll_ops = {
+ .recalc_rate = pll_clk_recalc_rate,
+ .round_rate = pll_clk_round_rate,
+ .set_rate = pll_clk_set_rate,
+};
+
+static const char *pll_clk_parents[] = {
+ "osc",
+};
+
+static struct clk_init_data clk_pll1_init = {
+ .name = "pll1",
+ .ops = &std_pll_ops,
+ .parent_names = pll_clk_parents,
+ .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_init_data clk_pll2_init = {
+ .name = "pll2",
+ .ops = &std_pll_ops,
+ .parent_names = pll_clk_parents,
+ .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_init_data clk_pll3_init = {
+ .name = "pll3",
+ .ops = &std_pll_ops,
+ .parent_names = pll_clk_parents,
+ .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_pll clk_pll1 = {
+ .regofs = SIRFSOC_CLKC_PLL1_CFG0,
+ .hw = {
+ .init = &clk_pll1_init,
+ },
+};
+
+static struct clk_pll clk_pll2 = {
+ .regofs = SIRFSOC_CLKC_PLL2_CFG0,
+ .hw = {
+ .init = &clk_pll2_init,
+ },
+};
+
+static struct clk_pll clk_pll3 = {
+ .regofs = SIRFSOC_CLKC_PLL3_CFG0,
+ .hw = {
+ .init = &clk_pll3_init,
+ },
+};
+
+/*
+ * usb uses specified pll
+ */
+
+static int usb_pll_clk_enable(struct clk_hw *hw)
+{
+ u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+ reg &= ~(SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
+ writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+ while (!(readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL) &
+ SIRFSOC_USBPHY_PLL_LOCK))
+ cpu_relax();
+
+ return 0;
+}
+
+static void usb_pll_clk_disable(struct clk_hw *clk)
+{
+ u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+ reg |= (SIRFSOC_USBPHY_PLL_POWERDOWN | SIRFSOC_USBPHY_PLL_BYPASS);
+ writel(reg, sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+}
+
+static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ u32 reg = readl(sirfsoc_rsc_vbase + SIRFSOC_USBPHY_PLL_CTRL);
+ return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ;
+}
+
+static struct clk_ops usb_pll_ops = {
+ .enable = usb_pll_clk_enable,
+ .disable = usb_pll_clk_disable,
+ .recalc_rate = usb_pll_clk_recalc_rate,
+};
+
+static struct clk_init_data clk_usb_pll_init = {
+ .name = "usb_pll",
+ .ops = &usb_pll_ops,
+ .parent_names = pll_clk_parents,
+ .num_parents = ARRAY_SIZE(pll_clk_parents),
+};
+
+static struct clk_hw usb_pll_clk_hw = {
+ .init = &clk_usb_pll_init,
+};
+
+/*
+ * clock domains - cpu, mem, sys/io, dsp, gfx
+ */
+
+static const char *dmn_clk_parents[] = {
+ "rtc",
+ "osc",
+ "pll1",
+ "pll2",
+ "pll3",
+};
+
+static u8 dmn_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_dmn *clk = to_dmnclk(hw);
+ u32 cfg = clkc_readl(clk->regofs);
+
+ /* parent of io domain can only be pll3 */
+ if (strcmp(hw->init->name, "io") == 0)
+ return 4;
+
+ WARN_ON((cfg & (BIT(3) - 1)) > 4);
+
+ return cfg & (BIT(3) - 1);
+}
+
+static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent)
+{
+ struct clk_dmn *clk = to_dmnclk(hw);
+ u32 cfg = clkc_readl(clk->regofs);
+
+ /* parent of io domain can only be pll3 */
+ if (strcmp(hw->init->name, "io") == 0)
+ return -EINVAL;
+
+ cfg &= ~(BIT(3) - 1);
+ clkc_writel(cfg | parent, clk->regofs);
+ /* BIT(3) - switching status: 1 - busy, 0 - done */
+ while (clkc_readl(clk->regofs) & BIT(3))
+ cpu_relax();
+
+ return 0;
+}
+
+static unsigned long dmn_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+
+{
+ unsigned long fin = parent_rate;
+ struct clk_dmn *clk = to_dmnclk(hw);
+
+ u32 cfg = clkc_readl(clk->regofs);
+
+ if (cfg & BIT(24)) {
+ /* fcd bypass mode */
+ return fin;
+ } else {
+ /*
+ * wait count: bit[19:16], hold count: bit[23:20]
+ */
+ u32 wait = (cfg >> 16) & (BIT(4) - 1);
+ u32 hold = (cfg >> 20) & (BIT(4) - 1);
+
+ return fin / (wait + hold + 2);
+ }
+}
+
+static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long fin;
+ unsigned ratio, wait, hold;
+ unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+
+ fin = *parent_rate;
+ ratio = fin / rate;
+
+ if (ratio < 2)
+ ratio = 2;
+ if (ratio > BIT(bits + 1))
+ ratio = BIT(bits + 1);
+
+ wait = (ratio >> 1) - 1;
+ hold = ratio - wait - 2;
+
+ return fin / (wait + hold + 2);
+}
+
+static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_dmn *clk = to_dmnclk(hw);
+ unsigned long fin;
+ unsigned ratio, wait, hold, reg;
+ unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4;
+
+ fin = parent_rate;
+ ratio = fin / rate;
+
+ if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
+ return -EINVAL;
+
+ WARN_ON(fin % rate);
+
+ wait = (ratio >> 1) - 1;
+ hold = ratio - wait - 2;
+
+ reg = clkc_readl(clk->regofs);
+ reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
+ reg |= (wait << 16) | (hold << 20) | BIT(25);
+ clkc_writel(reg, clk->regofs);
+
+ /* waiting FCD been effective */
+ while (clkc_readl(clk->regofs) & BIT(25))
+ cpu_relax();
+
+ return 0;
+}
+
+static struct clk_ops msi_ops = {
+ .set_rate = dmn_clk_set_rate,
+ .round_rate = dmn_clk_round_rate,
+ .recalc_rate = dmn_clk_recalc_rate,
+ .set_parent = dmn_clk_set_parent,
+ .get_parent = dmn_clk_get_parent,
+};
+
+static struct clk_init_data clk_mem_init = {
+ .name = "mem",
+ .ops = &msi_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mem = {
+ .regofs = SIRFSOC_CLKC_MEM_CFG,
+ .hw = {
+ .init = &clk_mem_init,
+ },
+};
+
+static struct clk_init_data clk_sys_init = {
+ .name = "sys",
+ .ops = &msi_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+ .flags = CLK_SET_RATE_GATE,
+};
+
+static struct clk_dmn clk_sys = {
+ .regofs = SIRFSOC_CLKC_SYS_CFG,
+ .hw = {
+ .init = &clk_sys_init,
+ },
+};
+
+static struct clk_init_data clk_io_init = {
+ .name = "io",
+ .ops = &msi_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_io = {
+ .regofs = SIRFSOC_CLKC_IO_CFG,
+ .hw = {
+ .init = &clk_io_init,
+ },
+};
+
+static struct clk_ops cpu_ops = {
+ .set_parent = dmn_clk_set_parent,
+ .get_parent = dmn_clk_get_parent,
+};
+
+static struct clk_init_data clk_cpu_init = {
+ .name = "cpu",
+ .ops = &cpu_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+ .flags = CLK_SET_RATE_PARENT,
+};
+
+static struct clk_dmn clk_cpu = {
+ .regofs = SIRFSOC_CLKC_CPU_CFG,
+ .hw = {
+ .init = &clk_cpu_init,
+ },
+};
+
+static struct clk_ops dmn_ops = {
+ .is_enabled = std_clk_is_enabled,
+ .enable = std_clk_enable,
+ .disable = std_clk_disable,
+ .set_rate = dmn_clk_set_rate,
+ .round_rate = dmn_clk_round_rate,
+ .recalc_rate = dmn_clk_recalc_rate,
+ .set_parent = dmn_clk_set_parent,
+ .get_parent = dmn_clk_get_parent,
+};
+
+/* dsp, gfx, mm, lcd and vpp domain */
+
+static struct clk_init_data clk_dsp_init = {
+ .name = "dsp",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_dsp = {
+ .regofs = SIRFSOC_CLKC_DSP_CFG,
+ .enable_bit = 0,
+ .hw = {
+ .init = &clk_dsp_init,
+ },
+};
+
+static struct clk_init_data clk_gfx_init = {
+ .name = "gfx",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_gfx = {
+ .regofs = SIRFSOC_CLKC_GFX_CFG,
+ .enable_bit = 8,
+ .hw = {
+ .init = &clk_gfx_init,
+ },
+};
+
+static struct clk_init_data clk_mm_init = {
+ .name = "mm",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mm = {
+ .regofs = SIRFSOC_CLKC_MM_CFG,
+ .enable_bit = 9,
+ .hw = {
+ .init = &clk_mm_init,
+ },
+};
+
+static struct clk_init_data clk_lcd_init = {
+ .name = "lcd",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_lcd = {
+ .regofs = SIRFSOC_CLKC_LCD_CFG,
+ .enable_bit = 10,
+ .hw = {
+ .init = &clk_lcd_init,
+ },
+};
+
+static struct clk_init_data clk_vpp_init = {
+ .name = "vpp",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_vpp = {
+ .regofs = SIRFSOC_CLKC_LCD_CFG,
+ .enable_bit = 11,
+ .hw = {
+ .init = &clk_vpp_init,
+ },
+};
+
+static struct clk_init_data clk_mmc01_init = {
+ .name = "mmc01",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc01 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 59,
+ .hw = {
+ .init = &clk_mmc01_init,
+ },
+};
+
+static struct clk_init_data clk_mmc23_init = {
+ .name = "mmc23",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc23 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 60,
+ .hw = {
+ .init = &clk_mmc23_init,
+ },
+};
+
+static struct clk_init_data clk_mmc45_init = {
+ .name = "mmc45",
+ .ops = &dmn_ops,
+ .parent_names = dmn_clk_parents,
+ .num_parents = ARRAY_SIZE(dmn_clk_parents),
+};
+
+static struct clk_dmn clk_mmc45 = {
+ .regofs = SIRFSOC_CLKC_MMC_CFG,
+ .enable_bit = 61,
+ .hw = {
+ .init = &clk_mmc45_init,
+ },
+};
+
+/*
+ * peripheral controllers in io domain
+ */
+
+static int std_clk_is_enabled(struct clk_hw *hw)
+{
+ u32 reg;
+ int bit;
+ struct clk_std *clk = to_stdclk(hw);
+
+ bit = clk->enable_bit % 32;
+ reg = clk->enable_bit / 32;
+ reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+ return !!(clkc_readl(reg) & BIT(bit));
+}
+
+static int std_clk_enable(struct clk_hw *hw)
+{
+ u32 val, reg;
+ int bit;
+ struct clk_std *clk = to_stdclk(hw);
+
+ BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
+
+ bit = clk->enable_bit % 32;
+ reg = clk->enable_bit / 32;
+ reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+ val = clkc_readl(reg) | BIT(bit);
+ clkc_writel(val, reg);
+ return 0;
+}
+
+static void std_clk_disable(struct clk_hw *hw)
+{
+ u32 val, reg;
+ int bit;
+ struct clk_std *clk = to_stdclk(hw);
+
+ BUG_ON(clk->enable_bit < 0 || clk->enable_bit > 63);
+
+ bit = clk->enable_bit % 32;
+ reg = clk->enable_bit / 32;
+ reg = SIRFSOC_CLKC_CLK_EN0 + reg * sizeof(reg);
+
+ val = clkc_readl(reg) & ~BIT(bit);
+ clkc_writel(val, reg);
+}
+
+static const char *std_clk_io_parents[] = {
+ "io",
+};
+
+static struct clk_ops ios_ops = {
+ .is_enabled = std_clk_is_enabled,
+ .enable = std_clk_enable,
+ .disable = std_clk_disable,
+};
+
+static struct clk_init_data clk_dmac0_init = {
+ .name = "dmac0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_dmac0 = {
+ .enable_bit = 32,
+ .hw = {
+ .init = &clk_dmac0_init,
+ },
+};
+
+static struct clk_init_data clk_dmac1_init = {
+ .name = "dmac1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_dmac1 = {
+ .enable_bit = 33,
+ .hw = {
+ .init = &clk_dmac1_init,
+ },
+};
+
+static struct clk_init_data clk_nand_init = {
+ .name = "nand",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_nand = {
+ .enable_bit = 34,
+ .hw = {
+ .init = &clk_nand_init,
+ },
+};
+
+static struct clk_init_data clk_audio_init = {
+ .name = "audio",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_audio = {
+ .enable_bit = 35,
+ .hw = {
+ .init = &clk_audio_init,
+ },
+};
+
+static struct clk_init_data clk_uart0_init = {
+ .name = "uart0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart0 = {
+ .enable_bit = 36,
+ .hw = {
+ .init = &clk_uart0_init,
+ },
+};
+
+static struct clk_init_data clk_uart1_init = {
+ .name = "uart1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart1 = {
+ .enable_bit = 37,
+ .hw = {
+ .init = &clk_uart1_init,
+ },
+};
+
+static struct clk_init_data clk_uart2_init = {
+ .name = "uart2",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_uart2 = {
+ .enable_bit = 38,
+ .hw = {
+ .init = &clk_uart2_init,
+ },
+};
+
+static struct clk_init_data clk_usp0_init = {
+ .name = "usp0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp0 = {
+ .enable_bit = 39,
+ .hw = {
+ .init = &clk_usp0_init,
+ },
+};
+
+static struct clk_init_data clk_usp1_init = {
+ .name = "usp1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp1 = {
+ .enable_bit = 40,
+ .hw = {
+ .init = &clk_usp1_init,
+ },
+};
+
+static struct clk_init_data clk_usp2_init = {
+ .name = "usp2",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_usp2 = {
+ .enable_bit = 41,
+ .hw = {
+ .init = &clk_usp2_init,
+ },
+};
+
+static struct clk_init_data clk_vip_init = {
+ .name = "vip",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_vip = {
+ .enable_bit = 42,
+ .hw = {
+ .init = &clk_vip_init,
+ },
+};
+
+static struct clk_init_data clk_spi0_init = {
+ .name = "spi0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_spi0 = {
+ .enable_bit = 43,
+ .hw = {
+ .init = &clk_spi0_init,
+ },
+};
+
+static struct clk_init_data clk_spi1_init = {
+ .name = "spi1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_spi1 = {
+ .enable_bit = 44,
+ .hw = {
+ .init = &clk_spi1_init,
+ },
+};
+
+static struct clk_init_data clk_tsc_init = {
+ .name = "tsc",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_tsc = {
+ .enable_bit = 45,
+ .hw = {
+ .init = &clk_tsc_init,
+ },
+};
+
+static struct clk_init_data clk_i2c0_init = {
+ .name = "i2c0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_i2c0 = {
+ .enable_bit = 46,
+ .hw = {
+ .init = &clk_i2c0_init,
+ },
+};
+
+static struct clk_init_data clk_i2c1_init = {
+ .name = "i2c1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_i2c1 = {
+ .enable_bit = 47,
+ .hw = {
+ .init = &clk_i2c1_init,
+ },
+};
+
+static struct clk_init_data clk_pwmc_init = {
+ .name = "pwmc",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_pwmc = {
+ .enable_bit = 48,
+ .hw = {
+ .init = &clk_pwmc_init,
+ },
+};
+
+static struct clk_init_data clk_efuse_init = {
+ .name = "efuse",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_efuse = {
+ .enable_bit = 49,
+ .hw = {
+ .init = &clk_efuse_init,
+ },
+};
+
+static struct clk_init_data clk_pulse_init = {
+ .name = "pulse",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_pulse = {
+ .enable_bit = 50,
+ .hw = {
+ .init = &clk_pulse_init,
+ },
+};
+
+static const char *std_clk_dsp_parents[] = {
+ "dsp",
+};
+
+static struct clk_init_data clk_gps_init = {
+ .name = "gps",
+ .ops = &ios_ops,
+ .parent_names = std_clk_dsp_parents,
+ .num_parents = ARRAY_SIZE(std_clk_dsp_parents),
+};
+
+static struct clk_std clk_gps = {
+ .enable_bit = 1,
+ .hw = {
+ .init = &clk_gps_init,
+ },
+};
+
+static struct clk_init_data clk_mf_init = {
+ .name = "mf",
+ .ops = &ios_ops,
+ .parent_names = std_clk_io_parents,
+ .num_parents = ARRAY_SIZE(std_clk_io_parents),
+};
+
+static struct clk_std clk_mf = {
+ .enable_bit = 2,
+ .hw = {
+ .init = &clk_mf_init,
+ },
+};
+
+static const char *std_clk_sys_parents[] = {
+ "sys",
+};
+
+static struct clk_init_data clk_security_init = {
+ .name = "mf",
+ .ops = &ios_ops,
+ .parent_names = std_clk_sys_parents,
+ .num_parents = ARRAY_SIZE(std_clk_sys_parents),
+};
+
+static struct clk_std clk_security = {
+ .enable_bit = 19,
+ .hw = {
+ .init = &clk_security_init,
+ },
+};
+
+static const char *std_clk_usb_parents[] = {
+ "usb_pll",
+};
+
+static struct clk_init_data clk_usb0_init = {
+ .name = "usb0",
+ .ops = &ios_ops,
+ .parent_names = std_clk_usb_parents,
+ .num_parents = ARRAY_SIZE(std_clk_usb_parents),
+};
+
+static struct clk_std clk_usb0 = {
+ .enable_bit = 16,
+ .hw = {
+ .init = &clk_usb0_init,
+ },
+};
+
+static struct clk_init_data clk_usb1_init = {
+ .name = "usb1",
+ .ops = &ios_ops,
+ .parent_names = std_clk_usb_parents,
+ .num_parents = ARRAY_SIZE(std_clk_usb_parents),
+};
+
+static struct clk_std clk_usb1 = {
+ .enable_bit = 17,
+ .hw = {
+ .init = &clk_usb1_init,
+ },
+};
+
+static struct of_device_id clkc_ids[] = {
+ { .compatible = "sirf,prima2-clkc" },
+ {},
+};
+
+static struct of_device_id rsc_ids[] = {
+ { .compatible = "sirf,prima2-rsc" },
+ {},
+};
+
+void __init sirfsoc_of_clk_init(void)
+{
+ struct clk *clk;
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, clkc_ids);
+ if (!np)
+ panic("unable to find compatible clkc node in dtb\n");
+
+ sirfsoc_clk_vbase = of_iomap(np, 0);
+ if (!sirfsoc_clk_vbase)
+ panic("unable to map clkc registers\n");
+
+ of_node_put(np);
+
+ np = of_find_matching_node(NULL, rsc_ids);
+ if (!np)
+ panic("unable to find compatible rsc node in dtb\n");
+
+ sirfsoc_rsc_vbase = of_iomap(np, 0);
+ if (!sirfsoc_rsc_vbase)
+ panic("unable to map rsc registers\n");
+
+ of_node_put(np);
+
+
+ /* These are always available (RTC and 26MHz OSC)*/
+ clk = clk_register_fixed_rate(NULL, "rtc", NULL,
+ CLK_IS_ROOT, 32768);
+ BUG_ON(!clk);
+ clk = clk_register_fixed_rate(NULL, "osc", NULL,
+ CLK_IS_ROOT, 26000000);
+ BUG_ON(!clk);
+
+ clk = clk_register(NULL, &clk_pll1.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_pll2.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_pll3.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_mem.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_sys.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_security.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b8030000.security");
+ clk = clk_register(NULL, &clk_dsp.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_gps.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "a8010000.gps");
+ clk = clk_register(NULL, &clk_mf.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_io.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "io");
+ clk = clk_register(NULL, &clk_cpu.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "cpu");
+ clk = clk_register(NULL, &clk_uart0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0050000.uart");
+ clk = clk_register(NULL, &clk_uart1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0060000.uart");
+ clk = clk_register(NULL, &clk_uart2.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0070000.uart");
+ clk = clk_register(NULL, &clk_tsc.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0110000.tsc");
+ clk = clk_register(NULL, &clk_i2c0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00e0000.i2c");
+ clk = clk_register(NULL, &clk_i2c1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00f0000.i2c");
+ clk = clk_register(NULL, &clk_spi0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00d0000.spi");
+ clk = clk_register(NULL, &clk_spi1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0170000.spi");
+ clk = clk_register(NULL, &clk_pwmc.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0130000.pwm");
+ clk = clk_register(NULL, &clk_efuse.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0140000.efusesys");
+ clk = clk_register(NULL, &clk_pulse.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0150000.pulsec");
+ clk = clk_register(NULL, &clk_dmac0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
+ clk = clk_register(NULL, &clk_dmac1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
+ clk = clk_register(NULL, &clk_nand.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0030000.nand");
+ clk = clk_register(NULL, &clk_audio.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0040000.audio");
+ clk = clk_register(NULL, &clk_usp0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0080000.usp");
+ clk = clk_register(NULL, &clk_usp1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b0090000.usp");
+ clk = clk_register(NULL, &clk_usp2.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00a0000.usp");
+ clk = clk_register(NULL, &clk_vip.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00c0000.vip");
+ clk = clk_register(NULL, &clk_gfx.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "98000000.graphics");
+ clk = clk_register(NULL, &clk_mm.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "a0000000.multimedia");
+ clk = clk_register(NULL, &clk_lcd.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "90010000.display");
+ clk = clk_register(NULL, &clk_vpp.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "90020000.vpp");
+ clk = clk_register(NULL, &clk_mmc01.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_mmc23.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_mmc45.hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &usb_pll_clk_hw);
+ BUG_ON(!clk);
+ clk = clk_register(NULL, &clk_usb0.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00e0000.usb");
+ clk = clk_register(NULL, &clk_usb1.hw);
+ BUG_ON(!clk);
+ clk_register_clkdev(clk, NULL, "b00f0000.usb");
+}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index efdfd009c270..56e4495ebeb1 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -558,25 +558,6 @@ int clk_enable(struct clk *clk)
EXPORT_SYMBOL_GPL(clk_enable);
/**
- * clk_get_rate - return the rate of clk
- * @clk: the clk whose rate is being returned
- *
- * Simply returns the cached rate of the clk. Does not query the hardware. If
- * clk is NULL then returns 0.
- */
-unsigned long clk_get_rate(struct clk *clk)
-{
- unsigned long rate;
-
- mutex_lock(&prepare_lock);
- rate = __clk_get_rate(clk);
- mutex_unlock(&prepare_lock);
-
- return rate;
-}
-EXPORT_SYMBOL_GPL(clk_get_rate);
-
-/**
* __clk_round_rate - round the given rate for a clk
* @clk: round the rate of this clock
*
@@ -702,6 +683,30 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
}
/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
+ * is set, which means a recalc_rate will be issued.
+ * If clk is NULL then returns 0.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ mutex_lock(&prepare_lock);
+
+ if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
+ __clk_recalc_rates(clk, 0);
+
+ rate = __clk_get_rate(clk);
+ mutex_unlock(&prepare_lock);
+
+ return rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/**
* __clk_speculate_rates
* @clk: first clk in the subtree
* @parent_rate: the "future" rate of clk's parent
@@ -1582,6 +1587,20 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
}
EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
+struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct clk_onecell_data *clk_data = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx >= clk_data->clk_num) {
+ pr_err("%s: invalid clock index %d\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clk_data->clks[idx];
+}
+EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
+
/**
* of_clk_add_provider() - Register a clock provider for a node
* @np: Device node pointer associated with clock provider
diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile
new file mode 100644
index 000000000000..392d78044ce3
--- /dev/null
+++ b/drivers/clk/mmp/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for mmp specific clk
+#
+
+obj-y += clk-apbc.o clk-apmu.o clk-frac.o
+
+obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o
+obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o
+obj-$(CONFIG_CPU_MMP2) += clk-mmp2.o
diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c
new file mode 100644
index 000000000000..d14120eaa71f
--- /dev/null
+++ b/drivers/clk/mmp/clk-apbc.c
@@ -0,0 +1,152 @@
+/*
+ * mmp APB clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/* Common APB clock register bit definitions */
+#define APBC_APBCLK (1 << 0) /* APB Bus Clock Enable */
+#define APBC_FNCLK (1 << 1) /* Functional Clock Enable */
+#define APBC_RST (1 << 2) /* Reset Generation */
+#define APBC_POWER (1 << 7) /* Reset Generation */
+
+#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
+struct clk_apbc {
+ struct clk_hw hw;
+ void __iomem *base;
+ unsigned int delay;
+ unsigned int flags;
+ spinlock_t *lock;
+};
+
+static int clk_apbc_prepare(struct clk_hw *hw)
+{
+ struct clk_apbc *apbc = to_clk_apbc(hw);
+ unsigned int data;
+ unsigned long flags = 0;
+
+ /*
+ * It may share same register as MUX clock,
+ * and it will impact FNCLK enable. Spinlock is needed
+ */
+ if (apbc->lock)
+ spin_lock_irqsave(apbc->lock, flags);
+
+ data = readl_relaxed(apbc->base);
+ if (apbc->flags & APBC_POWER_CTRL)
+ data |= APBC_POWER;
+ data |= APBC_FNCLK;
+ writel_relaxed(data, apbc->base);
+
+ if (apbc->lock)
+ spin_unlock_irqrestore(apbc->lock, flags);
+
+ udelay(apbc->delay);
+
+ if (apbc->lock)
+ spin_lock_irqsave(apbc->lock, flags);
+
+ data = readl_relaxed(apbc->base);
+ data |= APBC_APBCLK;
+ writel_relaxed(data, apbc->base);
+
+ if (apbc->lock)
+ spin_unlock_irqrestore(apbc->lock, flags);
+
+ udelay(apbc->delay);
+
+ if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
+ if (apbc->lock)
+ spin_lock_irqsave(apbc->lock, flags);
+
+ data = readl_relaxed(apbc->base);
+ data &= ~APBC_RST;
+ writel_relaxed(data, apbc->base);
+
+ if (apbc->lock)
+ spin_unlock_irqrestore(apbc->lock, flags);
+ }
+
+ return 0;
+}
+
+static void clk_apbc_unprepare(struct clk_hw *hw)
+{
+ struct clk_apbc *apbc = to_clk_apbc(hw);
+ unsigned long data;
+ unsigned long flags = 0;
+
+ if (apbc->lock)
+ spin_lock_irqsave(apbc->lock, flags);
+
+ data = readl_relaxed(apbc->base);
+ if (apbc->flags & APBC_POWER_CTRL)
+ data &= ~APBC_POWER;
+ data &= ~APBC_FNCLK;
+ writel_relaxed(data, apbc->base);
+
+ if (apbc->lock)
+ spin_unlock_irqrestore(apbc->lock, flags);
+
+ udelay(10);
+
+ if (apbc->lock)
+ spin_lock_irqsave(apbc->lock, flags);
+
+ data = readl_relaxed(apbc->base);
+ data &= ~APBC_APBCLK;
+ writel_relaxed(data, apbc->base);
+
+ if (apbc->lock)
+ spin_unlock_irqrestore(apbc->lock, flags);
+}
+
+struct clk_ops clk_apbc_ops = {
+ .prepare = clk_apbc_prepare,
+ .unprepare = clk_apbc_unprepare,
+};
+
+struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
+ void __iomem *base, unsigned int delay,
+ unsigned int apbc_flags, spinlock_t *lock)
+{
+ struct clk_apbc *apbc;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
+ if (!apbc)
+ return NULL;
+
+ init.name = name;
+ init.ops = &clk_apbc_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ apbc->base = base;
+ apbc->delay = delay;
+ apbc->flags = apbc_flags;
+ apbc->lock = lock;
+ apbc->hw.init = &init;
+
+ clk = clk_register(NULL, &apbc->hw);
+ if (IS_ERR(clk))
+ kfree(apbc);
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c
new file mode 100644
index 000000000000..abe182b2377f
--- /dev/null
+++ b/drivers/clk/mmp/clk-apmu.c
@@ -0,0 +1,97 @@
+/*
+ * mmp AXI peripharal clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define to_clk_apmu(clk) (container_of(clk, struct clk_apmu, clk))
+struct clk_apmu {
+ struct clk_hw hw;
+ void __iomem *base;
+ u32 rst_mask;
+ u32 enable_mask;
+ spinlock_t *lock;
+};
+
+static int clk_apmu_enable(struct clk_hw *hw)
+{
+ struct clk_apmu *apmu = to_clk_apmu(hw);
+ unsigned long data;
+ unsigned long flags = 0;
+
+ if (apmu->lock)
+ spin_lock_irqsave(apmu->lock, flags);
+
+ data = readl_relaxed(apmu->base) | apmu->enable_mask;
+ writel_relaxed(data, apmu->base);
+
+ if (apmu->lock)
+ spin_unlock_irqrestore(apmu->lock, flags);
+
+ return 0;
+}
+
+static void clk_apmu_disable(struct clk_hw *hw)
+{
+ struct clk_apmu *apmu = to_clk_apmu(hw);
+ unsigned long data;
+ unsigned long flags = 0;
+
+ if (apmu->lock)
+ spin_lock_irqsave(apmu->lock, flags);
+
+ data = readl_relaxed(apmu->base) & ~apmu->enable_mask;
+ writel_relaxed(data, apmu->base);
+
+ if (apmu->lock)
+ spin_unlock_irqrestore(apmu->lock, flags);
+}
+
+struct clk_ops clk_apmu_ops = {
+ .enable = clk_apmu_enable,
+ .disable = clk_apmu_disable,
+};
+
+struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name,
+ void __iomem *base, u32 enable_mask, spinlock_t *lock)
+{
+ struct clk_apmu *apmu;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ apmu = kzalloc(sizeof(*apmu), GFP_KERNEL);
+ if (!apmu)
+ return NULL;
+
+ init.name = name;
+ init.ops = &clk_apmu_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ apmu->base = base;
+ apmu->enable_mask = enable_mask;
+ apmu->lock = lock;
+ apmu->hw.init = &init;
+
+ clk = clk_register(NULL, &apmu->hw);
+
+ if (IS_ERR(clk))
+ kfree(apmu);
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c
new file mode 100644
index 000000000000..80c1dd15d15c
--- /dev/null
+++ b/drivers/clk/mmp/clk-frac.c
@@ -0,0 +1,153 @@
+/*
+ * mmp factor clock operation source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include "clk.h"
+/*
+ * It is M/N clock
+ *
+ * Fout from synthesizer can be given from two equations:
+ * numerator/denominator = Fin / (Fout * factor)
+ */
+
+#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw)
+struct clk_factor {
+ struct clk_hw hw;
+ void __iomem *base;
+ struct clk_factor_masks *masks;
+ struct clk_factor_tbl *ftbl;
+ unsigned int ftbl_cnt;
+};
+
+static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long *prate)
+{
+ struct clk_factor *factor = to_clk_factor(hw);
+ unsigned long rate = 0, prev_rate;
+ int i;
+
+ for (i = 0; i < factor->ftbl_cnt; i++) {
+ prev_rate = rate;
+ rate = (((*prate / 10000) * factor->ftbl[i].num) /
+ (factor->ftbl[i].den * factor->masks->factor)) * 10000;
+ if (rate > drate)
+ break;
+ }
+ if (i == 0)
+ return rate;
+ else
+ return prev_rate;
+}
+
+static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_factor *factor = to_clk_factor(hw);
+ struct clk_factor_masks *masks = factor->masks;
+ unsigned int val, num, den;
+
+ val = readl_relaxed(factor->base);
+
+ /* calculate numerator */
+ num = (val >> masks->num_shift) & masks->num_mask;
+
+ /* calculate denominator */
+ den = (val >> masks->den_shift) & masks->num_mask;
+
+ if (!den)
+ return 0;
+
+ return (((parent_rate / 10000) * den) /
+ (num * factor->masks->factor)) * 10000;
+}
+
+/* Configures new clock rate*/
+static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_factor *factor = to_clk_factor(hw);
+ struct clk_factor_masks *masks = factor->masks;
+ int i;
+ unsigned long val;
+ unsigned long prev_rate, rate = 0;
+
+ for (i = 0; i < factor->ftbl_cnt; i++) {
+ prev_rate = rate;
+ rate = (((prate / 10000) * factor->ftbl[i].num) /
+ (factor->ftbl[i].den * factor->masks->factor)) * 10000;
+ if (rate > drate)
+ break;
+ }
+ if (i > 0)
+ i--;
+
+ val = readl_relaxed(factor->base);
+
+ val &= ~(masks->num_mask << masks->num_shift);
+ val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift;
+
+ val &= ~(masks->den_mask << masks->den_shift);
+ val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift;
+
+ writel_relaxed(val, factor->base);
+
+ return 0;
+}
+
+static struct clk_ops clk_factor_ops = {
+ .recalc_rate = clk_factor_recalc_rate,
+ .round_rate = clk_factor_round_rate,
+ .set_rate = clk_factor_set_rate,
+};
+
+struct clk *mmp_clk_register_factor(const char *name, const char *parent_name,
+ unsigned long flags, void __iomem *base,
+ struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl,
+ unsigned int ftbl_cnt)
+{
+ struct clk_factor *factor;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ if (!masks) {
+ pr_err("%s: must pass a clk_factor_mask\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+ if (!factor) {
+ pr_err("%s: could not allocate factor clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* struct clk_aux assignments */
+ factor->base = base;
+ factor->masks = masks;
+ factor->ftbl = ftbl;
+ factor->ftbl_cnt = ftbl_cnt;
+ factor->hw.init = &init;
+
+ init.name = name;
+ init.ops = &clk_factor_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ clk = clk_register(NULL, &factor->hw);
+ if (IS_ERR_OR_NULL(clk))
+ kfree(factor);
+
+ return clk;
+}
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
new file mode 100644
index 000000000000..ade435820c7e
--- /dev/null
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -0,0 +1,449 @@
+/*
+ * mmp2 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC 0x0
+#define APBC_TWSI0 0x4
+#define APBC_TWSI1 0x8
+#define APBC_TWSI2 0xc
+#define APBC_TWSI3 0x10
+#define APBC_TWSI4 0x7c
+#define APBC_TWSI5 0x80
+#define APBC_KPC 0x18
+#define APBC_UART0 0x2c
+#define APBC_UART1 0x30
+#define APBC_UART2 0x34
+#define APBC_UART3 0x88
+#define APBC_GPIO 0x38
+#define APBC_PWM0 0x3c
+#define APBC_PWM1 0x40
+#define APBC_PWM2 0x44
+#define APBC_PWM3 0x48
+#define APBC_SSP0 0x50
+#define APBC_SSP1 0x54
+#define APBC_SSP2 0x58
+#define APBC_SSP3 0x5c
+#define APMU_SDH0 0x54
+#define APMU_SDH1 0x58
+#define APMU_SDH2 0xe8
+#define APMU_SDH3 0xec
+#define APMU_USB 0x5c
+#define APMU_DISP0 0x4c
+#define APMU_DISP1 0x110
+#define APMU_CCIC0 0x50
+#define APMU_CCIC1 0xf4
+#define MPMU_UART_PLL 0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+ .factor = 2,
+ .num_mask = 0x1fff,
+ .den_mask = 0x1fff,
+ .num_shift = 16,
+ .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+ {.num = 14634, .den = 2165}, /*14.745MHZ */
+ {.num = 3521, .den = 689}, /*19.23MHZ */
+ {.num = 9679, .den = 5728}, /*58.9824MHZ */
+ {.num = 15850, .den = 9451}, /*59.429MHZ */
+};
+
+static const char *uart_parent[] = {"uart_pll", "vctcxo"};
+static const char *ssp_parent[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"};
+static const char *sdh_parent[] = {"pll1_4", "pll2", "usb_pll", "pll1"};
+static const char *disp_parent[] = {"pll1", "pll1_16", "pll2", "vctcxo"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_16", "vctcxo"};
+
+void __init mmp2_clk_init(void)
+{
+ struct clk *clk;
+ struct clk *vctcxo;
+ void __iomem *mpmu_base;
+ void __iomem *apmu_base;
+ void __iomem *apbc_base;
+
+ mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ if (mpmu_base == NULL) {
+ pr_err("error to ioremap MPMU base\n");
+ return;
+ }
+
+ apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ if (apmu_base == NULL) {
+ pr_err("error to ioremap APMU base\n");
+ return;
+ }
+
+ apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ if (apbc_base == NULL) {
+ pr_err("error to ioremap APBC base\n");
+ return;
+ }
+
+ clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+ clk_register_clkdev(clk, "clk32", NULL);
+
+ vctcxo = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+ 26000000);
+ clk_register_clkdev(vctcxo, "vctcxo", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+ 800000000);
+ clk_register_clkdev(clk, "pll1", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "usb_pll", NULL, CLK_IS_ROOT,
+ 480000000);
+ clk_register_clkdev(clk, "usb_pll", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "pll2", NULL, CLK_IS_ROOT,
+ 960000000);
+ clk_register_clkdev(clk, "pll2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_4", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_8", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_16", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_20", "pll1_4",
+ CLK_SET_RATE_PARENT, 1, 5);
+ clk_register_clkdev(clk, "pll1_20", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_3", "pll1",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll1_3", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_3",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_6", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_12", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_2", "pll2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_4", "pll2_2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_4", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_8", "pll2_4",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_8", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_16", "pll2_8",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_16", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_3", "pll2",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll2_3", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_6", "pll2_3",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_6", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll2_12", "pll2_6",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll2_12", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "vctcxo_2", "vctcxo",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "vctcxo_2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "vctcxo_4", "vctcxo_2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "vctcxo_4", NULL);
+
+ clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+ mpmu_base + MPMU_UART_PLL,
+ &uart_factor_masks, uart_factor_tbl,
+ ARRAY_SIZE(uart_factor_tbl));
+ clk_set_rate(clk, 14745600);
+ clk_register_clkdev(clk, "uart_pll", NULL);
+
+ clk = mmp_clk_register_apbc("twsi0", "vctcxo",
+ apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+ clk = mmp_clk_register_apbc("twsi1", "vctcxo",
+ apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+ clk = mmp_clk_register_apbc("twsi2", "vctcxo",
+ apbc_base + APBC_TWSI2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.2");
+
+ clk = mmp_clk_register_apbc("twsi3", "vctcxo",
+ apbc_base + APBC_TWSI3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.3");
+
+ clk = mmp_clk_register_apbc("twsi4", "vctcxo",
+ apbc_base + APBC_TWSI4, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.4");
+
+ clk = mmp_clk_register_apbc("twsi5", "vctcxo",
+ apbc_base + APBC_TWSI5, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.5");
+
+ clk = mmp_clk_register_apbc("gpio", "vctcxo",
+ apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+ clk = mmp_clk_register_apbc("kpc", "clk32",
+ apbc_base + APBC_KPC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+ clk = mmp_clk_register_apbc("rtc", "clk32",
+ apbc_base + APBC_RTC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-rtc");
+
+ clk = mmp_clk_register_apbc("pwm0", "vctcxo",
+ apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp2-pwm.0");
+
+ clk = mmp_clk_register_apbc("pwm1", "vctcxo",
+ apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp2-pwm.1");
+
+ clk = mmp_clk_register_apbc("pwm2", "vctcxo",
+ apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp2-pwm.2");
+
+ clk = mmp_clk_register_apbc("pwm3", "vctcxo",
+ apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp2-pwm.3");
+
+ clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, vctcxo);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+ apbc_base + APBC_UART0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+ clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, vctcxo);
+ clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+ apbc_base + APBC_UART1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+ clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, vctcxo);
+ clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+ clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+ apbc_base + APBC_UART2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+ clk = clk_register_mux(NULL, "uart3_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART3, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, vctcxo);
+ clk_register_clkdev(clk, "uart_mux.3", NULL);
+
+ clk = mmp_clk_register_apbc("uart3", "uart3_mux",
+ apbc_base + APBC_UART3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.3");
+
+ clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
+ apbc_base + APBC_SSP0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+ clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
+ apbc_base + APBC_SSP1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+ clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.2", NULL);
+
+ clk = mmp_clk_register_apbc("ssp2", "ssp2_mux",
+ apbc_base + APBC_SSP2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.2");
+
+ clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.3", NULL);
+
+ clk = mmp_clk_register_apbc("ssp3", "ssp3_mux",
+ apbc_base + APBC_SSP3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.3");
+
+ clk = clk_register_mux(NULL, "sdh_mux", sdh_parent,
+ ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock);
+ clk_register_clkdev(clk, "sdh_mux", NULL);
+
+ clk = clk_register_divider(NULL, "sdh_div", "sdh_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_SDH0,
+ 10, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+ clk_register_clkdev(clk, "sdh_div", NULL);
+
+ clk = mmp_clk_register_apmu("sdh0", "sdh_div", apmu_base + APMU_SDH0,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxav3.0");
+
+ clk = mmp_clk_register_apmu("sdh1", "sdh_div", apmu_base + APMU_SDH1,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxav3.1");
+
+ clk = mmp_clk_register_apmu("sdh2", "sdh_div", apmu_base + APMU_SDH2,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxav3.2");
+
+ clk = mmp_clk_register_apmu("sdh3", "sdh_div", apmu_base + APMU_SDH3,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxav3.3");
+
+ clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
+ 0x9, &clk_lock);
+ clk_register_clkdev(clk, "usb_clk", NULL);
+
+ clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+ ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock);
+ clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+ clk = clk_register_divider(NULL, "disp0_div", "disp0_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_DISP0,
+ 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+ clk_register_clkdev(clk, "disp_div.0", NULL);
+
+ clk = mmp_clk_register_apmu("disp0", "disp0_div",
+ apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-disp.0");
+
+ clk = clk_register_divider(NULL, "disp0_sphy_div", "disp0_mux", 0,
+ apmu_base + APMU_DISP0, 15, 5, 0, &clk_lock);
+ clk_register_clkdev(clk, "disp_sphy_div.0", NULL);
+
+ clk = mmp_clk_register_apmu("disp0_sphy", "disp0_sphy_div",
+ apmu_base + APMU_DISP0, 0x1024, &clk_lock);
+ clk_register_clkdev(clk, "disp_sphy.0", NULL);
+
+ clk = clk_register_mux(NULL, "disp1_mux", disp_parent,
+ ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock);
+ clk_register_clkdev(clk, "disp_mux.1", NULL);
+
+ clk = clk_register_divider(NULL, "disp1_div", "disp1_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_DISP1,
+ 8, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+ clk_register_clkdev(clk, "disp_div.1", NULL);
+
+ clk = mmp_clk_register_apmu("disp1", "disp1_div",
+ apmu_base + APMU_DISP1, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-disp.1");
+
+ clk = mmp_clk_register_apmu("ccic_arbiter", "vctcxo",
+ apmu_base + APMU_CCIC0, 0x1800, &clk_lock);
+ clk_register_clkdev(clk, "ccic_arbiter", NULL);
+
+ clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+ ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+ clk = clk_register_divider(NULL, "ccic0_div", "ccic0_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 17, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+ clk_register_clkdev(clk, "ccic_div.0", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0", "ccic0_div",
+ apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+ clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_div",
+ apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+ clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+ clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_div",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 10, 5, 0, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.0");
+
+ clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+ apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+
+ clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent,
+ ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_mux.1", NULL);
+
+ clk = clk_register_divider(NULL, "ccic1_div", "ccic1_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
+ 16, 4, CLK_DIVIDER_ONE_BASED, &clk_lock);
+ clk_register_clkdev(clk, "ccic_div.1", NULL);
+
+ clk = mmp_clk_register_apmu("ccic1", "ccic1_div",
+ apmu_base + APMU_CCIC1, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, "fnclk", "mmp-ccic.1");
+
+ clk = mmp_clk_register_apmu("ccic1_phy", "ccic1_div",
+ apmu_base + APMU_CCIC1, 0x24, &clk_lock);
+ clk_register_clkdev(clk, "phyclk", "mmp-ccic.1");
+
+ clk = clk_register_divider(NULL, "ccic1_sphy_div", "ccic1_div",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC1,
+ 10, 5, 0, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk_div", "mmp-ccic.1");
+
+ clk = mmp_clk_register_apmu("ccic1_sphy", "ccic1_sphy_div",
+ apmu_base + APMU_CCIC1, 0x300, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk", "mmp-ccic.1");
+}
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
new file mode 100644
index 000000000000..e8d036c12cbf
--- /dev/null
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -0,0 +1,346 @@
+/*
+ * pxa168 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC 0x28
+#define APBC_TWSI0 0x2c
+#define APBC_KPC 0x30
+#define APBC_UART0 0x0
+#define APBC_UART1 0x4
+#define APBC_GPIO 0x8
+#define APBC_PWM0 0xc
+#define APBC_PWM1 0x10
+#define APBC_PWM2 0x14
+#define APBC_PWM3 0x18
+#define APBC_SSP0 0x81c
+#define APBC_SSP1 0x820
+#define APBC_SSP2 0x84c
+#define APBC_SSP3 0x858
+#define APBC_SSP4 0x85c
+#define APBC_TWSI1 0x6c
+#define APBC_UART2 0x70
+#define APMU_SDH0 0x54
+#define APMU_SDH1 0x58
+#define APMU_USB 0x5c
+#define APMU_DISP0 0x4c
+#define APMU_CCIC0 0x50
+#define APMU_DFC 0x60
+#define MPMU_UART_PLL 0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+ .factor = 2,
+ .num_mask = 0x1fff,
+ .den_mask = 0x1fff,
+ .num_shift = 16,
+ .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+ {.num = 8125, .den = 1536}, /*14.745MHZ */
+};
+
+static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
+static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
+static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
+static const char *disp_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
+
+void __init pxa168_clk_init(void)
+{
+ struct clk *clk;
+ struct clk *uart_pll;
+ void __iomem *mpmu_base;
+ void __iomem *apmu_base;
+ void __iomem *apbc_base;
+
+ mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ if (mpmu_base == NULL) {
+ pr_err("error to ioremap MPMU base\n");
+ return;
+ }
+
+ apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ if (apmu_base == NULL) {
+ pr_err("error to ioremap APMU base\n");
+ return;
+ }
+
+ apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ if (apbc_base == NULL) {
+ pr_err("error to ioremap APBC base\n");
+ return;
+ }
+
+ clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+ clk_register_clkdev(clk, "clk32", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+ 26000000);
+ clk_register_clkdev(clk, "vctcxo", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+ 624000000);
+ clk_register_clkdev(clk, "pll1", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_4", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_8", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_16", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll1_6", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_12", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_24", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_48", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_96", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
+ CLK_SET_RATE_PARENT, 1, 13);
+ clk_register_clkdev(clk, "pll1_13", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
+ CLK_SET_RATE_PARENT, 2, 3);
+ clk_register_clkdev(clk, "pll1_13_1_5", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
+ CLK_SET_RATE_PARENT, 2, 3);
+ clk_register_clkdev(clk, "pll1_2_1_5", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
+ CLK_SET_RATE_PARENT, 3, 16);
+ clk_register_clkdev(clk, "pll1_3_16", NULL);
+
+ uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+ mpmu_base + MPMU_UART_PLL,
+ &uart_factor_masks, uart_factor_tbl,
+ ARRAY_SIZE(uart_factor_tbl));
+ clk_set_rate(uart_pll, 14745600);
+ clk_register_clkdev(uart_pll, "uart_pll", NULL);
+
+ clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
+ apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+ clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
+ apbc_base + APBC_TWSI1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+ clk = mmp_clk_register_apbc("gpio", "vctcxo",
+ apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+ clk = mmp_clk_register_apbc("kpc", "clk32",
+ apbc_base + APBC_KPC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+ clk = mmp_clk_register_apbc("rtc", "clk32",
+ apbc_base + APBC_RTC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sa1100-rtc");
+
+ clk = mmp_clk_register_apbc("pwm0", "pll1_48",
+ apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa168-pwm.0");
+
+ clk = mmp_clk_register_apbc("pwm1", "pll1_48",
+ apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa168-pwm.1");
+
+ clk = mmp_clk_register_apbc("pwm2", "pll1_48",
+ apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa168-pwm.2");
+
+ clk = mmp_clk_register_apbc("pwm3", "pll1_48",
+ apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa168-pwm.3");
+
+ clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+ apbc_base + APBC_UART0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+ clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+ apbc_base + APBC_UART1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+ clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+ clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+ apbc_base + APBC_UART2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+ clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("ssp0", "ssp0_mux", apbc_base + APBC_SSP0,
+ 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+ clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("ssp1", "ssp1_mux", apbc_base + APBC_SSP1,
+ 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+ clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.2", NULL);
+
+ clk = mmp_clk_register_apbc("ssp2", "ssp1_mux", apbc_base + APBC_SSP2,
+ 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.2");
+
+ clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.3", NULL);
+
+ clk = mmp_clk_register_apbc("ssp3", "ssp1_mux", apbc_base + APBC_SSP3,
+ 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.3");
+
+ clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.4", NULL);
+
+ clk = mmp_clk_register_apbc("ssp4", "ssp1_mux", apbc_base + APBC_SSP4,
+ 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.4");
+
+ clk = mmp_clk_register_apmu("dfc", "pll1_4", apmu_base + APMU_DFC,
+ 0x19b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
+
+ clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
+ ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "sdh0_mux", NULL);
+
+ clk = mmp_clk_register_apmu("sdh0", "sdh_mux", apmu_base + APMU_SDH0,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
+
+ clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
+ ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "sdh1_mux", NULL);
+
+ clk = mmp_clk_register_apmu("sdh1", "sdh1_mux", apmu_base + APMU_SDH1,
+ 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
+
+ clk = mmp_clk_register_apmu("usb", "usb_pll", apmu_base + APMU_USB,
+ 0x9, &clk_lock);
+ clk_register_clkdev(clk, "usb_clk", NULL);
+
+ clk = mmp_clk_register_apmu("sph", "usb_pll", apmu_base + APMU_USB,
+ 0x12, &clk_lock);
+ clk_register_clkdev(clk, "sph_clk", NULL);
+
+ clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+ ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("disp0", "disp0_mux",
+ apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, "fnclk", "mmp-disp.0");
+
+ clk = mmp_clk_register_apmu("disp0_hclk", "disp0_mux",
+ apmu_base + APMU_DISP0, 0x24, &clk_lock);
+ clk_register_clkdev(clk, "hclk", "mmp-disp.0");
+
+ clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+ ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
+ apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+ clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
+ ARRAY_SIZE(ccic_phy_parent),
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 7, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
+ apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+ clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+ clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 10, 5, 0, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk_div", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+ apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+}
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
new file mode 100644
index 000000000000..7048c31d6e7e
--- /dev/null
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -0,0 +1,320 @@
+/*
+ * pxa910 clock framework source file
+ *
+ * Copyright (C) 2012 Marvell
+ * Chao Xie <xiechao.mail@gmail.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/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/addr-map.h>
+
+#include "clk.h"
+
+#define APBC_RTC 0x28
+#define APBC_TWSI0 0x2c
+#define APBC_KPC 0x18
+#define APBC_UART0 0x0
+#define APBC_UART1 0x4
+#define APBC_GPIO 0x8
+#define APBC_PWM0 0xc
+#define APBC_PWM1 0x10
+#define APBC_PWM2 0x14
+#define APBC_PWM3 0x18
+#define APBC_SSP0 0x1c
+#define APBC_SSP1 0x20
+#define APBC_SSP2 0x4c
+#define APBCP_TWSI1 0x28
+#define APBCP_UART2 0x1c
+#define APMU_SDH0 0x54
+#define APMU_SDH1 0x58
+#define APMU_USB 0x5c
+#define APMU_DISP0 0x4c
+#define APMU_CCIC0 0x50
+#define APMU_DFC 0x60
+#define MPMU_UART_PLL 0x14
+
+static DEFINE_SPINLOCK(clk_lock);
+
+static struct clk_factor_masks uart_factor_masks = {
+ .factor = 2,
+ .num_mask = 0x1fff,
+ .den_mask = 0x1fff,
+ .num_shift = 16,
+ .den_shift = 0,
+};
+
+static struct clk_factor_tbl uart_factor_tbl[] = {
+ {.num = 8125, .den = 1536}, /*14.745MHZ */
+};
+
+static const char *uart_parent[] = {"pll1_3_16", "uart_pll"};
+static const char *ssp_parent[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"};
+static const char *sdh_parent[] = {"pll1_12", "pll1_13"};
+static const char *disp_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_parent[] = {"pll1_2", "pll1_12"};
+static const char *ccic_phy_parent[] = {"pll1_6", "pll1_12"};
+
+void __init pxa910_clk_init(void)
+{
+ struct clk *clk;
+ struct clk *uart_pll;
+ void __iomem *mpmu_base;
+ void __iomem *apmu_base;
+ void __iomem *apbcp_base;
+ void __iomem *apbc_base;
+
+ mpmu_base = ioremap(APB_PHYS_BASE + 0x50000, SZ_4K);
+ if (mpmu_base == NULL) {
+ pr_err("error to ioremap MPMU base\n");
+ return;
+ }
+
+ apmu_base = ioremap(AXI_PHYS_BASE + 0x82800, SZ_4K);
+ if (apmu_base == NULL) {
+ pr_err("error to ioremap APMU base\n");
+ return;
+ }
+
+ apbcp_base = ioremap(APB_PHYS_BASE + 0x3b000, SZ_4K);
+ if (apbcp_base == NULL) {
+ pr_err("error to ioremap APBC extension base\n");
+ return;
+ }
+
+ apbc_base = ioremap(APB_PHYS_BASE + 0x15000, SZ_4K);
+ if (apbc_base == NULL) {
+ pr_err("error to ioremap APBC base\n");
+ return;
+ }
+
+ clk = clk_register_fixed_rate(NULL, "clk32", NULL, CLK_IS_ROOT, 3200);
+ clk_register_clkdev(clk, "clk32", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "vctcxo", NULL, CLK_IS_ROOT,
+ 26000000);
+ clk_register_clkdev(clk, "vctcxo", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "pll1", NULL, CLK_IS_ROOT,
+ 624000000);
+ clk_register_clkdev(clk, "pll1", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_2", "pll1",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_2", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_4", "pll1_2",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_4", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_8", "pll1_4",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_8", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_16", "pll1_8",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_16", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_6", "pll1_2",
+ CLK_SET_RATE_PARENT, 1, 3);
+ clk_register_clkdev(clk, "pll1_6", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_12", "pll1_6",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_12", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_24", "pll1_12",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_24", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_48", "pll1_24",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_48", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_96", "pll1_48",
+ CLK_SET_RATE_PARENT, 1, 2);
+ clk_register_clkdev(clk, "pll1_96", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_13", "pll1",
+ CLK_SET_RATE_PARENT, 1, 13);
+ clk_register_clkdev(clk, "pll1_13", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_13_1_5", "pll1",
+ CLK_SET_RATE_PARENT, 2, 3);
+ clk_register_clkdev(clk, "pll1_13_1_5", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_2_1_5", "pll1",
+ CLK_SET_RATE_PARENT, 2, 3);
+ clk_register_clkdev(clk, "pll1_2_1_5", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "pll1_3_16", "pll1",
+ CLK_SET_RATE_PARENT, 3, 16);
+ clk_register_clkdev(clk, "pll1_3_16", NULL);
+
+ uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0,
+ mpmu_base + MPMU_UART_PLL,
+ &uart_factor_masks, uart_factor_tbl,
+ ARRAY_SIZE(uart_factor_tbl));
+ clk_set_rate(uart_pll, 14745600);
+ clk_register_clkdev(uart_pll, "uart_pll", NULL);
+
+ clk = mmp_clk_register_apbc("twsi0", "pll1_13_1_5",
+ apbc_base + APBC_TWSI0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.0");
+
+ clk = mmp_clk_register_apbc("twsi1", "pll1_13_1_5",
+ apbcp_base + APBCP_TWSI1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-i2c.1");
+
+ clk = mmp_clk_register_apbc("gpio", "vctcxo",
+ apbc_base + APBC_GPIO, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa-gpio");
+
+ clk = mmp_clk_register_apbc("kpc", "clk32",
+ apbc_base + APBC_KPC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa27x-keypad");
+
+ clk = mmp_clk_register_apbc("rtc", "clk32",
+ apbc_base + APBC_RTC, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sa1100-rtc");
+
+ clk = mmp_clk_register_apbc("pwm0", "pll1_48",
+ apbc_base + APBC_PWM0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa910-pwm.0");
+
+ clk = mmp_clk_register_apbc("pwm1", "pll1_48",
+ apbc_base + APBC_PWM1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa910-pwm.1");
+
+ clk = mmp_clk_register_apbc("pwm2", "pll1_48",
+ apbc_base + APBC_PWM2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa910-pwm.2");
+
+ clk = mmp_clk_register_apbc("pwm3", "pll1_48",
+ apbc_base + APBC_PWM3, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa910-pwm.3");
+
+ clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("uart0", "uart0_mux",
+ apbc_base + APBC_UART0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
+
+ clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("uart1", "uart1_mux",
+ apbc_base + APBC_UART1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
+
+ clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
+ ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+ apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock);
+ clk_set_parent(clk, uart_pll);
+ clk_register_clkdev(clk, "uart_mux.2", NULL);
+
+ clk = mmp_clk_register_apbc("uart2", "uart2_mux",
+ apbcp_base + APBCP_UART2, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
+
+ clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "uart_mux.0", NULL);
+
+ clk = mmp_clk_register_apbc("ssp0", "ssp0_mux",
+ apbc_base + APBC_SSP0, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.0");
+
+ clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
+ ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+ apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
+ clk_register_clkdev(clk, "ssp_mux.1", NULL);
+
+ clk = mmp_clk_register_apbc("ssp1", "ssp1_mux",
+ apbc_base + APBC_SSP1, 10, 0, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-ssp.1");
+
+ clk = mmp_clk_register_apmu("dfc", "pll1_4",
+ apmu_base + APMU_DFC, 0x19b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
+
+ clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
+ ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "sdh0_mux", NULL);
+
+ clk = mmp_clk_register_apmu("sdh0", "sdh_mux",
+ apmu_base + APMU_SDH0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
+
+ clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
+ ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "sdh1_mux", NULL);
+
+ clk = mmp_clk_register_apmu("sdh1", "sdh1_mux",
+ apmu_base + APMU_SDH1, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "sdhci-pxa.1");
+
+ clk = mmp_clk_register_apmu("usb", "usb_pll",
+ apmu_base + APMU_USB, 0x9, &clk_lock);
+ clk_register_clkdev(clk, "usb_clk", NULL);
+
+ clk = mmp_clk_register_apmu("sph", "usb_pll",
+ apmu_base + APMU_USB, 0x12, &clk_lock);
+ clk_register_clkdev(clk, "sph_clk", NULL);
+
+ clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
+ ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "disp_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("disp0", "disp0_mux",
+ apmu_base + APMU_DISP0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, NULL, "mmp-disp.0");
+
+ clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
+ ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+ apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0", "ccic0_mux",
+ apmu_base + APMU_CCIC0, 0x1b, &clk_lock);
+ clk_register_clkdev(clk, "fnclk", "mmp-ccic.0");
+
+ clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
+ ARRAY_SIZE(ccic_phy_parent),
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 7, 1, 0, &clk_lock);
+ clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
+ apmu_base + APMU_CCIC0, 0x24, &clk_lock);
+ clk_register_clkdev(clk, "phyclk", "mmp-ccic.0");
+
+ clk = clk_register_divider(NULL, "ccic0_sphy_div", "ccic0_mux",
+ CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
+ 10, 5, 0, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk_div", NULL);
+
+ clk = mmp_clk_register_apmu("ccic0_sphy", "ccic0_sphy_div",
+ apmu_base + APMU_CCIC0, 0x300, &clk_lock);
+ clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
+}
diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h
new file mode 100644
index 000000000000..ab86dd4a416a
--- /dev/null
+++ b/drivers/clk/mmp/clk.h
@@ -0,0 +1,35 @@
+#ifndef __MACH_MMP_CLK_H
+#define __MACH_MMP_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#define APBC_NO_BUS_CTRL BIT(0)
+#define APBC_POWER_CTRL BIT(1)
+
+struct clk_factor_masks {
+ unsigned int factor;
+ unsigned int num_mask;
+ unsigned int den_mask;
+ unsigned int num_shift;
+ unsigned int den_shift;
+};
+
+struct clk_factor_tbl {
+ unsigned int num;
+ unsigned int den;
+};
+
+extern struct clk *mmp_clk_register_pll2(const char *name,
+ const char *parent_name, unsigned long flags);
+extern struct clk *mmp_clk_register_apbc(const char *name,
+ const char *parent_name, void __iomem *base,
+ unsigned int delay, unsigned int apbc_flags, spinlock_t *lock);
+extern struct clk *mmp_clk_register_apmu(const char *name,
+ const char *parent_name, void __iomem *base, u32 enable_mask,
+ spinlock_t *lock);
+extern struct clk *mmp_clk_register_factor(const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *base, struct clk_factor_masks *masks,
+ struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt);
+#endif
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 844043ad0fe4..9f6d15546cbe 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <mach/common.h>
#include <mach/mx23.h>
#include "clk.h"
@@ -71,44 +72,6 @@ static void __init clk_misc_init(void)
__mxs_setl(30 << BP_FRAC_IOFRAC, FRAC);
}
-static struct clk_lookup uart_lookups[] = {
- { .dev_id = "duart", },
- { .dev_id = "mxs-auart.0", },
- { .dev_id = "mxs-auart.1", },
- { .dev_id = "8006c000.serial", },
- { .dev_id = "8006e000.serial", },
- { .dev_id = "80070000.serial", },
-};
-
-static struct clk_lookup hbus_lookups[] = {
- { .dev_id = "imx23-dma-apbh", },
- { .dev_id = "80004000.dma-apbh", },
-};
-
-static struct clk_lookup xbus_lookups[] = {
- { .dev_id = "duart", .con_id = "apb_pclk"},
- { .dev_id = "80070000.serial", .con_id = "apb_pclk"},
- { .dev_id = "imx23-dma-apbx", },
- { .dev_id = "80024000.dma-apbx", },
-};
-
-static struct clk_lookup ssp_lookups[] = {
- { .dev_id = "imx23-mmc.0", },
- { .dev_id = "imx23-mmc.1", },
- { .dev_id = "80010000.ssp", },
- { .dev_id = "80034000.ssp", },
-};
-
-static struct clk_lookup lcdif_lookups[] = {
- { .dev_id = "imx23-fb", },
- { .dev_id = "80030000.lcdif", },
-};
-
-static struct clk_lookup gpmi_lookups[] = {
- { .dev_id = "imx23-gpmi-nand", },
- { .dev_id = "8000c000.gpmi-nand", },
-};
-
static const char *sel_pll[] __initconst = { "pll", "ref_xtal", };
static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", };
static const char *sel_pix[] __initconst = { "ref_pix", "ref_xtal", };
@@ -127,6 +90,7 @@ enum imx23_clk {
};
static struct clk *clks[clk_max];
+static struct clk_onecell_data clk_data;
static enum imx23_clk clks_init_on[] __initdata = {
cpu, hbus, xbus, emi, uart,
@@ -134,6 +98,7 @@ static enum imx23_clk clks_init_on[] __initdata = {
int __init mx23_clocks_init(void)
{
+ struct device_node *np;
int i;
clk_misc_init();
@@ -188,14 +153,14 @@ int __init mx23_clocks_init(void)
return PTR_ERR(clks[i]);
}
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl");
+ if (np) {
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ }
+
clk_register_clkdev(clks[clk32k], NULL, "timrot");
- clk_register_clkdev(clks[pwm], NULL, "80064000.pwm");
- clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups));
- clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups));
- clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups));
- clk_register_clkdevs(clks[ssp], ssp_lookups, ARRAY_SIZE(ssp_lookups));
- clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups));
- clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups));
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index e3aab67b3eb7..613e76f3758e 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <mach/common.h>
#include <mach/mx28.h>
#include "clk.h"
@@ -120,90 +121,6 @@ static void __init clk_misc_init(void)
writel_relaxed(val, FRAC0);
}
-static struct clk_lookup uart_lookups[] = {
- { .dev_id = "duart", },
- { .dev_id = "mxs-auart.0", },
- { .dev_id = "mxs-auart.1", },
- { .dev_id = "mxs-auart.2", },
- { .dev_id = "mxs-auart.3", },
- { .dev_id = "mxs-auart.4", },
- { .dev_id = "8006a000.serial", },
- { .dev_id = "8006c000.serial", },
- { .dev_id = "8006e000.serial", },
- { .dev_id = "80070000.serial", },
- { .dev_id = "80072000.serial", },
- { .dev_id = "80074000.serial", },
-};
-
-static struct clk_lookup hbus_lookups[] = {
- { .dev_id = "imx28-dma-apbh", },
- { .dev_id = "80004000.dma-apbh", },
-};
-
-static struct clk_lookup xbus_lookups[] = {
- { .dev_id = "duart", .con_id = "apb_pclk"},
- { .dev_id = "80074000.serial", .con_id = "apb_pclk"},
- { .dev_id = "imx28-dma-apbx", },
- { .dev_id = "80024000.dma-apbx", },
-};
-
-static struct clk_lookup ssp0_lookups[] = {
- { .dev_id = "imx28-mmc.0", },
- { .dev_id = "80010000.ssp", },
-};
-
-static struct clk_lookup ssp1_lookups[] = {
- { .dev_id = "imx28-mmc.1", },
- { .dev_id = "80012000.ssp", },
-};
-
-static struct clk_lookup ssp2_lookups[] = {
- { .dev_id = "imx28-mmc.2", },
- { .dev_id = "80014000.ssp", },
-};
-
-static struct clk_lookup ssp3_lookups[] = {
- { .dev_id = "imx28-mmc.3", },
- { .dev_id = "80016000.ssp", },
-};
-
-static struct clk_lookup lcdif_lookups[] = {
- { .dev_id = "imx28-fb", },
- { .dev_id = "80030000.lcdif", },
-};
-
-static struct clk_lookup gpmi_lookups[] = {
- { .dev_id = "imx28-gpmi-nand", },
- { .dev_id = "8000c000.gpmi-nand", },
-};
-
-static struct clk_lookup fec_lookups[] = {
- { .dev_id = "imx28-fec.0", },
- { .dev_id = "imx28-fec.1", },
- { .dev_id = "800f0000.ethernet", },
- { .dev_id = "800f4000.ethernet", },
-};
-
-static struct clk_lookup can0_lookups[] = {
- { .dev_id = "flexcan.0", },
- { .dev_id = "80032000.can", },
-};
-
-static struct clk_lookup can1_lookups[] = {
- { .dev_id = "flexcan.1", },
- { .dev_id = "80034000.can", },
-};
-
-static struct clk_lookup saif0_lookups[] = {
- { .dev_id = "mxs-saif.0", },
- { .dev_id = "80042000.saif", },
-};
-
-static struct clk_lookup saif1_lookups[] = {
- { .dev_id = "mxs-saif.1", },
- { .dev_id = "80046000.saif", },
-};
-
static const char *sel_cpu[] __initconst = { "ref_cpu", "ref_xtal", };
static const char *sel_io0[] __initconst = { "ref_io0", "ref_xtal", };
static const char *sel_io1[] __initconst = { "ref_io1", "ref_xtal", };
@@ -228,6 +145,7 @@ enum imx28_clk {
};
static struct clk *clks[clk_max];
+static struct clk_onecell_data clk_data;
static enum imx28_clk clks_init_on[] __initdata = {
cpu, hbus, xbus, emi, uart,
@@ -235,6 +153,7 @@ static enum imx28_clk clks_init_on[] __initdata = {
int __init mx28_clocks_init(void)
{
+ struct device_node *np;
int i;
clk_misc_init();
@@ -312,27 +231,15 @@ int __init mx28_clocks_init(void)
return PTR_ERR(clks[i]);
}
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl");
+ if (np) {
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ }
+
clk_register_clkdev(clks[clk32k], NULL, "timrot");
clk_register_clkdev(clks[enet_out], NULL, "enet_out");
- clk_register_clkdev(clks[pwm], NULL, "80064000.pwm");
- clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups));
- clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups));
- clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups));
- clk_register_clkdevs(clks[ssp0], ssp0_lookups, ARRAY_SIZE(ssp0_lookups));
- clk_register_clkdevs(clks[ssp1], ssp1_lookups, ARRAY_SIZE(ssp1_lookups));
- clk_register_clkdevs(clks[ssp2], ssp2_lookups, ARRAY_SIZE(ssp2_lookups));
- clk_register_clkdevs(clks[ssp3], ssp3_lookups, ARRAY_SIZE(ssp3_lookups));
- clk_register_clkdevs(clks[gpmi], gpmi_lookups, ARRAY_SIZE(gpmi_lookups));
- clk_register_clkdevs(clks[saif0], saif0_lookups, ARRAY_SIZE(saif0_lookups));
- clk_register_clkdevs(clks[saif1], saif1_lookups, ARRAY_SIZE(saif1_lookups));
- clk_register_clkdevs(clks[lcdif], lcdif_lookups, ARRAY_SIZE(lcdif_lookups));
- clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups));
- clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups));
- clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups));
- clk_register_clkdev(clks[usb0_pwr], NULL, "8007c000.usbphy");
- clk_register_clkdev(clks[usb1_pwr], NULL, "8007e000.usbphy");
- clk_register_clkdev(clks[usb0], NULL, "80080000.usb");
- clk_register_clkdev(clks[usb1], NULL, "80090000.usb");
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
new file mode 100644
index 000000000000..858fbfe66281
--- /dev/null
+++ b/drivers/clk/ux500/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for ux500 clocks
+#
+
+# Clock types
+obj-y += clk-prcc.o
+obj-y += clk-prcmu.o
+
+# Clock definitions
+obj-y += u8500_clk.o
+obj-y += u9540_clk.o
+obj-y += u8540_clk.o
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c
new file mode 100644
index 000000000000..7eee7f768355
--- /dev/null
+++ b/drivers/clk/ux500/clk-prcc.c
@@ -0,0 +1,164 @@
+/*
+ * PRCC clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <mach/hardware.h>
+
+#include "clk.h"
+
+#define PRCC_PCKEN 0x000
+#define PRCC_PCKDIS 0x004
+#define PRCC_KCKEN 0x008
+#define PRCC_KCKDIS 0x00C
+#define PRCC_PCKSR 0x010
+#define PRCC_KCKSR 0x014
+
+#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw)
+
+struct clk_prcc {
+ struct clk_hw hw;
+ void __iomem *base;
+ u32 cg_sel;
+ int is_enabled;
+};
+
+/* PRCC clock operations. */
+
+static int clk_prcc_pclk_enable(struct clk_hw *hw)
+{
+ struct clk_prcc *clk = to_clk_prcc(hw);
+
+ writel(clk->cg_sel, (clk->base + PRCC_PCKEN));
+ while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel))
+ cpu_relax();
+
+ clk->is_enabled = 1;
+ return 0;
+}
+
+static void clk_prcc_pclk_disable(struct clk_hw *hw)
+{
+ struct clk_prcc *clk = to_clk_prcc(hw);
+
+ writel(clk->cg_sel, (clk->base + PRCC_PCKDIS));
+ clk->is_enabled = 0;
+}
+
+static int clk_prcc_kclk_enable(struct clk_hw *hw)
+{
+ struct clk_prcc *clk = to_clk_prcc(hw);
+
+ writel(clk->cg_sel, (clk->base + PRCC_KCKEN));
+ while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel))
+ cpu_relax();
+
+ clk->is_enabled = 1;
+ return 0;
+}
+
+static void clk_prcc_kclk_disable(struct clk_hw *hw)
+{
+ struct clk_prcc *clk = to_clk_prcc(hw);
+
+ writel(clk->cg_sel, (clk->base + PRCC_KCKDIS));
+ clk->is_enabled = 0;
+}
+
+static int clk_prcc_is_enabled(struct clk_hw *hw)
+{
+ struct clk_prcc *clk = to_clk_prcc(hw);
+ return clk->is_enabled;
+}
+
+static struct clk_ops clk_prcc_pclk_ops = {
+ .enable = clk_prcc_pclk_enable,
+ .disable = clk_prcc_pclk_disable,
+ .is_enabled = clk_prcc_is_enabled,
+};
+
+static struct clk_ops clk_prcc_kclk_ops = {
+ .enable = clk_prcc_kclk_enable,
+ .disable = clk_prcc_kclk_disable,
+ .is_enabled = clk_prcc_is_enabled,
+};
+
+static struct clk *clk_reg_prcc(const char *name,
+ const char *parent_name,
+ resource_size_t phy_base,
+ u32 cg_sel,
+ unsigned long flags,
+ struct clk_ops *clk_prcc_ops)
+{
+ struct clk_prcc *clk;
+ struct clk_init_data clk_prcc_init;
+ struct clk *clk_reg;
+
+ if (!name) {
+ pr_err("clk_prcc: %s invalid arguments passed\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL);
+ if (!clk) {
+ pr_err("clk_prcc: %s could not allocate clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ clk->base = ioremap(phy_base, SZ_4K);
+ if (!clk->base)
+ goto free_clk;
+
+ clk->cg_sel = cg_sel;
+ clk->is_enabled = 1;
+
+ clk_prcc_init.name = name;
+ clk_prcc_init.ops = clk_prcc_ops;
+ clk_prcc_init.flags = flags;
+ clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL);
+ clk_prcc_init.num_parents = (parent_name ? 1 : 0);
+ clk->hw.init = &clk_prcc_init;
+
+ clk_reg = clk_register(NULL, &clk->hw);
+ if (IS_ERR_OR_NULL(clk_reg))
+ goto unmap_clk;
+
+ return clk_reg;
+
+unmap_clk:
+ iounmap(clk->base);
+free_clk:
+ kfree(clk);
+ pr_err("clk_prcc: %s failed to register clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+}
+
+struct clk *clk_reg_prcc_pclk(const char *name,
+ const char *parent_name,
+ resource_size_t phy_base,
+ u32 cg_sel,
+ unsigned long flags)
+{
+ return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
+ &clk_prcc_pclk_ops);
+}
+
+struct clk *clk_reg_prcc_kclk(const char *name,
+ const char *parent_name,
+ resource_size_t phy_base,
+ u32 cg_sel,
+ unsigned long flags)
+{
+ return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
+ &clk_prcc_kclk_ops);
+}
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
new file mode 100644
index 000000000000..930cdfeb47ab
--- /dev/null
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -0,0 +1,252 @@
+/*
+ * PRCMU clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clk-private.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include "clk.h"
+
+#define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
+
+struct clk_prcmu {
+ struct clk_hw hw;
+ u8 cg_sel;
+ int is_enabled;
+};
+
+/* PRCMU clock operations. */
+
+static int clk_prcmu_prepare(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return prcmu_request_clock(clk->cg_sel, true);
+}
+
+static void clk_prcmu_unprepare(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ if (prcmu_request_clock(clk->cg_sel, false))
+ pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+ hw->init->name);
+}
+
+static int clk_prcmu_enable(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ clk->is_enabled = 1;
+ return 0;
+}
+
+static void clk_prcmu_disable(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ clk->is_enabled = 0;
+}
+
+static int clk_prcmu_is_enabled(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return clk->is_enabled;
+}
+
+static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return prcmu_clock_rate(clk->cg_sel);
+}
+
+static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return prcmu_round_clock_rate(clk->cg_sel, rate);
+}
+
+static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return prcmu_set_clock_rate(clk->cg_sel, rate);
+}
+
+static int request_ape_opp100(bool enable)
+{
+ static int reqs;
+ int err = 0;
+
+ if (enable) {
+ if (!reqs)
+ err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+ "clock", 100);
+ if (!err)
+ reqs++;
+ } else {
+ reqs--;
+ if (!reqs)
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
+ "clock");
+ }
+ return err;
+}
+
+static int clk_prcmu_opp_prepare(struct clk_hw *hw)
+{
+ int err;
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+ err = request_ape_opp100(true);
+ if (err) {
+ pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
+ __func__, hw->init->name);
+ return err;
+ }
+
+ err = prcmu_request_clock(clk->cg_sel, true);
+ if (err)
+ request_ape_opp100(false);
+
+ return err;
+}
+
+static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+ if (prcmu_request_clock(clk->cg_sel, false))
+ goto out_error;
+ if (request_ape_opp100(false))
+ goto out_error;
+ return;
+
+out_error:
+ pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+ hw->init->name);
+}
+
+static struct clk_ops clk_prcmu_scalable_ops = {
+ .prepare = clk_prcmu_prepare,
+ .unprepare = clk_prcmu_unprepare,
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+ .round_rate = clk_prcmu_round_rate,
+ .set_rate = clk_prcmu_set_rate,
+};
+
+static struct clk_ops clk_prcmu_gate_ops = {
+ .prepare = clk_prcmu_prepare,
+ .unprepare = clk_prcmu_unprepare,
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk_ops clk_prcmu_rate_ops = {
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk_ops clk_prcmu_opp_gate_ops = {
+ .prepare = clk_prcmu_opp_prepare,
+ .unprepare = clk_prcmu_opp_unprepare,
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+};
+
+static struct clk *clk_reg_prcmu(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags,
+ struct clk_ops *clk_prcmu_ops)
+{
+ struct clk_prcmu *clk;
+ struct clk_init_data clk_prcmu_init;
+ struct clk *clk_reg;
+
+ if (!name) {
+ pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL);
+ if (!clk) {
+ pr_err("clk_prcmu: %s could not allocate clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ clk->cg_sel = cg_sel;
+ clk->is_enabled = 1;
+ /* "rate" can be used for changing the initial frequency */
+ if (rate)
+ prcmu_set_clock_rate(cg_sel, rate);
+
+ clk_prcmu_init.name = name;
+ clk_prcmu_init.ops = clk_prcmu_ops;
+ clk_prcmu_init.flags = flags;
+ clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
+ clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
+ clk->hw.init = &clk_prcmu_init;
+
+ clk_reg = clk_register(NULL, &clk->hw);
+ if (IS_ERR_OR_NULL(clk_reg))
+ goto free_clk;
+
+ return clk_reg;
+
+free_clk:
+ kfree(clk);
+ pr_err("clk_prcmu: %s failed to register clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+}
+
+struct clk *clk_reg_prcmu_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+ &clk_prcmu_scalable_ops);
+}
+
+struct clk *clk_reg_prcmu_gate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+ &clk_prcmu_gate_ops);
+}
+
+struct clk *clk_reg_prcmu_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+ &clk_prcmu_rate_ops);
+}
+
+struct clk *clk_reg_prcmu_opp_gate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
+ &clk_prcmu_opp_gate_ops);
+}
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
new file mode 100644
index 000000000000..836d7d16751e
--- /dev/null
+++ b/drivers/clk/ux500/clk.h
@@ -0,0 +1,48 @@
+/*
+ * Clocks for ux500 platforms
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __UX500_CLK_H
+#define __UX500_CLK_H
+
+#include <linux/clk.h>
+
+struct clk *clk_reg_prcc_pclk(const char *name,
+ const char *parent_name,
+ unsigned int phy_base,
+ u32 cg_sel,
+ unsigned long flags);
+
+struct clk *clk_reg_prcc_kclk(const char *name,
+ const char *parent_name,
+ unsigned int phy_base,
+ u32 cg_sel,
+ unsigned long flags);
+
+struct clk *clk_reg_prcmu_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags);
+
+struct clk *clk_reg_prcmu_gate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags);
+
+struct clk *clk_reg_prcmu_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags);
+
+struct clk *clk_reg_prcmu_opp_gate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long flags);
+
+#endif /* __UX500_CLK_H */
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
new file mode 100644
index 000000000000..ca4a25ed844c
--- /dev/null
+++ b/drivers/clk/ux500/u8500_clk.c
@@ -0,0 +1,477 @@
+/*
+ * Clock definitions for u8500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u8500_clk_init(void)
+{
+ struct prcmu_fw_version *fw_version;
+ const char *sgaclk_parent = NULL;
+ struct clk *clk;
+
+ /* Clock sources */
+ clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "soc0_pll", NULL);
+
+ clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "soc1_pll", NULL);
+
+ clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "ddr_pll", NULL);
+
+ /* FIXME: Add sys, ulp and int clocks here. */
+
+ clk = clk_register_fixed_rate(NULL, "rtc32k", "NULL",
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+ 32768);
+ clk_register_clkdev(clk, "clk32k", NULL);
+ clk_register_clkdev(clk, NULL, "rtc-pl031");
+
+ /* PRCMU clocks */
+ fw_version = prcmu_get_fw_version();
+ if (fw_version != NULL) {
+ switch (fw_version->project) {
+ case PRCMU_FW_PROJECT_U8500_C2:
+ case PRCMU_FW_PROJECT_U8520:
+ case PRCMU_FW_PROJECT_U8420:
+ sgaclk_parent = "soc0_pll";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (sgaclk_parent)
+ clk = clk_reg_prcmu_gate("sgclk", sgaclk_parent,
+ PRCMU_SGACLK, 0);
+ else
+ clk = clk_reg_prcmu_gate("sgclk", NULL,
+ PRCMU_SGACLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "mali");
+
+ clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "UART");
+
+ clk = clk_reg_prcmu_gate("msp02clk", NULL, PRCMU_MSP02CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "MSP02");
+
+ clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "MSP1");
+
+ clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "I2C");
+
+ clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "slim");
+
+ clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH1");
+
+ clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH2");
+
+ clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH3");
+
+ clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH5");
+
+ clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH6");
+
+ clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH7");
+
+ clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "lcd");
+ clk_register_clkdev(clk, "lcd", "mcde");
+
+ clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BMLCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "bml");
+
+ clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "hdmi");
+ clk_register_clkdev(clk, "hdmi", "mcde");
+
+ clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "apeat");
+
+ clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "apetrace");
+
+ clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "mcde");
+ clk_register_clkdev(clk, "mcde", "mcde");
+ clk_register_clkdev(clk, "dsisys", "dsilink.0");
+ clk_register_clkdev(clk, "dsisys", "dsilink.1");
+ clk_register_clkdev(clk, "dsisys", "dsilink.2");
+
+ clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "ipi2");
+
+ clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "dsialt");
+
+ clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "dma40.0");
+
+ clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "b2r2");
+ clk_register_clkdev(clk, NULL, "b2r2_core");
+ clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
+
+ clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "tv");
+ clk_register_clkdev(clk, "tv", "mcde");
+
+ clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "SSP");
+
+ clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "rngclk");
+
+ clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "uicc");
+
+ /*
+ * FIXME: The MTU clocks might need some kind of "parent muxed join"
+ * and these have no K-clocks. For now, we ignore the missing
+ * connection to the corresponding P-clocks, p6_mtu0_clk and
+ * p6_mtu1_clk. Instead timclk is used which is the valid parent.
+ */
+ clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "mtu0");
+ clk_register_clkdev(clk, NULL, "mtu1");
+
+ clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "sdmmc");
+
+
+ clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
+ PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs2", "mcde");
+ clk_register_clkdev(clk, "dsihs2", "dsilink.2");
+
+
+ clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
+ PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs0", "mcde");
+ clk_register_clkdev(clk, "dsihs0", "dsilink.0");
+
+ clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
+ PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs1", "mcde");
+ clk_register_clkdev(clk, "dsihs1", "dsilink.1");
+
+ clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
+ PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsilp0", "dsilink.0");
+ clk_register_clkdev(clk, "dsilp0", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
+ PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsilp1", "dsilink.1");
+ clk_register_clkdev(clk, "dsilp1", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
+ PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsilp2", "dsilink.2");
+ clk_register_clkdev(clk, "dsilp2", "mcde");
+
+ clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS,
+ CLK_IS_ROOT|CLK_GET_RATE_NOCACHE|
+ CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
+ /*
+ * FIXME: Add special handled PRCMU clocks here:
+ * 1. clk_arm, use PRCMU_ARMCLK.
+ * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
+ * 3. ab9540_clkout1yuv, see clkout0yuv
+ */
+
+ /* PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", U8500_CLKRST1_BASE,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", U8500_CLKRST1_BASE,
+ BIT(1), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart1");
+
+ clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE,
+ BIT(2), 0);
+ clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE,
+ BIT(3), 0);
+ clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE,
+ BIT(4), 0);
+
+ clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE,
+ BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE,
+ BIT(6), 0);
+
+ clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE,
+ BIT(7), 0);
+ clk_register_clkdev(clk, NULL, "spi3");
+
+ clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE,
+ BIT(8), 0);
+
+ clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE,
+ BIT(9), 0);
+ clk_register_clkdev(clk, NULL, "gpio.0");
+ clk_register_clkdev(clk, NULL, "gpio.1");
+ clk_register_clkdev(clk, NULL, "gpioblock0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE,
+ BIT(10), 0);
+ clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE,
+ BIT(11), 0);
+
+ clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE,
+ BIT(0), 0);
+
+ clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "spi2");
+
+ clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", U8500_CLKRST2_BASE,
+ BIT(2), 0);
+ clk_register_clkdev(clk, NULL, "spi1");
+
+ clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", U8500_CLKRST2_BASE,
+ BIT(3), 0);
+ clk_register_clkdev(clk, NULL, "pwl");
+
+ clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", U8500_CLKRST2_BASE,
+ BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi4");
+
+ clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE,
+ BIT(5), 0);
+
+ clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi1");
+
+
+ clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE,
+ BIT(7), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi3");
+
+ clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", U8500_CLKRST2_BASE,
+ BIT(8), 0);
+ clk_register_clkdev(clk, NULL, "spi0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", U8500_CLKRST2_BASE,
+ BIT(9), 0);
+ clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", U8500_CLKRST2_BASE,
+ BIT(10), 0);
+ clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", U8500_CLKRST2_BASE,
+ BIT(11), 0);
+ clk_register_clkdev(clk, NULL, "gpio.6");
+ clk_register_clkdev(clk, NULL, "gpio.7");
+ clk_register_clkdev(clk, NULL, "gpioblock1");
+
+ clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
+ BIT(11), 0);
+
+ clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
+ BIT(0), 0);
+ clk_register_clkdev(clk, NULL, "fsmc");
+
+ clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE,
+ BIT(1), 0);
+ clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE,
+ BIT(2), 0);
+ clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE,
+ BIT(3), 0);
+
+ clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE,
+ BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi2");
+
+ clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
+ BIT(5), 0);
+
+ clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart2");
+
+ clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", U8500_CLKRST3_BASE,
+ BIT(7), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi5");
+
+ clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", U8500_CLKRST3_BASE,
+ BIT(8), 0);
+ clk_register_clkdev(clk, NULL, "gpio.2");
+ clk_register_clkdev(clk, NULL, "gpio.3");
+ clk_register_clkdev(clk, NULL, "gpio.4");
+ clk_register_clkdev(clk, NULL, "gpio.5");
+ clk_register_clkdev(clk, NULL, "gpioblock2");
+
+ clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", U8500_CLKRST5_BASE,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "usb", "musb-ux500.0");
+
+ clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", U8500_CLKRST5_BASE,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "gpio.8");
+ clk_register_clkdev(clk, NULL, "gpioblock3");
+
+ clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
+ BIT(0), 0);
+
+ clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "cryp0");
+ clk_register_clkdev(clk, NULL, "cryp1");
+
+ clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", U8500_CLKRST6_BASE,
+ BIT(2), 0);
+ clk_register_clkdev(clk, NULL, "hash0");
+
+ clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", U8500_CLKRST6_BASE,
+ BIT(3), 0);
+ clk_register_clkdev(clk, NULL, "pka");
+
+ clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", U8500_CLKRST6_BASE,
+ BIT(4), 0);
+ clk_register_clkdev(clk, NULL, "hash1");
+
+ clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", U8500_CLKRST6_BASE,
+ BIT(5), 0);
+ clk_register_clkdev(clk, NULL, "cfgreg");
+
+ clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", U8500_CLKRST6_BASE,
+ BIT(6), 0);
+ clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", U8500_CLKRST6_BASE,
+ BIT(7), 0);
+
+ /* PRCC K-clocks
+ *
+ * FIXME: Some drivers requires PERPIH[n| to be automatically enabled
+ * by enabling just the K-clock, even if it is not a valid parent to
+ * the K-clock. Until drivers get fixed we might need some kind of
+ * "parent muxed join".
+ */
+
+ /* Periph1 */
+ clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
+ U8500_CLKRST1_BASE, BIT(0), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart0");
+
+ clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
+ U8500_CLKRST1_BASE, BIT(1), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart1");
+
+ clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
+ U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
+ U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
+ U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
+ U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi0");
+
+ clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
+ U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
+ U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
+ /* FIXME: Redefinition of BIT(3). */
+ clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
+ U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
+ U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE);
+
+ /* Periph2 */
+ clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
+ U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
+ U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi4");
+
+ clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
+ U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
+ U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi1");
+
+ clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
+ U8500_CLKRST2_BASE, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi3");
+
+ /* Note that rate is received from parent. */
+ clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
+ U8500_CLKRST2_BASE, BIT(6),
+ CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+ clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
+ U8500_CLKRST2_BASE, BIT(7),
+ CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+
+ /* Periph3 */
+ clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
+ U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
+ U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE);
+ clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
+ U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
+ U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi2");
+
+ clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
+ U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
+ U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart2");
+
+ clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
+ U8500_CLKRST3_BASE, BIT(7), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi5");
+
+ /* Periph6 */
+ clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
+ U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
+
+}
diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c
new file mode 100644
index 000000000000..10adfd2ead21
--- /dev/null
+++ b/drivers/clk/ux500/u8540_clk.c
@@ -0,0 +1,21 @@
+/*
+ * Clock definitions for u8540 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u8540_clk_init(void)
+{
+ /* register clocks here */
+}
diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c
new file mode 100644
index 000000000000..dbc0191e16c8
--- /dev/null
+++ b/drivers/clk/ux500/u9540_clk.c
@@ -0,0 +1,21 @@
+/*
+ * Clock definitions for u9540 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_data/clk-ux500.h>
+
+#include "clk.h"
+
+void u9540_clk_init(void)
+{
+ /* register clocks here */
+}
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index 50cf6a2ee693..c0a0f6478798 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -1,3 +1,4 @@
# Makefile for Versatile-specific clocks
obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
+obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
new file mode 100644
index 000000000000..e21a99cef378
--- /dev/null
+++ b/drivers/clk/versatile/clk-realview.c
@@ -0,0 +1,114 @@
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#include "clk-icst.h"
+
+/*
+ * Implementation of the ARM RealView clock trees.
+ */
+
+static void __iomem *sys_lock;
+static void __iomem *sys_vcoreg;
+
+/**
+ * realview_oscvco_get() - get ICST OSC settings for the RealView
+ */
+static struct icst_vco realview_oscvco_get(void)
+{
+ u32 val;
+ struct icst_vco vco;
+
+ val = readl(sys_vcoreg);
+ vco.v = val & 0x1ff;
+ vco.r = (val >> 9) & 0x7f;
+ vco.s = (val >> 16) & 03;
+ return vco;
+}
+
+static void realview_oscvco_set(struct icst_vco vco)
+{
+ u32 val;
+
+ val = readl(sys_vcoreg) & ~0x7ffff;
+ val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+ /* This magic unlocks the CM VCO so it can be controlled */
+ writel(0xa05f, sys_lock);
+ writel(val, sys_vcoreg);
+ /* This locks the CM again */
+ writel(0, sys_lock);
+}
+
+static const struct icst_params realview_oscvco_params = {
+ .ref = 24000000,
+ .vco_max = ICST307_VCO_MAX,
+ .vco_min = ICST307_VCO_MIN,
+ .vd_min = 4 + 8,
+ .vd_max = 511 + 8,
+ .rd_min = 1 + 2,
+ .rd_max = 127 + 2,
+ .s2div = icst307_s2div,
+ .idx2s = icst307_idx2s,
+};
+
+static const struct clk_icst_desc __initdata realview_icst_desc = {
+ .params = &realview_oscvco_params,
+ .getvco = realview_oscvco_get,
+ .setvco = realview_oscvco_set,
+};
+
+/*
+ * realview_clk_init() - set up the RealView clock tree
+ */
+void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
+{
+ struct clk *clk;
+
+ sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
+ if (is_pb1176)
+ sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
+ else
+ sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
+
+
+ /* APB clock dummy */
+ clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
+ clk_register_clkdev(clk, "apb_pclk", NULL);
+
+ /* 24 MHz clock */
+ clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
+ 24000000);
+ clk_register_clkdev(clk, NULL, "dev:uart0");
+ clk_register_clkdev(clk, NULL, "dev:uart1");
+ clk_register_clkdev(clk, NULL, "dev:uart2");
+ clk_register_clkdev(clk, NULL, "fpga:kmi0");
+ clk_register_clkdev(clk, NULL, "fpga:kmi1");
+ clk_register_clkdev(clk, NULL, "fpga:mmc0");
+ clk_register_clkdev(clk, NULL, "dev:ssp0");
+ if (is_pb1176) {
+ /*
+ * UART3 is on the dev chip in PB1176
+ * UART4 only exists in PB1176
+ */
+ clk_register_clkdev(clk, NULL, "dev:uart3");
+ clk_register_clkdev(clk, NULL, "dev:uart4");
+ } else
+ clk_register_clkdev(clk, NULL, "fpga:uart3");
+
+
+ /* 1 MHz clock */
+ clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
+ 1000000);
+ clk_register_clkdev(clk, NULL, "sp804");
+
+ /* ICST VCO clock */
+ clk = icst_clk_register(NULL, &realview_icst_desc);
+ clk_register_clkdev(clk, NULL, "dev:clcd");
+ clk_register_clkdev(clk, NULL, "issp:clcd");
+}
diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c
index 002888185f17..d216cd3cc569 100644
--- a/drivers/crypto/caam/key_gen.c
+++ b/drivers/crypto/caam/key_gen.c
@@ -120,3 +120,4 @@ u32 gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len,
return ret;
}
+EXPORT_SYMBOL(gen_split_key);
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index ae0561826137..2e1662777661 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -18,6 +18,8 @@
#include <linux/spinlock.h>
#include "virt-dma.h"
+
+#include <plat/cpu.h>
#include <plat/dma.h>
struct omap_dmadev {
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 920a609b2c35..38f9e52f358b 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -669,13 +669,18 @@ static int __devinit max77693_muic_probe(struct platform_device *pdev)
}
info->dev = &pdev->dev;
info->max77693 = max77693;
- info->max77693->regmap_muic = regmap_init_i2c(info->max77693->muic,
- &max77693_muic_regmap_config);
- if (IS_ERR(info->max77693->regmap_muic)) {
- ret = PTR_ERR(info->max77693->regmap_muic);
- dev_err(max77693->dev,
- "failed to allocate register map: %d\n", ret);
- goto err_regmap;
+ if (info->max77693->regmap_muic)
+ dev_dbg(&pdev->dev, "allocate register map\n");
+ else {
+ info->max77693->regmap_muic = devm_regmap_init_i2c(
+ info->max77693->muic,
+ &max77693_muic_regmap_config);
+ if (IS_ERR(info->max77693->regmap_muic)) {
+ ret = PTR_ERR(info->max77693->regmap_muic);
+ dev_err(max77693->dev,
+ "failed to allocate register map: %d\n", ret);
+ goto err_regmap;
+ }
}
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index e6efd77668f0..64fbce30c502 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -25,11 +25,9 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/irqdomain.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-omap.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <mach/irqs.h>
-#include <asm/gpio.h>
#include <asm/mach/irq.h>
#define OFF_MODE 1
@@ -385,13 +383,16 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
static int gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned gpio;
+ unsigned gpio = 0;
int retval;
unsigned long flags;
- if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
+#ifdef CONFIG_ARCH_OMAP1
+ if (d->irq > IH_MPUIO_BASE)
gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
- else
+#endif
+
+ if (!gpio)
gpio = irq_to_gpio(bank, d->irq);
if (type & ~IRQ_TYPE_SENSE_MASK)
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 9cac88a65f78..9528779ca463 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -26,6 +26,8 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
+#include <asm/mach/irq.h>
+
#include <mach/irqs.h>
/*
@@ -59,6 +61,7 @@
#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
int pxa_last_gpio;
+static int irq_base;
#ifdef CONFIG_OF
static struct irq_domain *domain;
@@ -167,63 +170,14 @@ static inline int __gpio_is_occupied(unsigned gpio)
return ret;
}
-#ifdef CONFIG_ARCH_PXA
-static inline int __pxa_gpio_to_irq(int gpio)
-{
- if (gpio_is_pxa_type(gpio_type))
- return PXA_GPIO_TO_IRQ(gpio);
- return -1;
-}
-
-static inline int __pxa_irq_to_gpio(int irq)
-{
- if (gpio_is_pxa_type(gpio_type))
- return irq - PXA_GPIO_TO_IRQ(0);
- return -1;
-}
-#else
-static inline int __pxa_gpio_to_irq(int gpio) { return -1; }
-static inline int __pxa_irq_to_gpio(int irq) { return -1; }
-#endif
-
-#ifdef CONFIG_ARCH_MMP
-static inline int __mmp_gpio_to_irq(int gpio)
-{
- if (gpio_is_mmp_type(gpio_type))
- return MMP_GPIO_TO_IRQ(gpio);
- return -1;
-}
-
-static inline int __mmp_irq_to_gpio(int irq)
-{
- if (gpio_is_mmp_type(gpio_type))
- return irq - MMP_GPIO_TO_IRQ(0);
- return -1;
-}
-#else
-static inline int __mmp_gpio_to_irq(int gpio) { return -1; }
-static inline int __mmp_irq_to_gpio(int irq) { return -1; }
-#endif
-
static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- int gpio, ret;
-
- gpio = chip->base + offset;
- ret = __pxa_gpio_to_irq(gpio);
- if (ret >= 0)
- return ret;
- return __mmp_gpio_to_irq(gpio);
+ return chip->base + offset + irq_base;
}
int pxa_irq_to_gpio(int irq)
{
- int ret;
-
- ret = __pxa_irq_to_gpio(irq);
- if (ret >= 0)
- return ret;
- return __mmp_irq_to_gpio(irq);
+ return irq - irq_base;
}
static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -403,6 +357,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
struct pxa_gpio_chip *c;
int loop, gpio, gpio_base, n;
unsigned long gedr;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
do {
loop = 0;
@@ -422,6 +379,8 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
}
}
} while (loop);
+
+ chained_irq_exit(chip, desc);
}
static void pxa_ack_muxed_gpio(struct irq_data *d)
@@ -535,7 +494,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
{
- int ret, nr_banks, nr_gpios, irq_base;
+ int ret, nr_banks, nr_gpios;
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);
@@ -590,10 +549,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
ret = pxa_gpio_probe_dt(pdev);
- if (ret < 0)
+ if (ret < 0) {
pxa_last_gpio = pxa_gpio_nums();
- else
+#ifdef CONFIG_ARCH_PXA
+ if (gpio_is_pxa_type(gpio_type))
+ irq_base = PXA_GPIO_TO_IRQ(0);
+#endif
+#ifdef CONFIG_ARCH_MMP
+ if (gpio_is_mmp_type(gpio_type))
+ irq_base = MMP_GPIO_TO_IRQ(0);
+#endif
+ } else {
use_of = 1;
+ }
+
if (!pxa_last_gpio)
return -EINVAL;
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index ba126cc04073..f4814a889a5b 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -938,6 +938,67 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
s3c_gpiolib_track(chip);
}
+#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF)
+static int s3c24xx_gpio_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ unsigned int pin;
+
+ if (WARN_ON(gc->of_gpio_n_cells < 3))
+ return -EINVAL;
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ if (gpiospec->args[0] > gc->ngpio)
+ return -EINVAL;
+
+ pin = gc->base + gpiospec->args[0];
+
+ if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1])))
+ pr_warn("gpio_xlate: failed to set pin function\n");
+ if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff))
+ pr_warn("gpio_xlate: failed to set pin pull up/down\n");
+
+ if (flags)
+ *flags = gpiospec->args[2] >> 16;
+
+ return gpiospec->args[0];
+}
+
+static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = {
+ { .compatible = "samsung,s3c24xx-gpio", },
+ {}
+};
+
+static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+ u64 base, u64 offset)
+{
+ struct gpio_chip *gc = &chip->chip;
+ u64 address;
+
+ if (!of_have_populated_dt())
+ return;
+
+ address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
+ gc->of_node = of_find_matching_node_by_address(NULL,
+ s3c24xx_gpio_dt_match, address);
+ if (!gc->of_node) {
+ pr_info("gpio: device tree node not found for gpio controller"
+ " with base address %08llx\n", address);
+ return;
+ }
+ gc->of_gpio_n_cells = 3;
+ gc->of_xlate = s3c24xx_gpio_xlate;
+}
+#else
+static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
+ u64 base, u64 offset)
+{
+ return;
+}
+#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */
+
static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
int nr_chips, void __iomem *base)
{
@@ -962,6 +1023,8 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
gc->direction_output = samsung_gpiolib_2bit_output;
samsung_gpiolib_add(chip);
+
+ s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10);
}
}
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 94256fe7bf36..c5f8ca233e1f 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -51,6 +51,7 @@
static struct gpio_chip twl_gpiochip;
+static int twl4030_gpio_base;
static int twl4030_gpio_irq_base;
/* genirq interfaces are not available to modules */
@@ -395,6 +396,29 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
static int gpio_twl4030_remove(struct platform_device *pdev);
+static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
+{
+ struct twl4030_gpio_platform_data *omap_twl_info;
+
+ omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL);
+ if (!omap_twl_info)
+ return NULL;
+
+ omap_twl_info->use_leds = of_property_read_bool(dev->of_node,
+ "ti,use-leds");
+
+ of_property_read_u32(dev->of_node, "ti,debounce",
+ &omap_twl_info->debounce);
+ of_property_read_u32(dev->of_node, "ti,mmc-cd",
+ (u32 *)&omap_twl_info->mmc_cd);
+ of_property_read_u32(dev->of_node, "ti,pullups",
+ &omap_twl_info->pullups);
+ of_property_read_u32(dev->of_node, "ti,pulldowns",
+ &omap_twl_info->pulldowns);
+
+ return omap_twl_info;
+}
+
static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
{
struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
@@ -427,49 +451,57 @@ no_irqs:
twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
twl_gpiochip.dev = &pdev->dev;
- if (pdata) {
- twl_gpiochip.base = pdata->gpio_base;
+ if (node)
+ pdata = of_gpio_twl4030(&pdev->dev);
- /*
- * NOTE: boards may waste power if they don't set pullups
- * and pulldowns correctly ... default for non-ULPI pins is
- * pulldown, and some other pins may have external pullups
- * or pulldowns. Careful!
- */
- ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
- if (ret)
- dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
- pdata->pullups, pdata->pulldowns,
- ret);
-
- ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
- if (ret)
- dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
- pdata->debounce, pdata->mmc_cd,
- ret);
-
- /*
- * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
- * is (still) clear if use_leds is set.
- */
- if (pdata->use_leds)
- twl_gpiochip.ngpio += 2;
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Platform data is missing\n");
+ return -ENXIO;
}
+ /*
+ * NOTE: boards may waste power if they don't set pullups
+ * and pulldowns correctly ... default for non-ULPI pins is
+ * pulldown, and some other pins may have external pullups
+ * or pulldowns. Careful!
+ */
+ ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+ if (ret)
+ dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+ pdata->pullups, pdata->pulldowns, ret);
+
+ ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd);
+ if (ret)
+ dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n",
+ pdata->debounce, pdata->mmc_cd, ret);
+
+ /*
+ * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE,
+ * is (still) clear if use_leds is set.
+ */
+ if (pdata->use_leds)
+ twl_gpiochip.ngpio += 2;
+
ret = gpiochip_add(&twl_gpiochip);
if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
twl_gpiochip.ngpio = 0;
gpio_twl4030_remove(pdev);
- } else if (pdata && pdata->setup) {
+ goto out;
+ }
+
+ twl4030_gpio_base = twl_gpiochip.base;
+
+ if (pdata && pdata->setup) {
int status;
status = pdata->setup(&pdev->dev,
- pdata->gpio_base, TWL4030_GPIO_MAX);
+ twl4030_gpio_base, TWL4030_GPIO_MAX);
if (status)
dev_dbg(&pdev->dev, "setup --> %d\n", status);
}
+out:
return ret;
}
@@ -481,7 +513,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev,
- pdata->gpio_base, TWL4030_GPIO_MAX);
+ twl4030_gpio_base, TWL4030_GPIO_MAX);
if (status) {
dev_dbg(&pdev->dev, "teardown --> %d\n", status);
return status;
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index d0c4574ef49c..36164806b9d4 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -193,6 +193,9 @@ static const struct file_operations ast_fops = {
.mmap = ast_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.read = drm_read,
};
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 7282c081fb53..a712cafcfa1d 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -841,7 +841,7 @@ int ast_cursor_init(struct drm_device *dev)
ast->cursor_cache = obj;
ast->cursor_cache_gpu_addr = gpu_addr;
- DRM_ERROR("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr);
+ DRM_DEBUG_KMS("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr);
return 0;
fail:
return ret;
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index 7053140c6596..b83a2d7ddd1a 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -74,6 +74,9 @@ static const struct file_operations cirrus_driver_fops = {
.unlocked_ioctl = drm_ioctl,
.mmap = cirrus_mmap,
.poll = drm_poll,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.fasync = drm_fasync,
};
static struct drm_driver driver = {
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 7f5096763b7d..59a26e577b57 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -36,6 +36,6 @@ config DRM_EXYNOS_VIDI
config DRM_EXYNOS_G2D
bool "Exynos DRM G2D"
- depends on DRM_EXYNOS
+ depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_G2D
help
Choose this option if you want to use Exynos G2D for DRM.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 613bf8a5d9b2..ae13febe0eaa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -163,6 +163,12 @@ static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
/* TODO */
}
+static int exynos_gem_dmabuf_mmap(struct dma_buf *dma_buf,
+ struct vm_area_struct *vma)
+{
+ return -ENOTTY;
+}
+
static struct dma_buf_ops exynos_dmabuf_ops = {
.map_dma_buf = exynos_gem_map_dma_buf,
.unmap_dma_buf = exynos_gem_unmap_dma_buf,
@@ -170,6 +176,7 @@ static struct dma_buf_ops exynos_dmabuf_ops = {
.kmap_atomic = exynos_gem_dmabuf_kmap_atomic,
.kunmap = exynos_gem_dmabuf_kunmap,
.kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic,
+ .mmap = exynos_gem_dmabuf_mmap,
.release = exynos_dmabuf_release,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index ebacec6f1e48..d07071937453 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -160,7 +160,6 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
if (!file_priv)
return -ENOMEM;
- drm_prime_init_file_private(&file->prime);
file->driver_priv = file_priv;
return exynos_drm_subdrv_open(dev, file);
@@ -184,7 +183,6 @@ 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);
@@ -241,6 +239,9 @@ static const struct file_operations exynos_drm_driver_fops = {
.poll = drm_poll,
.read = drm_read,
.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.release = drm_release,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a68d2b313f03..b19cd93e7047 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -831,11 +831,6 @@ static int __devinit fimd_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "failed to find registers\n");
- ret = -ENOENT;
- goto err_clk;
- }
ctx->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!ctx->regs) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index d2d88f22a037..1065e90d0919 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -129,7 +129,6 @@ struct g2d_runqueue_node {
struct g2d_data {
struct device *dev;
struct clk *gate_clk;
- struct resource *regs_res;
void __iomem *regs;
int irq;
struct workqueue_struct *g2d_workq;
@@ -751,7 +750,7 @@ static int __devinit g2d_probe(struct platform_device *pdev)
struct exynos_drm_subdrv *subdrv;
int ret;
- g2d = kzalloc(sizeof(*g2d), GFP_KERNEL);
+ g2d = devm_kzalloc(&pdev->dev, sizeof(*g2d), GFP_KERNEL);
if (!g2d) {
dev_err(dev, "failed to allocate driver data\n");
return -ENOMEM;
@@ -759,10 +758,8 @@ static int __devinit g2d_probe(struct platform_device *pdev)
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;
- }
+ if (!g2d->runqueue_slab)
+ return -ENOMEM;
g2d->dev = dev;
@@ -794,38 +791,26 @@ static int __devinit g2d_probe(struct platform_device *pdev)
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));
+ g2d->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!g2d->regs) {
dev_err(dev, "failed to remap I/O memory\n");
ret = -ENXIO;
- goto err_release_res;
+ goto err_put_clk;
}
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;
+ goto err_put_clk;
}
- ret = request_irq(g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d);
+ ret = devm_request_irq(&pdev->dev, g2d->irq, g2d_irq_handler, 0,
+ "drm_g2d", g2d);
if (ret < 0) {
dev_err(dev, "irq request failed\n");
- goto err_unmap_base;
+ goto err_put_clk;
}
platform_set_drvdata(pdev, g2d);
@@ -838,7 +823,7 @@ static int __devinit g2d_probe(struct platform_device *pdev)
ret = exynos_drm_subdrv_register(subdrv);
if (ret < 0) {
dev_err(dev, "failed to register drm g2d device\n");
- goto err_free_irq;
+ goto err_put_clk;
}
dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n",
@@ -846,13 +831,6 @@ static int __devinit g2d_probe(struct platform_device *pdev)
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);
@@ -862,8 +840,6 @@ err_destroy_workqueue:
destroy_workqueue(g2d->g2d_workq);
err_destroy_slab:
kmem_cache_destroy(g2d->runqueue_slab);
-err_free_mem:
- kfree(g2d);
return ret;
}
@@ -873,24 +849,18 @@ static int __devexit g2d_remove(struct platform_device *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;
}
@@ -924,7 +894,7 @@ static int g2d_resume(struct device *dev)
}
#endif
-SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
+static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
struct platform_driver g2d_driver = {
.probe = g2d_probe,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index f9efde40c097..a38051c95ec4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -122,7 +122,7 @@ fail:
__free_page(pages[i]);
drm_free_large(pages);
- return ERR_PTR(PTR_ERR(p));
+ return ERR_CAST(p);
}
static void exynos_gem_put_pages(struct drm_gem_object *obj,
@@ -662,7 +662,7 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
*/
args->pitch = args->width * ((args->bpp + 7) / 8);
- args->size = PAGE_ALIGN(args->pitch * args->height);
+ args->size = args->pitch * args->height;
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
if (IS_ERR(exynos_gem_obj))
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 8ffcdf8b9e22..3fdf0b65f47e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -345,7 +345,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
DRM_LOG_KMS("failed to alloc common hdmi context.\n");
return -ENOMEM;
@@ -371,7 +371,6 @@ static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
exynos_drm_subdrv_unregister(&ctx->subdrv);
- kfree(ctx);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index b89829e5043a..e1f94b746bd7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -29,7 +29,6 @@ static const uint32_t formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_NV12,
- DRM_FORMAT_NV12M,
DRM_FORMAT_NV12MT,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index bb1550c4dd57..537027a74fd5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -633,7 +633,7 @@ static int __devinit vidi_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -673,8 +673,6 @@ static int __devexit vidi_remove(struct platform_device *pdev)
ctx->raw_edid = NULL;
}
- kfree(ctx);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 409e2ec1207c..a6aea6f3ea1a 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2172,7 +2172,7 @@ static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
DRM_DEBUG_KMS("HDMI resource init\n");
- memset(res, 0, sizeof *res);
+ memset(res, 0, sizeof(*res));
/* get clocks, power */
res->hdmi = clk_get(dev, "hdmi");
@@ -2204,7 +2204,7 @@ static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
- sizeof res->regul_bulk[0], GFP_KERNEL);
+ sizeof(res->regul_bulk[0]), GFP_KERNEL);
if (!res->regul_bulk) {
DRM_ERROR("failed to get memory for regulators\n");
goto fail;
@@ -2243,7 +2243,7 @@ static int hdmi_resources_cleanup(struct hdmi_context *hdata)
clk_put(res->sclk_hdmi);
if (!IS_ERR_OR_NULL(res->hdmi))
clk_put(res->hdmi);
- memset(res, 0, sizeof *res);
+ memset(res, 0, sizeof(*res));
return 0;
}
@@ -2312,11 +2312,6 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DRM_ERROR("failed to find registers\n");
- ret = -ENOENT;
- goto err_resource;
- }
hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
if (!hdata->regs) {
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 30fcc12f81dd..25b97d5e5fcb 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -236,11 +236,11 @@ static inline void vp_filter_set(struct mixer_resources *res,
static void vp_default_filter(struct mixer_resources *res)
{
vp_filter_set(res, VP_POLY8_Y0_LL,
- filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+ filter_y_horiz_tap8, sizeof(filter_y_horiz_tap8));
vp_filter_set(res, VP_POLY4_Y0_LL,
- filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+ filter_y_vert_tap4, sizeof(filter_y_vert_tap4));
vp_filter_set(res, VP_POLY4_C0_LL,
- filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+ filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4));
}
static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 0f9b7db80f6b..cf49ba5a54bf 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -476,6 +476,7 @@ static const struct psb_offset oaktrail_regmap[2] = {
.pos = DSPAPOS,
.surf = DSPASURF,
.addr = MRST_DSPABASE,
+ .base = MRST_DSPABASE,
.status = PIPEASTAT,
.linoff = DSPALINOFF,
.tileoff = DSPATILEOFF,
@@ -499,6 +500,7 @@ static const struct psb_offset oaktrail_regmap[2] = {
.pos = DSPBPOS,
.surf = DSPBSURF,
.addr = DSPBBASE,
+ .base = DSPBBASE,
.status = PIPEBSTAT,
.linoff = DSPBLINOFF,
.tileoff = DSPBTILEOFF,
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 57d892eaaa6e..463ec6871fe9 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -115,6 +115,9 @@ static const struct file_operations i810_buffer_fops = {
.unlocked_ioctl = drm_ioctl,
.mmap = i810_mmap_buffers,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c
index f9924ad04d09..48cfcca2b350 100644
--- a/drivers/gpu/drm/i810/i810_drv.c
+++ b/drivers/gpu/drm/i810/i810_drv.c
@@ -51,6 +51,9 @@ static const struct file_operations i810_driver_fops = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9cf7dfe022b9..914c0dfabe60 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1587,6 +1587,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock);
spin_lock_init(&dev_priv->rps_lock);
+ spin_lock_init(&dev_priv->dpio_lock);
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
dev_priv->num_pipe = 3;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8a3828528b9d..5249640cce13 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2700,9 +2700,6 @@ void intel_irq_init(struct drm_device *dev)
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;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2dfa6cf4886b..bc2ad348e5d8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1376,7 +1376,8 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
- WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_PIPE_B_SELECT),
+ WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
+ && (val & DP_PIPEB_SELECT),
"IBX PCH dp port still using transcoder B\n");
}
@@ -1388,7 +1389,8 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
- WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_PIPE_B_SELECT),
+ WARN(HAS_PCH_IBX(dev_priv->dev) && (val & PORT_ENABLE) == 0
+ && (val & SDVO_PIPE_B_SELECT),
"IBX PCH hdmi port still using transcoder B\n");
}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index a6c426afaa7a..ace757af9133 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2533,14 +2533,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
break;
}
- intel_dp_i2c_init(intel_dp, intel_connector, name);
-
/* Cache some DPCD data in the eDP case */
if (is_edp(intel_dp)) {
- bool ret;
struct edp_power_seq cur, vbt;
u32 pp_on, pp_off, pp_div;
- struct edid *edid;
pp_on = I915_READ(PCH_PP_ON_DELAYS);
pp_off = I915_READ(PCH_PP_OFF_DELAYS);
@@ -2591,6 +2587,13 @@ intel_dp_init(struct drm_device *dev, int output_reg)
DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
+ }
+
+ intel_dp_i2c_init(intel_dp, intel_connector, name);
+
+ if (is_edp(intel_dp)) {
+ bool ret;
+ struct edid *edid;
ironlake_edp_panel_vdd_on(intel_dp);
ret = intel_dp_get_dpcd(intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 3df4f5fa892a..e019b2369861 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -162,19 +162,12 @@ static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
return val;
}
-u32 intel_panel_get_max_backlight(struct drm_device *dev)
+static u32 _intel_panel_get_max_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 max;
max = i915_read_blc_pwm_ctl(dev_priv);
- if (max == 0) {
- /* XXX add code here to query mode clock or hardware clock
- * and program max PWM appropriately.
- */
- pr_warn_once("fixme: max PWM is zero\n");
- return 1;
- }
if (HAS_PCH_SPLIT(dev)) {
max >>= 16;
@@ -188,6 +181,22 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
max *= 0xff;
}
+ return max;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+ u32 max;
+
+ max = _intel_panel_get_max_backlight(dev);
+ if (max == 0) {
+ /* XXX add code here to query mode clock or hardware clock
+ * and program max PWM appropriately.
+ */
+ pr_warn_once("fixme: max PWM is zero\n");
+ return 1;
+ }
+
DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
return max;
}
@@ -424,7 +433,11 @@ int intel_panel_setup_backlight(struct drm_device *dev)
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
- props.max_brightness = intel_panel_get_max_backlight(dev);
+ props.max_brightness = _intel_panel_get_max_backlight(dev);
+ if (props.max_brightness == 0) {
+ DRM_ERROR("Failed to get maximum backlight value\n");
+ return -ENODEV;
+ }
dev_priv->backlight =
backlight_device_register("intel_backlight",
&connector->kdev, dev,
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1881c8c83f0e..ba8a27b1757a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3672,6 +3672,9 @@ static void gen3_init_clock_gating(struct drm_device *dev)
if (IS_PINEVIEW(dev))
I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY));
+
+ /* IIR "flip pending" means done if this bit is set */
+ I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE));
}
static void i85x_init_clock_gating(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d81bb0bf2885..123afd357611 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2573,7 +2573,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
hotplug_mask = intel_sdvo->is_sdvob ?
SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
}
- dev_priv->hotplug_supported_mask |= hotplug_mask;
drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
@@ -2581,14 +2580,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
goto err;
- /* Set up hotplug command - note paranoia about contents of reply.
- * We assume that the hardware is in a sane state, and only touch
- * the bits we think we understand.
- */
- intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG,
- &intel_sdvo->hotplug_active, 2);
- intel_sdvo->hotplug_active[0] &= ~0x3;
-
if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
@@ -2596,6 +2587,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
goto err;
}
+ /* Only enable the hotplug irq if we need it, to work around noisy
+ * hotplug lines.
+ */
+ if (intel_sdvo->hotplug_active[0])
+ dev_priv->hotplug_supported_mask |= hotplug_mask;
+
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
/* Set the input timing to the screen. Assume always input 0. */
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index ea1024d79974..e5f145d2cb3b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -84,6 +84,9 @@ static const struct file_operations mgag200_driver_fops = {
.mmap = mgag200_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.read = drm_read,
};
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 69688ef5cf46..7e16dc5e6467 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -598,7 +598,7 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
args->size = args->pitch * args->height;
args->size = roundup(args->size, PAGE_SIZE);
- ret = nouveau_gem_new(dev, args->size, 0, TTM_PL_FLAG_VRAM, 0, 0, &bo);
+ ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
index f429e6a8ca7a..f03490534893 100644
--- a/drivers/gpu/drm/nouveau/nv50_gpio.c
+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c
@@ -115,6 +115,9 @@ nv50_gpio_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ /* initialise gpios and routing to vbios defaults */
+ nouveau_gpio_reset(dev);
+
/* disable, and ack any pending gpio interrupts */
nv_wr32(dev, 0xe050, 0x00000000);
nv_wr32(dev, 0xe054, 0xffffffff);
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index dac525b2994e..8a2fc89b7763 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -1510,10 +1510,10 @@ nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
case OUTPUT_DP:
if (nv_connector->base.display_info.bpc == 6) {
nv_encoder->dp.datarate = mode->clock * 18 / 8;
- syncs |= 0x00000140;
+ syncs |= 0x00000002 << 6;
} else {
nv_encoder->dp.datarate = mode->clock * 24 / 8;
- syncs |= 0x00000180;
+ syncs |= 0x00000005 << 6;
}
if (nv_encoder->dcb->sorconf.link & 1)
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 2817101fb167..e721e3087b99 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1479,14 +1479,98 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
}
}
+/**
+ * radeon_get_pll_use_mask - look up a mask of which pplls are in use
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the mask of which PPLLs (Pixel PLLs) are in use.
+ */
+static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_crtc *test_crtc;
+ struct radeon_crtc *radeon_test_crtc;
+ u32 pll_in_use = 0;
+
+ list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc == test_crtc)
+ continue;
+
+ radeon_test_crtc = to_radeon_crtc(test_crtc);
+ if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
+ pll_in_use |= (1 << radeon_test_crtc->pll_id);
+ }
+ return pll_in_use;
+}
+
+/**
+ * radeon_get_shared_dp_ppll - return the PPLL used by another crtc for DP
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the PPLL (Pixel PLL) used by another crtc/encoder which is
+ * also in DP mode. For DP, a single PPLL can be used for all DP
+ * crtcs/encoders.
+ */
+static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *test_encoder;
+ struct radeon_crtc *radeon_test_crtc;
+
+ list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+ if (test_encoder->crtc && (test_encoder->crtc != crtc)) {
+ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
+ /* for DP use the same PLL for all */
+ radeon_test_crtc = to_radeon_crtc(test_encoder->crtc);
+ if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
+ return radeon_test_crtc->pll_id;
+ }
+ }
+ }
+ return ATOM_PPLL_INVALID;
+}
+
+/**
+ * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc.
+ *
+ * @crtc: drm crtc
+ *
+ * Returns the PPLL (Pixel PLL) to be used by the crtc. For DP monitors
+ * a single PPLL can be used for all DP crtcs/encoders. For non-DP
+ * monitors a dedicated PPLL must be used. If a particular board has
+ * an external DP PLL, return ATOM_PPLL_INVALID to skip PLL programming
+ * as there is no need to program the PLL itself. If we are not able to
+ * allocate a PLL, return ATOM_PPLL_INVALID to skip PLL programming to
+ * avoid messing up an existing monitor.
+ *
+ * Asic specific PLL information
+ *
+ * DCE 6.1
+ * - PPLL2 is only available to UNIPHYA (both DP and non-DP)
+ * - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
+ *
+ * DCE 6.0
+ * - PPLL0 is available to all UNIPHY (DP only)
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
+ * DCE 5.0
+ * - DCPLL is available to all UNIPHY (DP only)
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
+ * DCE 3.0/4.0/4.1
+ * - PPLL1, PPLL2 are available for all UNIPHY (both DP and non-DP) and DAC
+ *
+ */
static int radeon_atom_pick_pll(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *test_encoder;
- struct drm_crtc *test_crtc;
- uint32_t pll_in_use = 0;
+ u32 pll_in_use;
+ int pll;
if (ASIC_IS_DCE61(rdev)) {
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
@@ -1498,32 +1582,40 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
if ((test_radeon_encoder->encoder_id ==
ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
- (dig->linkb == false)) /* UNIPHY A uses PPLL2 */
+ (dig->linkb == false))
+ /* UNIPHY A uses PPLL2 */
return ATOM_PPLL2;
+ else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
+ /* UNIPHY B/C/D/E/F */
+ if (rdev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
+ return ATOM_PPLL_INVALID;
+ else {
+ /* use the same PPLL for all DP monitors */
+ pll = radeon_get_shared_dp_ppll(crtc);
+ if (pll != ATOM_PPLL_INVALID)
+ return pll;
+ }
+ }
+ break;
}
}
/* UNIPHY B/C/D/E/F */
- list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
- struct radeon_crtc *radeon_test_crtc;
-
- if (crtc == test_crtc)
- continue;
-
- radeon_test_crtc = to_radeon_crtc(test_crtc);
- if ((radeon_test_crtc->pll_id == ATOM_PPLL0) ||
- (radeon_test_crtc->pll_id == ATOM_PPLL1))
- pll_in_use |= (1 << radeon_test_crtc->pll_id);
- }
- if (!(pll_in_use & 4))
+ pll_in_use = radeon_get_pll_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL0)))
return ATOM_PPLL0;
- return ATOM_PPLL1;
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
+ return ATOM_PPLL1;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
} else if (ASIC_IS_DCE4(rdev)) {
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
/* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
* depending on the asic:
* DCE4: PPLL or ext clock
- * DCE5: DCPLL or ext clock
+ * DCE5: PPLL, DCPLL, or ext clock
+ * DCE6: PPLL, PPLL0, or ext clock
*
* Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
* PPLL/DCPLL programming and only program the DP DTO for the
@@ -1531,31 +1623,34 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
*/
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
if (rdev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
return ATOM_PPLL_INVALID;
else if (ASIC_IS_DCE6(rdev))
+ /* use PPLL0 for all DP */
return ATOM_PPLL0;
else if (ASIC_IS_DCE5(rdev))
+ /* use DCPLL for all DP */
return ATOM_DCPLL;
+ else {
+ /* use the same PPLL for all DP monitors */
+ pll = radeon_get_shared_dp_ppll(crtc);
+ if (pll != ATOM_PPLL_INVALID)
+ return pll;
+ }
}
+ break;
}
}
-
- /* otherwise, pick one of the plls */
- list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
- struct radeon_crtc *radeon_test_crtc;
-
- if (crtc == test_crtc)
- continue;
-
- radeon_test_crtc = to_radeon_crtc(test_crtc);
- if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
- (radeon_test_crtc->pll_id <= ATOM_PPLL2))
- pll_in_use |= (1 << radeon_test_crtc->pll_id);
- }
- if (!(pll_in_use & 1))
+ /* all other cases */
+ pll_in_use = radeon_get_pll_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL2)))
+ return ATOM_PPLL2;
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
return ATOM_PPLL1;
- return ATOM_PPLL2;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
} else
+ /* use PPLL1 or PPLL2 */
return radeon_crtc->crtc_id;
}
@@ -1697,7 +1792,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
break;
}
done:
- radeon_crtc->pll_id = -1;
+ radeon_crtc->pll_id = ATOM_PPLL_INVALID;
}
static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@@ -1746,6 +1841,6 @@ void radeon_atombios_init_crtc(struct drm_device *dev,
else
radeon_crtc->crtc_offset = 0;
}
- radeon_crtc->pll_id = -1;
+ radeon_crtc->pll_id = ATOM_PPLL_INVALID;
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
}
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 7b737b9339ad..2a59375dbe52 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -131,7 +131,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
*/
void radeon_fence_process(struct radeon_device *rdev, int ring)
{
- uint64_t seq, last_seq;
+ uint64_t seq, last_seq, last_emitted;
unsigned count_loop = 0;
bool wake = false;
@@ -158,13 +158,15 @@ void radeon_fence_process(struct radeon_device *rdev, int ring)
*/
last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq);
do {
+ last_emitted = rdev->fence_drv[ring].sync_seq[ring];
seq = radeon_fence_read(rdev, ring);
seq |= last_seq & 0xffffffff00000000LL;
if (seq < last_seq) {
- seq += 0x100000000LL;
+ seq &= 0xffffffff;
+ seq |= last_emitted & 0xffffffff00000000LL;
}
- if (seq == last_seq) {
+ if (seq <= last_seq || seq > last_emitted) {
break;
}
/* If we loop over we don't want to return without
diff --git a/drivers/gpu/drm/savage/savage_drv.c b/drivers/gpu/drm/savage/savage_drv.c
index d31d4cca9a4c..c5a164337bd5 100644
--- a/drivers/gpu/drm/savage/savage_drv.c
+++ b/drivers/gpu/drm/savage/savage_drv.c
@@ -43,6 +43,9 @@ static const struct file_operations savage_driver_fops = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c
index 7f119870147c..867dc03000e6 100644
--- a/drivers/gpu/drm/sis/sis_drv.c
+++ b/drivers/gpu/drm/sis/sis_drv.c
@@ -74,6 +74,9 @@ static const struct file_operations sis_driver_fops = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/tdfx/tdfx_drv.c b/drivers/gpu/drm/tdfx/tdfx_drv.c
index 90f6b13acfac..a7f4d6bd1330 100644
--- a/drivers/gpu/drm/tdfx/tdfx_drv.c
+++ b/drivers/gpu/drm/tdfx/tdfx_drv.c
@@ -49,6 +49,9 @@ static const struct file_operations tdfx_driver_fops = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 6e52069894b3..9f84128505bb 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -66,6 +66,9 @@ static const struct file_operations udl_driver_fops = {
.unlocked_ioctl = drm_ioctl,
.release = drm_release,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/via/via_drv.c b/drivers/gpu/drm/via/via_drv.c
index e927b4c052f5..af1b914b17e3 100644
--- a/drivers/gpu/drm/via/via_drv.c
+++ b/drivers/gpu/drm/via/via_drv.c
@@ -65,6 +65,9 @@ static const struct file_operations via_driver_fops = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.llseek = noop_llseek,
};
diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig
index 794ff67c5701..b71bcd0bfbbf 100644
--- a/drivers/gpu/drm/vmwgfx/Kconfig
+++ b/drivers/gpu/drm/vmwgfx/Kconfig
@@ -12,3 +12,11 @@ config DRM_VMWGFX
This is a KMS enabled DRM driver for the VMware SVGA2
virtual hardware.
The compiled module will be called "vmwgfx.ko".
+
+config DRM_VMWGFX_FBCON
+ depends on DRM_VMWGFX
+ bool "Enable framebuffer console under vmwgfx by default"
+ help
+ Choose this option if you are shipping a new vmwgfx
+ userspace driver that supports using the kernel driver.
+
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 4d9edead01ac..ba2c35dbf10e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -182,8 +182,9 @@ static struct pci_device_id vmw_pci_id_list[] = {
{0x15ad, 0x0405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VMWGFX_CHIP_SVGAII},
{0, 0, 0}
};
+MODULE_DEVICE_TABLE(pci, vmw_pci_id_list);
-static int enable_fbdev;
+static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON);
static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static void vmw_master_init(struct vmw_master *);
@@ -1154,6 +1155,11 @@ static struct drm_driver driver = {
.open = vmw_driver_open,
.preclose = vmw_preclose,
.postclose = vmw_postclose,
+
+ .dumb_create = vmw_dumb_create,
+ .dumb_map_offset = vmw_dumb_map_offset,
+ .dumb_destroy = vmw_dumb_destroy,
+
.fops = &vmwgfx_driver_fops,
.name = VMWGFX_DRIVER_NAME,
.desc = VMWGFX_DRIVER_DESC,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index d0f2c079ee27..29c984ff7f23 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -645,6 +645,16 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+int vmw_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+
+int vmw_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle,
+ uint64_t *offset);
+int vmw_dumb_destroy(struct drm_file *file_priv,
+ struct drm_device *dev,
+ uint32_t handle);
/**
* Overlay control - vmwgfx_overlay.c
*/
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index 22bf9a21ec71..2c6ffe0e2c07 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -1917,3 +1917,76 @@ err_ref:
vmw_resource_unreference(&res);
return ret;
}
+
+
+int vmw_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ struct vmw_user_dma_buffer *vmw_user_bo;
+ struct ttm_buffer_object *tmp;
+ int ret;
+
+ args->pitch = args->width * ((args->bpp + 7) / 8);
+ args->size = args->pitch * args->height;
+
+ vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
+ if (vmw_user_bo == NULL)
+ return -ENOMEM;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (ret != 0) {
+ kfree(vmw_user_bo);
+ return ret;
+ }
+
+ ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, args->size,
+ &vmw_vram_sys_placement, true,
+ &vmw_user_dmabuf_destroy);
+ if (ret != 0)
+ goto out_no_dmabuf;
+
+ tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
+ ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
+ &vmw_user_bo->base,
+ false,
+ ttm_buffer_type,
+ &vmw_user_dmabuf_release, NULL);
+ if (unlikely(ret != 0))
+ goto out_no_base_object;
+
+ args->handle = vmw_user_bo->base.hash.key;
+
+out_no_base_object:
+ ttm_bo_unref(&tmp);
+out_no_dmabuf:
+ ttm_read_unlock(&vmaster->lock);
+ return ret;
+}
+
+int vmw_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle,
+ uint64_t *offset)
+{
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+ struct vmw_dma_buffer *out_buf;
+ int ret;
+
+ ret = vmw_user_dmabuf_lookup(tfile, handle, &out_buf);
+ if (ret != 0)
+ return -EINVAL;
+
+ *offset = out_buf->base.addr_space_offset;
+ vmw_dmabuf_unreference(&out_buf);
+ return 0;
+}
+
+int vmw_dumb_destroy(struct drm_file *file_priv,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+ handle, TTM_REF_USAGE);
+}
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 7f3f4a385729..602148299f68 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -69,22 +69,6 @@ struct ina2xx_data {
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);
@@ -102,7 +86,7 @@ static struct ina2xx_data *ina2xx_update_device(struct device *dev)
/* Read all registers */
for (i = 0; i < data->registers; i++) {
- int rv = ina2xx_read_word(client, i);
+ int rv = i2c_smbus_read_word_swapped(client, i);
if (rv < 0) {
ret = ERR_PTR(rv);
goto abort;
@@ -279,22 +263,26 @@ static int ina2xx_probe(struct i2c_client *client,
switch (data->kind) {
case ina219:
/* device configuration */
- ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+ i2c_smbus_write_word_swapped(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);
+ i2c_smbus_write_word_swapped(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);
+ i2c_smbus_write_word_swapped(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);
+ i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+ 5120000 / shunt);
dev_info(&client->dev,
"power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
data->registers = INA226_REGISTERS;
diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c
index 0018c7dd0097..1a174f0a3cde 100644
--- a/drivers/hwmon/twl4030-madc-hwmon.c
+++ b/drivers/hwmon/twl4030-madc-hwmon.c
@@ -44,12 +44,13 @@ static ssize_t madc_read(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct twl4030_madc_request req;
+ struct twl4030_madc_request req = {
+ .channels = 1 << attr->index,
+ .method = TWL4030_MADC_SW2,
+ .type = TWL4030_MADC_WAIT,
+ };
long val;
- req.channels = (1 << attr->index);
- req.method = TWL4030_MADC_SW2;
- req.func_cb = NULL;
val = twl4030_madc_conversion(&req);
if (val < 0)
return val;
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 73133b1063f0..6f5f98d69af7 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -476,17 +476,17 @@ static int pca_init(struct i2c_adapter *adap)
/* To avoid integer overflow, use clock/100 for calculations */
clock = pca_clock(pca_data) / 100;
- if (pca_data->i2c_clock > 10000) {
+ if (pca_data->i2c_clock > 1000000) {
mode = I2C_PCA_MODE_TURBO;
min_tlow = 14;
min_thi = 5;
raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
- } else if (pca_data->i2c_clock > 4000) {
+ } else if (pca_data->i2c_clock > 400000) {
mode = I2C_PCA_MODE_FASTP;
min_tlow = 17;
min_thi = 9;
raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
- } else if (pca_data->i2c_clock > 1000) {
+ } else if (pca_data->i2c_clock > 100000) {
mode = I2C_PCA_MODE_FAST;
min_tlow = 44;
min_thi = 20;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index b4aaa1bd6728..970a1612e795 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -104,6 +104,7 @@ config I2C_I801
DH89xxCC (PCH)
Panther Point (PCH)
Lynx Point (PCH)
+ Lynx Point-LP (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -354,9 +355,13 @@ config I2C_DAVINCI
devices such as DaVinci NIC.
For details please see http://www.ti.com/davinci
+config I2C_DESIGNWARE_CORE
+ tristate
+
config I2C_DESIGNWARE_PLATFORM
tristate "Synopsys DesignWare Platform"
depends on HAVE_CLK
+ select I2C_DESIGNWARE_CORE
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
@@ -367,6 +372,7 @@ config I2C_DESIGNWARE_PLATFORM
config I2C_DESIGNWARE_PCI
tristate "Synopsys DesignWare PCI"
depends on PCI
+ select I2C_DESIGNWARE_CORE
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ce3c2be7fb40..37c4182cc98b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,10 +33,11 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
-i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o
+i2c-designware-platform-objs := i2c-designware-platdrv.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
-i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o
+i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 1e48bec80edf..7b8ebbefb581 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -25,6 +25,7 @@
* ----------------------------------------------------------------------------
*
*/
+#include <linux/export.h>
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/err.h>
@@ -316,6 +317,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, dev->master_cfg , DW_IC_CON);
return 0;
}
+EXPORT_SYMBOL_GPL(i2c_dw_init);
/*
* Waiting for bus not busy
@@ -568,12 +570,14 @@ done:
return ret;
}
+EXPORT_SYMBOL_GPL(i2c_dw_xfer);
u32 i2c_dw_func(struct i2c_adapter *adap)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
return dev->functionality;
}
+EXPORT_SYMBOL_GPL(i2c_dw_func);
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
@@ -678,17 +682,20 @@ tx_aborted:
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(i2c_dw_isr);
void i2c_dw_enable(struct dw_i2c_dev *dev)
{
/* Enable the adapter */
dw_writel(dev, 1, DW_IC_ENABLE);
}
+EXPORT_SYMBOL_GPL(i2c_dw_enable);
u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
{
return dw_readl(dev, DW_IC_ENABLE);
}
+EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
@@ -699,18 +706,22 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
dw_writel(dev, 0, DW_IC_INTR_MASK);
dw_readl(dev, DW_IC_CLR_INTR);
}
+EXPORT_SYMBOL_GPL(i2c_dw_disable);
void i2c_dw_clear_int(struct dw_i2c_dev *dev)
{
dw_readl(dev, DW_IC_CLR_INTR);
}
+EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
void i2c_dw_disable_int(struct dw_i2c_dev *dev)
{
dw_writel(dev, 0, DW_IC_INTR_MASK);
}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_int);
u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
{
return dw_readl(dev, DW_IC_COMP_PARAM_1);
}
+EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 898dcf9c7ade..33e9b0c09af2 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -52,6 +52,7 @@
DH89xxCC (PCH) 0x2330 32 hard yes yes yes
Panther Point (PCH) 0x1e22 32 hard yes yes yes
Lynx Point (PCH) 0x8c22 32 hard yes yes yes
+ Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -155,6 +156,7 @@
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
struct i801_priv {
struct i2c_adapter adapter;
@@ -771,6 +773,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 088c5c1ed17d..51f05b8520ed 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -365,10 +365,6 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
struct device_node *node = dev->of_node;
int ret;
- if (!node)
- return -EINVAL;
-
- i2c->speed = &mxs_i2c_95kHz_config;
ret = of_property_read_u32(node, "clock-frequency", &speed);
if (ret)
dev_warn(dev, "No I2C speed selected, using 100kHz\n");
@@ -419,10 +415,13 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
return err;
i2c->dev = dev;
+ i2c->speed = &mxs_i2c_95kHz_config;
- err = mxs_i2c_get_ofdata(i2c);
- if (err)
- return err;
+ if (dev->of_node) {
+ err = mxs_i2c_get_ofdata(i2c);
+ if (err)
+ return err;
+ }
platform_set_drvdata(pdev, i2c);
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 5d54416770b0..8488bddfe465 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -48,8 +48,9 @@ enum {
mcntrl_afie = 0x00000002,
mcntrl_naie = 0x00000004,
mcntrl_drmie = 0x00000008,
- mcntrl_daie = 0x00000020,
- mcntrl_rffie = 0x00000040,
+ mcntrl_drsie = 0x00000010,
+ mcntrl_rffie = 0x00000020,
+ mcntrl_daie = 0x00000040,
mcntrl_tffie = 0x00000080,
mcntrl_reset = 0x00000100,
mcntrl_cdbmode = 0x00000400,
@@ -290,31 +291,37 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
* or we didn't 'ask' for it yet.
*/
if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
- dev_dbg(&alg_data->adapter.dev,
- "%s(): Write dummy data to fill Rx-fifo...\n",
- __func__);
+ /* 'Asking' is done asynchronously, e.g. dummy TX of several
+ * bytes is done before the first actual RX arrives in FIFO.
+ * Therefore, ordered bytes (via TX) are counted separately.
+ */
+ if (alg_data->mif.order) {
+ dev_dbg(&alg_data->adapter.dev,
+ "%s(): Write dummy data to fill Rx-fifo...\n",
+ __func__);
- if (alg_data->mif.len == 1) {
- /* Last byte, do not acknowledge next rcv. */
- val |= stop_bit;
+ if (alg_data->mif.order == 1) {
+ /* Last byte, do not acknowledge next rcv. */
+ val |= stop_bit;
+
+ /*
+ * Enable interrupt RFDAIE (data in Rx fifo),
+ * and disable DRMIE (need data for Tx)
+ */
+ ctl = ioread32(I2C_REG_CTL(alg_data));
+ ctl |= mcntrl_rffie | mcntrl_daie;
+ ctl &= ~mcntrl_drmie;
+ iowrite32(ctl, I2C_REG_CTL(alg_data));
+ }
/*
- * Enable interrupt RFDAIE (data in Rx fifo),
- * and disable DRMIE (need data for Tx)
+ * Now we'll 'ask' for data:
+ * For each byte we want to receive, we must
+ * write a (dummy) byte to the Tx-FIFO.
*/
- ctl = ioread32(I2C_REG_CTL(alg_data));
- ctl |= mcntrl_rffie | mcntrl_daie;
- ctl &= ~mcntrl_drmie;
- iowrite32(ctl, I2C_REG_CTL(alg_data));
+ iowrite32(val, I2C_REG_TX(alg_data));
+ alg_data->mif.order--;
}
-
- /*
- * Now we'll 'ask' for data:
- * For each byte we want to receive, we must
- * write a (dummy) byte to the Tx-FIFO.
- */
- iowrite32(val, I2C_REG_TX(alg_data));
-
return 0;
}
@@ -514,6 +521,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
alg_data->mif.buf = pmsg->buf;
alg_data->mif.len = pmsg->len;
+ alg_data->mif.order = pmsg->len;
alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
I2C_SMBUS_READ : I2C_SMBUS_WRITE;
alg_data->mif.ret = 0;
@@ -566,6 +574,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/* Cleanup to be sure... */
alg_data->mif.buf = NULL;
alg_data->mif.len = 0;
+ alg_data->mif.order = 0;
dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
__func__, ioread32(I2C_REG_STS(alg_data)));
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 2efa56c5ff2c..2091ae8f539a 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -637,6 +637,22 @@ static void i2c_adapter_dev_release(struct device *dev)
}
/*
+ * This function is only needed for mutex_lock_nested, so it is never
+ * called unless locking correctness checking is enabled. Thus we
+ * make it inline to avoid a compiler warning. That's what gcc ends up
+ * doing anyway.
+ */
+static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
+{
+ unsigned int depth = 0;
+
+ while ((adapter = i2c_parent_is_i2c_adapter(adapter)))
+ depth++;
+
+ return depth;
+}
+
+/*
* Let users instantiate I2C devices through sysfs. This can be used when
* platform initialization code doesn't contain the proper data for
* whatever reason. Also useful for drivers that do device detection and
@@ -726,7 +742,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
/* Make sure the device was added through sysfs */
res = -ENOENT;
- mutex_lock(&adap->userspace_clients_lock);
+ mutex_lock_nested(&adap->userspace_clients_lock,
+ i2c_adapter_depth(adap));
list_for_each_entry_safe(client, next, &adap->userspace_clients,
detected) {
if (client->addr == addr) {
@@ -1073,7 +1090,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
return res;
/* Remove devices instantiated from sysfs */
- mutex_lock(&adap->userspace_clients_lock);
+ mutex_lock_nested(&adap->userspace_clients_lock,
+ i2c_adapter_depth(adap));
list_for_each_entry_safe(client, next, &adap->userspace_clients,
detected) {
dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f61780a02374..3bd5540238a7 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -617,7 +617,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
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);
+ ret = PTR_ERR(st->adc_clk);
goto error_disable_clk;
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c50fa75416f8..b4b65af8612a 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -533,7 +533,7 @@ config KEYBOARD_DAVINCI
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
- depends on (ARCH_OMAP1 || ARCH_OMAP2)
+ depends on ARCH_OMAP1
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP keypad.
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index a0222db4dc86..2bda5f0b9c6e 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -35,13 +35,9 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-omap.h>
#include <plat/keypad.h>
-#include <plat/menelaus.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <plat/mux.h>
#undef NEW_BOARD_LEARNING_MODE
@@ -96,28 +92,8 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
{
- struct omap_kp *omap_kp = dev_id;
-
/* disable keyboard interrupt and schedule for handling */
- if (cpu_is_omap24xx()) {
- int i;
-
- for (i = 0; i < omap_kp->rows; i++) {
- int gpio_irq = gpio_to_irq(row_gpios[i]);
- /*
- * The interrupt which we're currently handling should
- * be disabled _nosync() to avoid deadlocks waiting
- * for this handler to complete. All others should
- * be disabled the regular way for SMP safety.
- */
- if (gpio_irq == irq)
- disable_irq_nosync(gpio_irq);
- else
- disable_irq(gpio_irq);
- }
- } else
- /* disable keyboard interrupt and schedule for handling */
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
tasklet_schedule(&kp_tasklet);
@@ -133,33 +109,22 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
{
int col = 0;
- /* read the keypad status */
- if (cpu_is_omap24xx()) {
- /* read the keypad status */
- for (col = 0; col < omap_kp->cols; col++) {
- set_col_gpio_val(omap_kp, ~(1 << col));
- state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;
- }
- set_col_gpio_val(omap_kp, 0);
-
- } else {
- /* disable keyboard interrupt and schedule for handling */
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- /* read the keypad status */
- omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- for (col = 0; col < omap_kp->cols; col++) {
- omap_writew(~(1 << col) & 0xff,
- OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ /* read the keypad status */
+ omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ for (col = 0; col < omap_kp->cols; col++) {
+ omap_writew(~(1 << col) & 0xff,
+ OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- udelay(omap_kp->delay);
+ udelay(omap_kp->delay);
- state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
- OMAP_MPUIO_KBR_LATCH) & 0xff;
- }
- omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- udelay(2);
+ state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
+ OMAP_MPUIO_KBR_LATCH) & 0xff;
}
+ omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ udelay(2);
}
static void omap_kp_tasklet(unsigned long data)
@@ -222,14 +187,8 @@ static void omap_kp_tasklet(unsigned long data)
mod_timer(&omap_kp_data->timer, jiffies + delay);
} else {
/* enable interrupts */
- if (cpu_is_omap24xx()) {
- int i;
- for (i = 0; i < omap_kp_data->rows; i++)
- enable_irq(gpio_to_irq(row_gpios[i]));
- } else {
- omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- kp_cur_group = -1;
- }
+ omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ kp_cur_group = -1;
}
}
@@ -242,6 +201,7 @@ static ssize_t omap_kp_enable_show(struct device *dev,
static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct omap_kp *omap_kp = dev_get_drvdata(dev);
int state;
if (sscanf(buf, "%u", &state) != 1)
@@ -253,9 +213,9 @@ static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute
mutex_lock(&kp_enable_mutex);
if (state != kp_enable) {
if (state)
- enable_irq(INT_KEYBOARD);
+ enable_irq(omap_kp->irq);
else
- disable_irq(INT_KEYBOARD);
+ disable_irq(omap_kp->irq);
kp_enable = state;
}
mutex_unlock(&kp_enable_mutex);
@@ -289,7 +249,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
struct omap_kp *omap_kp;
struct input_dev *input_dev;
struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
- int i, col_idx, row_idx, irq_idx, ret;
+ int i, col_idx, row_idx, ret;
unsigned int row_shift, keycodemax;
if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
@@ -314,8 +274,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
omap_kp->input = input_dev;
/* Disable the interrupt for the MPUIO keyboard */
- if (!cpu_is_omap24xx())
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
if (pdata->delay)
omap_kp->delay = pdata->delay;
@@ -328,31 +287,8 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
omap_kp->rows = pdata->rows;
omap_kp->cols = pdata->cols;
- if (cpu_is_omap24xx()) {
- /* Cols: outputs */
- for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
- if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
- printk(KERN_ERR "Failed to request"
- "GPIO%d for keypad\n",
- col_gpios[col_idx]);
- goto err1;
- }
- gpio_direction_output(col_gpios[col_idx], 0);
- }
- /* Rows: inputs */
- for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
- if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
- printk(KERN_ERR "Failed to request"
- "GPIO%d for keypad\n",
- row_gpios[row_idx]);
- goto err2;
- }
- gpio_direction_input(row_gpios[row_idx]);
- }
- } else {
- col_idx = 0;
- row_idx = 0;
- }
+ col_idx = 0;
+ row_idx = 0;
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
@@ -394,27 +330,16 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
/* scan current status and enable interrupt */
omap_kp_scan_keypad(omap_kp, keypad_state);
- if (!cpu_is_omap24xx()) {
- omap_kp->irq = platform_get_irq(pdev, 0);
- if (omap_kp->irq >= 0) {
- if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
- "omap-keypad", omap_kp) < 0)
- goto err4;
- }
- omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- } else {
- for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
- if (request_irq(gpio_to_irq(row_gpios[irq_idx]),
- omap_kp_interrupt,
- IRQF_TRIGGER_FALLING,
- "omap-keypad", omap_kp) < 0)
- goto err5;
- }
+ omap_kp->irq = platform_get_irq(pdev, 0);
+ if (omap_kp->irq >= 0) {
+ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
+ "omap-keypad", omap_kp) < 0)
+ goto err4;
}
+ omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
return 0;
-err5:
- for (i = irq_idx - 1; i >=0; i--)
- free_irq(row_gpios[i], omap_kp);
+
err4:
input_unregister_device(omap_kp->input);
input_dev = NULL;
@@ -423,7 +348,6 @@ err3:
err2:
for (i = row_idx - 1; i >=0; i--)
gpio_free(row_gpios[i]);
-err1:
for (i = col_idx - 1; i >=0; i--)
gpio_free(col_gpios[i]);
@@ -439,18 +363,8 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
/* disable keypad interrupt handling */
tasklet_disable(&kp_tasklet);
- if (cpu_is_omap24xx()) {
- int i;
- for (i = 0; i < omap_kp->cols; i++)
- gpio_free(col_gpios[i]);
- for (i = 0; i < omap_kp->rows; i++) {
- gpio_free(row_gpios[i]);
- free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
- }
- } else {
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- free_irq(omap_kp->irq, omap_kp);
- }
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ free_irq(omap_kp->irq, omap_kp);
del_timer_sync(&omap_kp->timer);
tasklet_kill(&kp_tasklet);
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
index f06231b7cab1..84ec691c05aa 100644
--- a/drivers/input/misc/ab8500-ponkey.c
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -74,8 +74,8 @@ static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
ponkey->idev = input;
ponkey->ab8500 = ab8500;
- ponkey->irq_dbf = ab8500_irq_get_virq(ab8500, irq_dbf);
- ponkey->irq_dbr = ab8500_irq_get_virq(ab8500, irq_dbr);
+ ponkey->irq_dbf = irq_dbf;
+ ponkey->irq_dbr = irq_dbr;
input->name = "AB8500 POn(PowerOn) Key";
input->dev.parent = &pdev->dev;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 38c4bd87b2c9..c679867c2ccd 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
mp->minor = minor;
- dev = tty_register_device(capinc_tty_driver, minor, NULL);
+ dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
+ NULL);
if (IS_ERR(dev))
goto err_out2;
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index a6d9fd2858f7..67abf3ff45e8 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
goto out;
}
- iflag = tty->termios->c_iflag;
- cflag = tty->termios->c_cflag;
+ iflag = tty->termios.c_iflag;
+ cflag = tty->termios.c_cflag;
old_cflag = old ? old->c_cflag : cflag;
gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
cs->minor_index, iflag, cflag, old_cflag);
@@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
mutex_lock(&cs->mutex);
- cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
+ cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
+ cs->minor_index, NULL);
if (!IS_ERR(cs->tty_dev))
dev_set_drvdata(cs->tty_dev, cs);
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
index fa6ca4733725..dceaec821b0e 100644
--- a/drivers/isdn/hardware/mISDN/avmfritz.c
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -857,8 +857,9 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ cancel_work_sync(&bch->workq);
spin_lock_irqsave(&fc->lock, flags);
- mISDN_freebchannel(bch);
+ mISDN_clear_bchannel(bch);
modehdlc(bch, ISDN_P_NONE);
spin_unlock_irqrestore(&fc->lock, flags);
ch->protocol = ISDN_P_NONE;
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index 5e402cf2e795..f02794203bb1 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -5059,6 +5059,7 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
printk(KERN_INFO
"HFC-E1 #%d has overlapping B-channels on fragment #%d\n",
E1_cnt + 1, pt);
+ kfree(hc);
return -EINVAL;
}
maskcheck |= hc->bmask[pt];
@@ -5086,6 +5087,7 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
if ((poll >> 1) > sizeof(hc->silence_data)) {
printk(KERN_ERR "HFCMULTI error: silence_data too small, "
"please fix\n");
+ kfree(hc);
return -EINVAL;
}
for (i = 0; i < (poll >> 1); i++)
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index 752e0825591f..ccd7d851be26 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1406,8 +1406,9 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ cancel_work_sync(&bch->workq);
spin_lock_irqsave(hx->ip->hwlock, flags);
- mISDN_freebchannel(bch);
+ mISDN_clear_bchannel(bch);
hscx_mode(hx, ISDN_P_NONE);
spin_unlock_irqrestore(hx->ip->hwlock, flags);
ch->protocol = ISDN_P_NONE;
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
index be5973ded6d6..182ecf0626c2 100644
--- a/drivers/isdn/hardware/mISDN/mISDNisar.c
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -1588,8 +1588,9 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ cancel_work_sync(&bch->workq);
spin_lock_irqsave(ich->is->hwlock, flags);
- mISDN_freebchannel(bch);
+ mISDN_clear_bchannel(bch);
modeisar(ich, ISDN_P_NONE);
spin_unlock_irqrestore(ich->is->hwlock, flags);
ch->protocol = ISDN_P_NONE;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index c3e3e7686273..9bcade59eb73 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -812,8 +812,9 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ cancel_work_sync(&bch->workq);
spin_lock_irqsave(&card->lock, flags);
- mISDN_freebchannel(bch);
+ mISDN_clear_bchannel(bch);
mode_tiger(bc, ISDN_P_NONE);
spin_unlock_irqrestore(&card->lock, flags);
ch->protocol = ISDN_P_NONE;
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index 26a86b846099..335fe6455002 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1054,8 +1054,9 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
switch (cmd) {
case CLOSE_CHANNEL:
test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ cancel_work_sync(&bch->workq);
spin_lock_irqsave(&card->lock, flags);
- mISDN_freebchannel(bch);
+ mISDN_clear_bchannel(bch);
w6692_mode(bc, ISDN_P_NONE);
spin_unlock_irqrestore(&card->lock, flags);
ch->protocol = ISDN_P_NONE;
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 7bc50670d7d9..b817809f763c 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info)
quot;
int i;
- if (!port->tty || !port->tty->termios)
+ if (!port->tty)
return;
- cflag = port->tty->termios->c_cflag;
+ cflag = port->tty->termios.c_cflag;
quot = i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
if (i < 1 || i > 2)
- port->tty->termios->c_cflag &= ~CBAUDEX;
+ port->tty->termios.c_cflag &= ~CBAUDEX;
else
i += 15;
}
@@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info)
#endif
isdn_unlock_drivers();
info->msr &= ~UART_MSR_RI;
- if (!info->port.tty || (info->port.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);
@@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!old_termios)
isdn_tty_change_speed(info);
else {
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_ispeed == old_termios->c_ispeed &&
- tty->termios->c_ospeed == old_termios->c_ospeed)
+ if (tty->termios.c_cflag == old_termios->c_cflag &&
+ tty->termios.c_ispeed == old_termios->c_ispeed &&
+ tty->termios.c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS))
+ !(tty->termios.c_cflag & CRTSCTS))
tty->hw_stopped = 0;
}
}
@@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* ------------------------------------------------------------
*/
+static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ modem_info *info = &dev->mdm.info[tty->index];
+
+ if (isdn_tty_paranoia_check(info, tty->name, __func__))
+ return -ENODEV;
+
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
@@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
- struct tty_port *port;
- modem_info *info;
+ modem_info *info = tty->driver_data;
+ struct tty_port *port = &info->port;
int retval;
- info = &dev->mdm.info[tty->index];
- if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
- return -ENODEV;
- port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
port->count);
#endif
port->count++;
- tty->driver_data = info;
port->tty = tty;
- tty->port = port;
/*
* Start up serial port
*/
@@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
}
static const struct tty_operations modem_ops = {
+ .install = isdn_tty_install,
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
@@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void)
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index ef34fd40867c..2602be23f341 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -148,17 +148,16 @@ mISDN_clear_bchannel(struct bchannel *ch)
ch->next_minlen = ch->init_minlen;
ch->maxlen = ch->init_maxlen;
ch->next_maxlen = ch->init_maxlen;
+ skb_queue_purge(&ch->rqueue);
+ ch->rcount = 0;
}
EXPORT_SYMBOL(mISDN_clear_bchannel);
-int
+void
mISDN_freebchannel(struct bchannel *ch)
{
+ cancel_work_sync(&ch->workq);
mISDN_clear_bchannel(ch);
- skb_queue_purge(&ch->rqueue);
- ch->rcount = 0;
- flush_work_sync(&ch->workq);
- return 0;
}
EXPORT_SYMBOL(mISDN_freebchannel);
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 88cf9d952631..409da0f8e5cf 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -44,6 +44,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <plat/cpu.h>
#include <plat/dma.h>
#include <plat/vrfb.h>
#include <video/omapdss.h>
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 1c347633e663..43e61fe5df50 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -70,6 +70,8 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <plat/cpu.h>
+
#include "isp.h"
#include "ispreg.h"
#include "ispccdc.h"
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index b67a3018b136..ce229ea933d1 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -470,7 +470,8 @@ static int __devinit device_800_init(struct pm80x_chip *chip,
ret =
mfd_add_devices(chip->dev, 0, &onkey_devs[0],
- ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0);
+ ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
+ NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
@@ -481,7 +482,7 @@ static int __devinit device_800_init(struct pm80x_chip *chip,
rtc_devs[0].platform_data = pdata->rtc;
rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
- ARRAY_SIZE(rtc_devs), NULL, 0);
+ ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out_dev;
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
index 6146583589f6..c20a31136f04 100644
--- a/drivers/mfd/88pm805.c
+++ b/drivers/mfd/88pm805.c
@@ -216,7 +216,8 @@ static int __devinit device_805_init(struct pm80x_chip *chip)
}
ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
- ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
+ ARRAY_SIZE(codec_devs), &codec_resources[0], 0,
+ NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add codec subdev\n");
goto out_codec;
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index d09918cf1b15..b73f033b2c60 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -637,7 +637,7 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
bk_devs[i].resources = &bk_resources[j];
ret = mfd_add_devices(chip->dev, 0,
&bk_devs[i], 1,
- &bk_resources[j], 0);
+ &bk_resources[j], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add "
"backlight subdev\n");
@@ -672,7 +672,7 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
led_devs[i].resources = &led_resources[j],
ret = mfd_add_devices(chip->dev, 0,
&led_devs[i], 1,
- &led_resources[j], 0);
+ &led_resources[j], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add "
"led subdev\n");
@@ -709,7 +709,7 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip,
regulator_devs[i].resources = &regulator_resources[seq];
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
- &regulator_resources[seq], 0);
+ &regulator_resources[seq], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add regulator subdev\n");
goto out;
@@ -733,7 +733,7 @@ static void __devinit device_rtc_init(struct pm860x_chip *chip,
rtc_devs[0].resources = &rtc_resources[0];
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs), &rtc_resources[0],
- chip->irq_base);
+ chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add rtc subdev\n");
}
@@ -752,7 +752,7 @@ static void __devinit device_touch_init(struct pm860x_chip *chip,
touch_devs[0].resources = &touch_resources[0];
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
ARRAY_SIZE(touch_devs), &touch_resources[0],
- chip->irq_base);
+ chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add touch subdev\n");
}
@@ -770,7 +770,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
power_devs[0].resources = &battery_resources[0],
ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
- &battery_resources[0], chip->irq_base);
+ &battery_resources[0], chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add battery subdev\n");
@@ -779,7 +779,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
power_devs[1].resources = &charger_resources[0],
ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
- &charger_resources[0], chip->irq_base);
+ &charger_resources[0], chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add charger subdev\n");
@@ -788,7 +788,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
power_devs[2].num_resources = ARRAY_SIZE(preg_resources);
power_devs[2].resources = &preg_resources[0],
ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
- &preg_resources[0], chip->irq_base);
+ &preg_resources[0], chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add preg subdev\n");
}
@@ -802,7 +802,7 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip,
onkey_devs[0].resources = &onkey_resources[0],
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs), &onkey_resources[0],
- chip->irq_base);
+ chip->irq_base, NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add onkey subdev\n");
}
@@ -815,7 +815,8 @@ static void __devinit device_codec_init(struct pm860x_chip *chip,
codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
codec_devs[0].resources = &codec_resources[0],
ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
- ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
+ ARRAY_SIZE(codec_devs), &codec_resources[0], 0,
+ NULL);
if (ret < 0)
dev_err(chip->dev, "Failed to add codec subdev\n");
}
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index 44a3fdbadef4..f1beb4971f87 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -424,7 +424,7 @@ static int aat2870_i2c_probe(struct i2c_client *client,
}
ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs,
- ARRAY_SIZE(aat2870_devs), NULL, 0);
+ ARRAY_SIZE(aat2870_devs), NULL, 0, NULL);
if (ret != 0) {
dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret);
goto out_disable;
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 78fca2902c8d..01781ae5d0d7 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -946,7 +946,7 @@ static int __devinit ab3100_probe(struct i2c_client *client,
}
err = mfd_add_devices(&client->dev, 0, ab3100_devs,
- ARRAY_SIZE(ab3100_devs), NULL, 0);
+ ARRAY_SIZE(ab3100_devs), NULL, 0, NULL);
ab3100_setup_debugfs(ab3100);
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 626b4ecaf647..47adf800024e 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1418,25 +1418,25 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
ARRAY_SIZE(abx500_common_devs), NULL,
- ab8500->irq_base);
+ ab8500->irq_base, ab8500->domain);
if (ret)
goto out_freeirq;
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
- ab8500->irq_base);
+ ab8500->irq_base, ab8500->domain);
else
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
- ab8500->irq_base);
+ ab8500->irq_base, ab8500->domain);
if (ret)
goto out_freeirq;
if (is_ab9540(ab8500) || is_ab8505(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
ARRAY_SIZE(ab9540_ab8505_devs), NULL,
- ab8500->irq_base);
+ ab8500->irq_base, ab8500->domain);
if (ret)
goto out_freeirq;
@@ -1444,7 +1444,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
ARRAY_SIZE(ab8500_bm_devs), NULL,
- ab8500->irq_base);
+ ab8500->irq_base, ab8500->domain);
if (ret)
dev_err(ab8500->dev, "error adding bm devices\n");
}
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index c7983e862549..1b48f2094806 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -316,7 +316,7 @@ int __devinit arizona_dev_init(struct arizona *arizona)
}
ret = mfd_add_devices(arizona->dev, -1, early_devs,
- ARRAY_SIZE(early_devs), NULL, 0);
+ ARRAY_SIZE(early_devs), NULL, 0, NULL);
if (ret != 0) {
dev_err(dev, "Failed to add early children: %d\n", ret);
return ret;
@@ -516,11 +516,11 @@ int __devinit arizona_dev_init(struct arizona *arizona)
switch (arizona->type) {
case WM5102:
ret = mfd_add_devices(arizona->dev, -1, wm5102_devs,
- ARRAY_SIZE(wm5102_devs), NULL, 0);
+ ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
break;
case WM5110:
ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
- ARRAY_SIZE(wm5102_devs), NULL, 0);
+ ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
break;
}
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 683e18a23329..62f0883a7630 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -913,14 +913,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
if (pdata->clock_rate) {
ds1wm_pdata.clock_rate = pdata->clock_rate;
ret = mfd_add_devices(&pdev->dev, pdev->id,
- &asic3_cell_ds1wm, 1, mem, asic->irq_base);
+ &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL);
if (ret < 0)
goto out;
}
if (mem_sdio && (irq >= 0)) {
ret = mfd_add_devices(&pdev->dev, pdev->id,
- &asic3_cell_mmc, 1, mem_sdio, irq);
+ &asic3_cell_mmc, 1, mem_sdio, irq, NULL);
if (ret < 0)
goto out;
}
@@ -934,7 +934,7 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]);
}
ret = mfd_add_devices(&pdev->dev, 0,
- asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0);
+ asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL);
}
out:
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
index 3419e726de47..2b282133c725 100644
--- a/drivers/mfd/cs5535-mfd.c
+++ b/drivers/mfd/cs5535-mfd.c
@@ -149,7 +149,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
}
err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
- ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
+ ARRAY_SIZE(cs5535_mfd_cells), NULL, 0, NULL);
if (err) {
dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
goto err_disable;
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index 2544910e1fd6..a0a62b24621b 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -803,7 +803,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret);
ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
- ARRAY_SIZE(da9052_subdev_info), NULL, 0);
+ ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL);
if (ret)
goto err;
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index 4e2af2cb2d26..45e83a68641b 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -129,7 +129,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
cell->pdata_size = sizeof(*davinci_vc);
ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
- DAVINCI_VC_CELLS, NULL, 0);
+ DAVINCI_VC_CELLS, NULL, 0, NULL);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register client devices\n");
goto fail4;
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 7040a0081130..6b67edbdbd01 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -418,6 +418,9 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
+/* Functions definition */
+static void compute_armss_rate(void);
+
/* Spinlocks */
static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock);
@@ -517,6 +520,7 @@ static struct dsiescclk dsiescclk[3] = {
}
};
+
/*
* Used by MCDE to setup all necessary PRCMU registers
*/
@@ -1013,6 +1017,7 @@ int db8500_prcmu_set_arm_opp(u8 opp)
(mb1_transfer.ack.arm_opp != opp))
r = -EIO;
+ compute_armss_rate();
mutex_unlock(&mb1_transfer.lock);
return r;
@@ -1612,6 +1617,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate,
if ((branch == PLL_FIX) || ((branch == PLL_DIV) &&
(val & PRCM_PLL_FREQ_DIV2EN) &&
((reg == PRCM_PLLSOC0_FREQ) ||
+ (reg == PRCM_PLLARM_FREQ) ||
(reg == PRCM_PLLDDR_FREQ))))
div *= 2;
@@ -1661,6 +1667,39 @@ static unsigned long clock_rate(u8 clock)
else
return 0;
}
+static unsigned long latest_armss_rate;
+static unsigned long armss_rate(void)
+{
+ return latest_armss_rate;
+}
+
+static void compute_armss_rate(void)
+{
+ u32 r;
+ unsigned long rate;
+
+ r = readl(PRCM_ARM_CHGCLKREQ);
+
+ if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) {
+ /* External ARMCLKFIX clock */
+
+ rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX);
+
+ /* Check PRCM_ARM_CHGCLKREQ divider */
+ if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL))
+ rate /= 2;
+
+ /* Check PRCM_ARMCLKFIX_MGT divider */
+ r = readl(PRCM_ARMCLKFIX_MGT);
+ r &= PRCM_CLK_MGT_CLKPLLDIV_MASK;
+ rate /= r;
+
+ } else {/* ARM PLL */
+ rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
+ }
+
+ latest_armss_rate = rate;
+}
static unsigned long dsiclk_rate(u8 n)
{
@@ -1707,6 +1746,8 @@ unsigned long prcmu_clock_rate(u8 clock)
return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
else if (clock == PRCMU_PLLSOC1)
return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
+ else if (clock == PRCMU_ARMSS)
+ return armss_rate();
else if (clock == PRCMU_PLLDDR)
return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW);
else if (clock == PRCMU_PLLDSI)
@@ -2693,6 +2734,7 @@ void __init db8500_prcmu_early_init(void)
handle_simple_irq);
set_irq_flags(irq, IRQF_VALID);
}
+ compute_armss_rate();
}
static void __init init_prcm_registers(void)
@@ -3010,7 +3052,7 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
- ARRAY_SIZE(db8500_prcmu_devs), NULL, 0);
+ ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL);
if (err) {
pr_err("prcmu: Failed to add subdevices\n");
return err;
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h
index 23108a6e3167..79c76ebdba52 100644
--- a/drivers/mfd/dbx500-prcmu-regs.h
+++ b/drivers/mfd/dbx500-prcmu-regs.h
@@ -61,7 +61,8 @@
#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2
#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
-#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16)
#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1
@@ -140,6 +141,7 @@
/* PRCMU clock/PLL/reset registers */
#define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080)
#define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084)
+#define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088)
#define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C)
#define PRCM_PLL_FREQ_D_SHIFT 0
#define PRCM_PLL_FREQ_D_MASK BITS(0, 7)
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index 04c7093d6499..9e5453d21a68 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -168,7 +168,7 @@ static int __init pasic3_probe(struct platform_device *pdev)
/* the first 5 PASIC3 registers control the DS1WM */
ds1wm_resources[0].end = (5 << asic->bus_shift) - 1;
ret = mfd_add_devices(&pdev->dev, pdev->id,
- &ds1wm_cell, 1, r, irq);
+ &ds1wm_cell, 1, r, irq, NULL);
if (ret < 0)
dev_warn(dev, "failed to register DS1WM\n");
}
@@ -176,7 +176,8 @@ static int __init pasic3_probe(struct platform_device *pdev)
if (pdata && pdata->led_pdata) {
led_cell.platform_data = pdata->led_pdata;
led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo);
- ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
+ ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r,
+ 0, NULL);
if (ret < 0)
dev_warn(dev, "failed to register LED device\n");
}
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index 59df5584cb58..266bdc5bd96d 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -344,13 +344,13 @@ static int __devinit intel_msic_init_devices(struct intel_msic *msic)
continue;
ret = mfd_add_devices(&pdev->dev, -1, &msic_devs[i], 1, NULL,
- pdata->irq[i]);
+ pdata->irq[i], NULL);
if (ret)
goto fail;
}
ret = mfd_add_devices(&pdev->dev, 0, msic_other_devs,
- ARRAY_SIZE(msic_other_devs), NULL, 0);
+ ARRAY_SIZE(msic_other_devs), NULL, 0, NULL);
if (ret)
goto fail;
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index 2ea99989551a..965c4801df8a 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -147,7 +147,7 @@ static int __devinit cmodio_probe_submodules(struct cmodio_device *priv)
}
return mfd_add_devices(&pdev->dev, 0, priv->cells,
- num_probed, NULL, pdev->irq);
+ num_probed, NULL, pdev->irq, NULL);
}
/*
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 87662a17dec6..c6b6d7dda517 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -287,7 +287,8 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
- ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base);
+ ARRAY_SIZE(jz4740_adc_cells), mem_base,
+ irq_base, NULL);
if (ret < 0)
goto err_clk_put;
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 0b2879b87fd9..24212f45b201 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -393,7 +393,8 @@ static int __devinit lm3533_device_als_init(struct lm3533 *lm3533)
lm3533_als_devs[0].platform_data = pdata->als;
lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
- ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 0);
+ ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL,
+ 0, NULL);
if (ret) {
dev_err(lm3533->dev, "failed to add ALS device\n");
return ret;
@@ -422,7 +423,7 @@ static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533)
}
ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
- pdata->num_backlights, NULL, 0);
+ pdata->num_backlights, NULL, 0, NULL);
if (ret) {
dev_err(lm3533->dev, "failed to add backlight devices\n");
return ret;
@@ -451,7 +452,7 @@ static int __devinit lm3533_device_led_init(struct lm3533 *lm3533)
}
ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
- pdata->num_leds, NULL, 0);
+ pdata->num_leds, NULL, 0, NULL);
if (ret) {
dev_err(lm3533->dev, "failed to add LED devices\n");
return ret;
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index 027cc8f86132..092ad4b44b6d 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -750,7 +750,7 @@ gpe0_done:
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
- 1, NULL, 0);
+ 1, NULL, 0, NULL);
gpio_done:
if (acpi_conflict)
@@ -765,7 +765,6 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev,
u32 base_addr_cfg;
u32 base_addr;
int ret;
- bool acpi_conflict = false;
struct resource *res;
/* Setup power management base register */
@@ -780,20 +779,11 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev,
res = wdt_io_res(ICH_RES_IO_TCO);
res->start = base_addr + ACPIBASE_TCO_OFF;
res->end = base_addr + ACPIBASE_TCO_END;
- ret = acpi_check_resource_conflict(res);
- if (ret) {
- acpi_conflict = true;
- goto wdt_done;
- }
res = wdt_io_res(ICH_RES_IO_SMI);
res->start = base_addr + ACPIBASE_SMI_OFF;
res->end = base_addr + ACPIBASE_SMI_END;
- ret = acpi_check_resource_conflict(res);
- if (ret) {
- acpi_conflict = true;
- goto wdt_done;
- }
+
lpc_ich_enable_acpi_space(dev);
/*
@@ -813,21 +803,13 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev,
res = wdt_mem_res(ICH_RES_MEM_GCS);
res->start = base_addr + ACPIBASE_GCS_OFF;
res->end = base_addr + ACPIBASE_GCS_END;
- ret = acpi_check_resource_conflict(res);
- if (ret) {
- acpi_conflict = true;
- goto wdt_done;
- }
}
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
- 1, NULL, 0);
+ 1, NULL, 0, NULL);
wdt_done:
- if (acpi_conflict)
- pr_warn("Resource conflict(s) found affecting %s\n",
- lpc_ich_cells[LPC_WDT].name);
return ret;
}
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index 9f20abc5e393..f6b9c5c96b24 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -127,7 +127,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
lpc_sch_cells[i].id = id->device;
ret = mfd_add_devices(&dev->dev, 0,
- lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
+ lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL,
+ 0, NULL);
if (ret)
goto out_dev;
@@ -153,7 +154,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
tunnelcreek_cells[i].id = id->device;
ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
- ARRAY_SIZE(tunnelcreek_cells), NULL, 0);
+ ARRAY_SIZE(tunnelcreek_cells), NULL,
+ 0, NULL);
}
return ret;
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index c03e12b51924..d9e24c849a00 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -126,7 +126,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
max77686_irq_init(max77686);
ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
- ARRAY_SIZE(max77686_devs), NULL, 0);
+ ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
if (ret < 0)
goto err_mfd;
diff --git a/drivers/mfd/max77693-irq.c b/drivers/mfd/max77693-irq.c
index 2b403569e0a6..1029d018c739 100644
--- a/drivers/mfd/max77693-irq.c
+++ b/drivers/mfd/max77693-irq.c
@@ -137,6 +137,9 @@ static void max77693_irq_mask(struct irq_data *data)
const struct max77693_irq_data *irq_data =
irq_to_max77693_irq(max77693, data->irq);
+ if (irq_data->group >= MAX77693_IRQ_GROUP_NR)
+ return;
+
if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3)
max77693->irq_masks_cur[irq_data->group] &= ~irq_data->mask;
else
@@ -149,6 +152,9 @@ static void max77693_irq_unmask(struct irq_data *data)
const struct max77693_irq_data *irq_data =
irq_to_max77693_irq(max77693, data->irq);
+ if (irq_data->group >= MAX77693_IRQ_GROUP_NR)
+ return;
+
if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3)
max77693->irq_masks_cur[irq_data->group] |= irq_data->mask;
else
@@ -200,7 +206,7 @@ static irqreturn_t max77693_irq_thread(int irq, void *data)
if (irq_src & MAX77693_IRQSRC_MUIC)
/* MUIC INT1 ~ INT3 */
- max77693_bulk_read(max77693->regmap, MAX77693_MUIC_REG_INT1,
+ max77693_bulk_read(max77693->regmap_muic, MAX77693_MUIC_REG_INT1,
MAX77693_NUM_IRQ_MUIC_REGS, &irq_reg[MUIC_INT1]);
/* Apply masking */
@@ -255,7 +261,8 @@ int max77693_irq_init(struct max77693_dev *max77693)
{
struct irq_domain *domain;
int i;
- int ret;
+ int ret = 0;
+ u8 intsrc_mask;
mutex_init(&max77693->irqlock);
@@ -287,19 +294,38 @@ int max77693_irq_init(struct max77693_dev *max77693)
&max77693_irq_domain_ops, max77693);
if (!domain) {
dev_err(max77693->dev, "could not create irq domain\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_irq;
}
max77693->irq_domain = domain;
+ /* Unmask max77693 interrupt */
+ ret = max77693_read_reg(max77693->regmap,
+ MAX77693_PMIC_REG_INTSRC_MASK, &intsrc_mask);
+ if (ret < 0) {
+ dev_err(max77693->dev, "fail to read PMIC register\n");
+ goto err_irq;
+ }
+
+ intsrc_mask &= ~(MAX77693_IRQSRC_CHG);
+ intsrc_mask &= ~(MAX77693_IRQSRC_FLASH);
+ intsrc_mask &= ~(MAX77693_IRQSRC_MUIC);
+ ret = max77693_write_reg(max77693->regmap,
+ MAX77693_PMIC_REG_INTSRC_MASK, intsrc_mask);
+ if (ret < 0) {
+ dev_err(max77693->dev, "fail to write PMIC register\n");
+ goto err_irq;
+ }
+
ret = request_threaded_irq(max77693->irq, NULL, max77693_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"max77693-irq", max77693);
-
if (ret)
dev_err(max77693->dev, "Failed to request IRQ %d: %d\n",
max77693->irq, ret);
- return 0;
+err_irq:
+ return ret;
}
void max77693_irq_exit(struct max77693_dev *max77693)
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index a1811cb50ec7..cc5155e20494 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -152,6 +152,20 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
i2c_set_clientdata(max77693->haptic, max77693);
+ /*
+ * Initialize register map for MUIC device because use regmap-muic
+ * instance of MUIC device when irq of max77693 is initialized
+ * before call max77693-muic probe() function.
+ */
+ max77693->regmap_muic = devm_regmap_init_i2c(max77693->muic,
+ &max77693_regmap_config);
+ if (IS_ERR(max77693->regmap_muic)) {
+ ret = PTR_ERR(max77693->regmap_muic);
+ dev_err(max77693->dev,
+ "failed to allocate register map: %d\n", ret);
+ goto err_regmap;
+ }
+
ret = max77693_irq_init(max77693);
if (ret < 0)
goto err_irq;
@@ -159,7 +173,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(max77693->dev);
ret = mfd_add_devices(max77693->dev, -1, max77693_devs,
- ARRAY_SIZE(max77693_devs), NULL, 0);
+ ARRAY_SIZE(max77693_devs), NULL, 0, NULL);
if (ret < 0)
goto err_mfd;
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 825a7f06d9ba..ee53757beca7 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -598,7 +598,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
ARRAY_SIZE(rtc_devs),
- &rtc_resources[0], chip->irq_base);
+ &rtc_resources[0], chip->irq_base, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out;
@@ -606,7 +606,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs),
- &onkey_resources[0], 0);
+ &onkey_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
@@ -615,7 +615,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
if (pdata) {
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),
- &regulator_resources[0], 0);
+ &regulator_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add regulator subdev\n");
goto out_dev;
@@ -625,7 +625,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
if (pdata && pdata->backlight) {
ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
ARRAY_SIZE(backlight_devs),
- &backlight_resources[0], 0);
+ &backlight_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add backlight subdev\n");
goto out_dev;
@@ -635,7 +635,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
if (pdata && pdata->power) {
ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
ARRAY_SIZE(power_devs),
- &power_supply_resources[0], 0);
+ &power_supply_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add power supply "
"subdev\n");
@@ -646,7 +646,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
if (pdata && pdata->touch) {
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
ARRAY_SIZE(touch_devs),
- &touch_resources[0], 0);
+ &touch_resources[0], 0, NULL);
if (ret < 0) {
dev_err(chip->dev, "Failed to add touch subdev\n");
goto out_dev;
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 10b629c245b6..f123517065ec 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -160,7 +160,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
mfd_add_devices(max8997->dev, -1, max8997_devs,
ARRAY_SIZE(max8997_devs),
- NULL, 0);
+ NULL, 0, NULL);
/*
* TODO: enable others (flash, muic, rtc, battery, ...) and
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index 6ef56d28c056..d7218cc90945 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -161,13 +161,13 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
switch (id->driver_data) {
case TYPE_LP3974:
ret = mfd_add_devices(max8998->dev, -1,
- lp3974_devs, ARRAY_SIZE(lp3974_devs),
- NULL, 0);
+ lp3974_devs, ARRAY_SIZE(lp3974_devs),
+ NULL, 0, NULL);
break;
case TYPE_MAX8998:
ret = mfd_add_devices(max8998->dev, -1,
- max8998_devs, ARRAY_SIZE(max8998_devs),
- NULL, 0);
+ max8998_devs, ARRAY_SIZE(max8998_devs),
+ NULL, 0, NULL);
break;
default:
ret = -EINVAL;
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index b801dc72f041..1ec79b54bd2f 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -612,7 +612,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
if (!cell.name)
return -ENOMEM;
- return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0);
+ return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0, NULL);
}
static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 0c3a01cde2f7..f8b77711ad2d 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -74,12 +74,11 @@ static int mfd_platform_add_cell(struct platform_device *pdev,
static int mfd_add_device(struct device *parent, int id,
const struct mfd_cell *cell,
struct resource *mem_base,
- int irq_base)
+ int irq_base, struct irq_domain *domain)
{
struct resource *res;
struct platform_device *pdev;
struct device_node *np = NULL;
- struct irq_domain *domain = NULL;
int ret = -ENOMEM;
int r;
@@ -97,7 +96,6 @@ static int mfd_add_device(struct device *parent, int id,
for_each_child_of_node(parent->of_node, np) {
if (of_device_is_compatible(np, cell->of_compatible)) {
pdev->dev.of_node = np;
- domain = irq_find_host(parent->of_node);
break;
}
}
@@ -177,7 +175,7 @@ fail_alloc:
int mfd_add_devices(struct device *parent, int id,
struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
- int irq_base)
+ int irq_base, struct irq_domain *domain)
{
int i;
int ret = 0;
@@ -191,7 +189,8 @@ int mfd_add_devices(struct device *parent, int id,
for (i = 0; i < n_devs; i++) {
atomic_set(&cnts[i], 0);
cells[i].usage_count = &cnts[i];
- ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base);
+ ret = mfd_add_device(parent, id, cells + i, mem_base,
+ irq_base, domain);
if (ret)
break;
}
@@ -247,7 +246,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)
for (i = 0; i < n_clones; i++) {
cell_entry.name = clones[i];
/* don't give up if a single call fails; just report error */
- if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0))
+ if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0,
+ NULL))
dev_err(dev, "failed to create platform device '%s'\n",
clones[i]);
}
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index c4a69f193a1d..a345f9bb7b47 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -453,7 +453,8 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(palmas->dev, -1,
children, ARRAY_SIZE(palmas_children),
- NULL, regmap_irq_chip_get_base(palmas->irq_data));
+ NULL, regmap_irq_chip_get_base(palmas->irq_data),
+ NULL);
kfree(children);
if (ret < 0)
diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c
index cdc1df7fa0e9..3a8fa88567b1 100644
--- a/drivers/mfd/rc5t583.c
+++ b/drivers/mfd/rc5t583.c
@@ -289,7 +289,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
}
ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
- ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
+ ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
goto err_add_devs;
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c
index 685d61e431ad..0f70dce61160 100644
--- a/drivers/mfd/rdc321x-southbridge.c
+++ b/drivers/mfd/rdc321x-southbridge.c
@@ -87,7 +87,8 @@ static int __devinit rdc321x_sb_probe(struct pci_dev *pdev,
rdc321x_wdt_pdata.sb_pdev = pdev;
return mfd_add_devices(&pdev->dev, -1,
- rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), NULL, 0);
+ rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells),
+ NULL, 0, NULL);
}
static void __devexit rdc321x_sb_remove(struct pci_dev *pdev)
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 2988efde11eb..49d361a618d0 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -141,19 +141,19 @@ static int sec_pmic_probe(struct i2c_client *i2c,
switch (sec_pmic->device_type) {
case S5M8751X:
ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs,
- ARRAY_SIZE(s5m8751_devs), NULL, 0);
+ ARRAY_SIZE(s5m8751_devs), NULL, 0, NULL);
break;
case S5M8763X:
ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs,
- ARRAY_SIZE(s5m8763_devs), NULL, 0);
+ ARRAY_SIZE(s5m8763_devs), NULL, 0, NULL);
break;
case S5M8767X:
ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
- ARRAY_SIZE(s5m8767_devs), NULL, 0);
+ ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
break;
case S2MPS11X:
ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
- ARRAY_SIZE(s2mps11_devs), NULL, 0);
+ ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
break;
default:
/* If this happens the probe function is problem */
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c
index d31fed07aefb..d35da6820bea 100644
--- a/drivers/mfd/sta2x11-mfd.c
+++ b/drivers/mfd/sta2x11-mfd.c
@@ -407,7 +407,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev,
sta2x11_mfd_bar0,
ARRAY_SIZE(sta2x11_mfd_bar0),
&pdev->resource[0],
- 0);
+ 0, NULL);
if (err) {
dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err);
goto err_disable;
@@ -417,7 +417,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev,
sta2x11_mfd_bar1,
ARRAY_SIZE(sta2x11_mfd_bar1),
&pdev->resource[1],
- 0);
+ 0, NULL);
if (err) {
dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err);
goto err_disable;
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 2dd8d49cb30b..c94f521f392c 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -962,7 +962,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe,
struct mfd_cell *cell, int irq)
{
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
- NULL, stmpe->irq_base + irq);
+ NULL, stmpe->irq_base + irq, NULL);
}
static int __devinit stmpe_devices_init(struct stmpe *stmpe)
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 2d9e8799e733..b32940ec9034 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -388,7 +388,7 @@ static int t7l66xb_probe(struct platform_device *dev)
ret = mfd_add_devices(&dev->dev, dev->id,
t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
- iomem, t7l66xb->irq_base);
+ iomem, t7l66xb->irq_base, NULL);
if (!ret)
return 0;
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
index 048bf0532a09..b56ba6b43294 100644
--- a/drivers/mfd/tc3589x.c
+++ b/drivers/mfd/tc3589x.c
@@ -262,8 +262,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_GPIO) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
- ARRAY_SIZE(tc3589x_dev_gpio), NULL,
- tc3589x->irq_base);
+ ARRAY_SIZE(tc3589x_dev_gpio), NULL,
+ tc3589x->irq_base, NULL);
if (ret) {
dev_err(tc3589x->dev, "failed to add gpio child\n");
return ret;
@@ -273,8 +273,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_KEYPAD) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
- ARRAY_SIZE(tc3589x_dev_keypad), NULL,
- tc3589x->irq_base);
+ ARRAY_SIZE(tc3589x_dev_keypad), NULL,
+ tc3589x->irq_base, NULL);
if (ret) {
dev_err(tc3589x->dev, "failed to keypad child\n");
return ret;
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index d20a284ad4ba..413c891102f8 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -192,7 +192,7 @@ static int __devinit tc6387xb_probe(struct platform_device *dev)
printk(KERN_INFO "Toshiba tc6387xb initialised\n");
ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells,
- ARRAY_SIZE(tc6387xb_cells), iomem, irq);
+ ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL);
if (!ret)
return 0;
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 9612264f0e6d..dcab026fcbb2 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -700,8 +700,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data);
ret = mfd_add_devices(&dev->dev, dev->id,
- tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
- iomem, tcpd->irq_base);
+ tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
+ iomem, tcpd->irq_base, NULL);
if (!ret)
return 0;
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
index 4fb0e6c8e8fe..7c3675a74f93 100644
--- a/drivers/mfd/ti-ssp.c
+++ b/drivers/mfd/ti-ssp.c
@@ -412,7 +412,7 @@ static int __devinit ti_ssp_probe(struct platform_device *pdev)
cells[id].data_size = data->pdata_size;
}
- error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
+ error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL);
if (error < 0) {
dev_err(dev, "cannot add mfd cells\n");
goto error_enable;
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index a447f4ec11fb..cccc626c83c8 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -757,25 +757,25 @@ static int __devinit timb_probe(struct pci_dev *dev,
err = mfd_add_devices(&dev->dev, -1,
timberdale_cells_bar0_cfg0,
ARRAY_SIZE(timberdale_cells_bar0_cfg0),
- &dev->resource[0], msix_entries[0].vector);
+ &dev->resource[0], msix_entries[0].vector, NULL);
break;
case TIMB_HW_VER1:
err = mfd_add_devices(&dev->dev, -1,
timberdale_cells_bar0_cfg1,
ARRAY_SIZE(timberdale_cells_bar0_cfg1),
- &dev->resource[0], msix_entries[0].vector);
+ &dev->resource[0], msix_entries[0].vector, NULL);
break;
case TIMB_HW_VER2:
err = mfd_add_devices(&dev->dev, -1,
timberdale_cells_bar0_cfg2,
ARRAY_SIZE(timberdale_cells_bar0_cfg2),
- &dev->resource[0], msix_entries[0].vector);
+ &dev->resource[0], msix_entries[0].vector, NULL);
break;
case TIMB_HW_VER3:
err = mfd_add_devices(&dev->dev, -1,
timberdale_cells_bar0_cfg3,
ARRAY_SIZE(timberdale_cells_bar0_cfg3),
- &dev->resource[0], msix_entries[0].vector);
+ &dev->resource[0], msix_entries[0].vector, NULL);
break;
default:
dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n",
@@ -792,7 +792,7 @@ static int __devinit timb_probe(struct pci_dev *dev,
err = mfd_add_devices(&dev->dev, 0,
timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
- &dev->resource[1], msix_entries[0].vector);
+ &dev->resource[1], msix_entries[0].vector, NULL);
if (err) {
dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
goto err_mfd2;
@@ -803,7 +803,7 @@ static int __devinit timb_probe(struct pci_dev *dev,
((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
ARRAY_SIZE(timberdale_cells_bar2),
- &dev->resource[2], msix_entries[0].vector);
+ &dev->resource[2], msix_entries[0].vector, NULL);
if (err) {
dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
goto err_mfd2;
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c
index a293b978e27c..14051bdc714b 100644
--- a/drivers/mfd/tps6105x.c
+++ b/drivers/mfd/tps6105x.c
@@ -188,7 +188,7 @@ static int __devinit tps6105x_probe(struct i2c_client *client,
}
ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
- ARRAY_SIZE(tps6105x_cells), NULL, 0);
+ ARRAY_SIZE(tps6105x_cells), NULL, 0, NULL);
if (ret)
goto fail;
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c
index 33ba7723c967..1b203499c744 100644
--- a/drivers/mfd/tps6507x.c
+++ b/drivers/mfd/tps6507x.c
@@ -100,7 +100,7 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(tps6507x->dev, -1,
tps6507x_devs, ARRAY_SIZE(tps6507x_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (ret < 0)
goto err;
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index 80e24f4b47bf..50fd87c87a1c 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -292,7 +292,7 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client,
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
- ARRAY_SIZE(tps65090s), NULL, 0);
+ ARRAY_SIZE(tps65090s), NULL, 0, NULL);
if (ret) {
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
ret);
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 61c097a98f5d..a95e9421b735 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -24,11 +24,18 @@
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/err.h>
-#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps65217.h>
+static struct mfd_cell tps65217s[] = {
+ {
+ .name = "tps65217-pmic",
+ },
+};
+
/**
* tps65217_reg_read: Read a single tps65217 register.
*
@@ -133,83 +140,48 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
-#ifdef CONFIG_OF
-static struct of_regulator_match reg_matches[] = {
- { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
- { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
- { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
- { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
- { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
- { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
- { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
-};
-
-static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
-{
- struct device_node *node = client->dev.of_node;
- struct tps65217_board *pdata;
- struct device_node *regs;
- int count = ARRAY_SIZE(reg_matches);
- int ret, i;
-
- regs = of_find_node_by_name(node, "regulators");
- if (!regs)
- return NULL;
-
- ret = of_regulator_match(&client->dev, regs, reg_matches, count);
- of_node_put(regs);
- if ((ret < 0) || (ret > count))
- return NULL;
-
- count = ret;
- pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- for (i = 0; i < count; i++) {
- if (!reg_matches[i].init_data || !reg_matches[i].of_node)
- continue;
-
- pdata->tps65217_init_data[i] = reg_matches[i].init_data;
- pdata->of_node[i] = reg_matches[i].of_node;
- }
-
- return pdata;
-}
-
-static struct of_device_id tps65217_of_match[] = {
- { .compatible = "ti,tps65217", },
- { },
-};
-#else
-static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
-{
- return NULL;
-}
-#endif
-
static struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
+static const struct of_device_id tps65217_of_match[] = {
+ { .compatible = "ti,tps65217", .data = (void *)TPS65217 },
+ { /* sentinel */ },
+};
+
static int __devinit tps65217_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
{
struct tps65217 *tps;
- struct regulator_init_data *reg_data;
- struct tps65217_board *pdata = client->dev.platform_data;
- int i, ret;
unsigned int version;
+ unsigned int chip_id = ids->driver_data;
+ const struct of_device_id *match;
+ int ret;
- if (!pdata && client->dev.of_node)
- pdata = tps65217_parse_dt(client);
+ if (client->dev.of_node) {
+ match = of_match_device(tps65217_of_match, &client->dev);
+ if (!match) {
+ dev_err(&client->dev,
+ "Failed to find matching dt id\n");
+ return -EINVAL;
+ }
+ chip_id = (unsigned int)match->data;
+ }
+
+ if (!chip_id) {
+ dev_err(&client->dev, "id is null.\n");
+ return -ENODEV;
+ }
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
- tps->pdata = pdata;
+ i2c_set_clientdata(client, tps);
+ tps->dev = &client->dev;
+ tps->id = chip_id;
+
tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
@@ -218,8 +190,12 @@ static int __devinit tps65217_probe(struct i2c_client *client,
return ret;
}
- i2c_set_clientdata(client, tps);
- tps->dev = &client->dev;
+ ret = mfd_add_devices(tps->dev, -1, tps65217s,
+ ARRAY_SIZE(tps65217s), NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
+ return ret;
+ }
ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version);
if (ret < 0) {
@@ -232,41 +208,21 @@ static int __devinit tps65217_probe(struct i2c_client *client,
(version & TPS65217_CHIPID_CHIP_MASK) >> 4,
version & TPS65217_CHIPID_REV_MASK);
- for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
- struct platform_device *pdev;
-
- pdev = platform_device_alloc("tps65217-pmic", i);
- if (!pdev) {
- dev_err(tps->dev, "Cannot create regulator %d\n", i);
- continue;
- }
-
- pdev->dev.parent = tps->dev;
- pdev->dev.of_node = pdata->of_node[i];
- reg_data = pdata->tps65217_init_data[i];
- platform_device_add_data(pdev, reg_data, sizeof(*reg_data));
- tps->regulator_pdev[i] = pdev;
-
- platform_device_add(pdev);
- }
-
return 0;
}
static int __devexit tps65217_remove(struct i2c_client *client)
{
struct tps65217 *tps = i2c_get_clientdata(client);
- int i;
- for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
- platform_device_unregister(tps->regulator_pdev[i]);
+ mfd_remove_devices(tps->dev);
return 0;
}
static const struct i2c_device_id tps65217_id_table[] = {
- {"tps65217", 0xF0},
- {/* end of list */}
+ {"tps65217", TPS65217},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 353c34812120..5f58370ccf55 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -493,7 +493,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
}
ret = mfd_add_devices(tps6586x->dev, -1,
- tps6586x_cell, ARRAY_SIZE(tps6586x_cell), NULL, 0);
+ tps6586x_cell, ARRAY_SIZE(tps6586x_cell),
+ NULL, 0, NULL);
if (ret < 0) {
dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret);
goto err_mfd_add;
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 1c563792c777..d3ce4d569deb 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -254,7 +254,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(tps65910->dev, -1,
tps65910s, ARRAY_SIZE(tps65910s),
- NULL, 0);
+ NULL, 0, NULL);
if (ret < 0) {
dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret);
return ret;
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
index 74fd8cb5f372..4658b5bdcd84 100644
--- a/drivers/mfd/tps65912-core.c
+++ b/drivers/mfd/tps65912-core.c
@@ -146,7 +146,7 @@ int tps65912_device_init(struct tps65912 *tps65912)
ret = mfd_add_devices(tps65912->dev, -1,
tps65912s, ARRAY_SIZE(tps65912s),
- NULL, 0);
+ NULL, 0, NULL);
if (ret < 0)
goto err;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 1c32afed28aa..f462ff226c8d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -46,6 +46,8 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
+#include <plat/cpu.h>
+
#include "twl-core.h"
/*
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c
index 838ce4eb444e..77c9acb14583 100644
--- a/drivers/mfd/twl4030-audio.c
+++ b/drivers/mfd/twl4030-audio.c
@@ -223,7 +223,7 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev)
if (childs)
ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells,
- childs, NULL, 0);
+ childs, NULL, 0, NULL);
else {
dev_err(&pdev->dev, "No platform data found for childs\n");
ret = -ENODEV;
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index b0fad0ffca56..3dca5c195a20 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -632,7 +632,7 @@ static int __devinit twl6040_probe(struct i2c_client *client,
}
ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
- NULL, 0);
+ NULL, 0, NULL);
if (ret)
goto mfd_err;
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c
index 872aff21e4be..b9a636d44c7f 100644
--- a/drivers/mfd/vx855.c
+++ b/drivers/mfd/vx855.c
@@ -102,7 +102,7 @@ static __devinit int vx855_probe(struct pci_dev *pdev,
vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3;
ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells),
- NULL, 0);
+ NULL, 0, NULL);
/* we always return -ENODEV here in order to enable other
* drivers like old, not-yet-platform_device ported i2c-viapro */
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c
index f39b756df561..86e0e4309fc2 100644
--- a/drivers/mfd/wl1273-core.c
+++ b/drivers/mfd/wl1273-core.c
@@ -241,7 +241,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
__func__, children);
r = mfd_add_devices(&client->dev, -1, core->cells,
- children, NULL, 0);
+ children, NULL, 0, NULL);
if (r)
goto err;
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 946698fd2dc6..301731035940 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1813,27 +1813,27 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8310:
ret = mfd_add_devices(wm831x->dev, wm831x_num,
wm8310_devs, ARRAY_SIZE(wm8310_devs),
- NULL, 0);
+ NULL, 0, NULL);
break;
case WM8311:
ret = mfd_add_devices(wm831x->dev, wm831x_num,
wm8311_devs, ARRAY_SIZE(wm8311_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (!pdata || !pdata->disable_touch)
mfd_add_devices(wm831x->dev, wm831x_num,
touch_devs, ARRAY_SIZE(touch_devs),
- NULL, 0);
+ NULL, 0, NULL);
break;
case WM8312:
ret = mfd_add_devices(wm831x->dev, wm831x_num,
wm8312_devs, ARRAY_SIZE(wm8312_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (!pdata || !pdata->disable_touch)
mfd_add_devices(wm831x->dev, wm831x_num,
touch_devs, ARRAY_SIZE(touch_devs),
- NULL, 0);
+ NULL, 0, NULL);
break;
case WM8320:
@@ -1842,7 +1842,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
case WM8326:
ret = mfd_add_devices(wm831x->dev, wm831x_num,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
+ NULL, 0, NULL);
break;
default:
@@ -1867,7 +1867,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
if (ret & WM831X_XTAL_ENA) {
ret = mfd_add_devices(wm831x->dev, wm831x_num,
rtc_devs, ARRAY_SIZE(rtc_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (ret != 0) {
dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
goto err_irq;
@@ -1880,7 +1880,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
/* Treat errors as non-critical */
ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
ARRAY_SIZE(backlight_devs), NULL,
- 0);
+ 0, NULL);
if (ret < 0)
dev_err(wm831x->dev, "Failed to add backlight: %d\n",
ret);
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 4b7d378551d5..639ca359242f 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -70,7 +70,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
.pdata_size = sizeof(*wm8400),
};
- return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
+ return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL);
}
/*
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index eec74aa55fdf..2febf88cfce8 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -414,7 +414,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
ret = mfd_add_devices(wm8994->dev, -1,
wm8994_regulator_devs,
ARRAY_SIZE(wm8994_regulator_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
goto err;
@@ -648,7 +648,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq)
ret = mfd_add_devices(wm8994->dev, -1,
wm8994_devs, ARRAY_SIZE(wm8994_devs),
- NULL, 0);
+ NULL, 0, NULL);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
goto err_irq;
diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c
index 1dcb9ae1905a..01e2b0d7e590 100644
--- a/drivers/misc/ibmasm/uart.c
+++ b/drivers/misc/ibmasm/uart.c
@@ -33,7 +33,7 @@
void ibmasm_register_uart(struct service_processor *sp)
{
- struct uart_port uport;
+ struct uart_8250_port uart;
void __iomem *iomem_base;
iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp)
return;
}
- memset(&uport, 0, sizeof(struct uart_port));
- uport.irq = sp->irq;
- uport.uartclk = 3686400;
- uport.flags = UPF_SHARE_IRQ;
- uport.iotype = UPIO_MEM;
- uport.membase = iomem_base;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.irq = sp->irq;
+ uart.port.uartclk = 3686400;
+ uart.port.flags = UPF_SHARE_IRQ;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.membase = iomem_base;
- sp->serial_line = serial8250_register_port(&uport);
+ sp->serial_line = serial8250_register_8250_port(&uart);
if (sp->serial_line < 0) {
dev_err(sp->dev, "Failed to register serial port\n");
return;
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index b7eb545394b1..4999b34b7a60 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -60,7 +60,7 @@ struct pti_tty {
};
struct pti_dev {
- struct tty_port port;
+ struct tty_port port[PTITTY_MINOR_NUM];
unsigned long pti_addr;
unsigned long aperture_base;
void __iomem *pti_ioaddr;
@@ -76,7 +76,7 @@ struct pti_dev {
*/
static DEFINE_MUTEX(alloclock);
-static struct pci_device_id pci_ids[] __devinitconst = {
+static const struct pci_device_id pci_ids[] __devinitconst = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
{0}
};
@@ -393,25 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
}
EXPORT_SYMBOL_GPL(pti_writedata);
-/**
- * pti_pci_remove()- Driver exit method to remove PTI from
- * PCI bus.
- * @pdev: variable containing pci info of PTI.
- */
-static void __devexit pti_pci_remove(struct pci_dev *pdev)
-{
- struct pti_dev *drv_data;
-
- drv_data = pci_get_drvdata(pdev);
- if (drv_data != NULL) {
- pci_iounmap(pdev, drv_data->pti_ioaddr);
- pci_set_drvdata(pdev, NULL);
- kfree(drv_data);
- pci_release_region(pdev, 1);
- pci_disable_device(pdev);
- }
-}
-
/*
* for the tty_driver_*() basic function descriptions, see tty_driver.h.
* Specific header comments made for PTI-related specifics.
@@ -446,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
* also removes a locking requirement for the actual write
* procedure.
*/
- return tty_port_open(&drv_data->port, tty, filp);
+ return tty_port_open(tty->port, tty, filp);
}
/**
@@ -462,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
*/
static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
{
- tty_port_close(&drv_data->port, tty, filp);
+ tty_port_close(tty->port, tty, filp);
}
/**
@@ -818,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = {
static int __devinit pti_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ unsigned int a;
int retval = -EINVAL;
int pci_bar = 1;
@@ -830,7 +812,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
- return retval;
+ goto err;
}
retval = pci_enable_device(pdev);
@@ -838,17 +820,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s: pci_enable_device() returned error %d\n",
__func__, retval);
- return retval;
+ goto err_unreg_misc;
}
drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
-
if (drv_data == NULL) {
retval = -ENOMEM;
dev_err(&pdev->dev,
"%s(%d): kmalloc() returned NULL memory.\n",
__func__, __LINE__);
- return retval;
+ goto err_disable_pci;
}
drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
@@ -857,33 +838,65 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev,
"%s(%d): pci_request_region() returned error %d\n",
__func__, __LINE__, retval);
- kfree(drv_data);
- return retval;
+ goto err_free_dd;
}
drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
drv_data->pti_ioaddr =
ioremap_nocache((u32)drv_data->aperture_base,
APERTURE_LEN);
if (!drv_data->pti_ioaddr) {
- pci_release_region(pdev, pci_bar);
retval = -ENOMEM;
- kfree(drv_data);
- return retval;
+ goto err_rel_reg;
}
pci_set_drvdata(pdev, drv_data);
- tty_port_init(&drv_data->port);
- drv_data->port.ops = &tty_port_ops;
+ for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+ struct tty_port *port = &drv_data->port[a];
+ tty_port_init(port);
+ port->ops = &tty_port_ops;
- tty_register_device(pti_tty_driver, 0, &pdev->dev);
- tty_register_device(pti_tty_driver, 1, &pdev->dev);
+ tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
+ }
register_console(&pti_console);
+ return 0;
+err_rel_reg:
+ pci_release_region(pdev, pci_bar);
+err_free_dd:
+ kfree(drv_data);
+err_disable_pci:
+ pci_disable_device(pdev);
+err_unreg_misc:
+ misc_deregister(&pti_char_driver);
+err:
return retval;
}
+/**
+ * pti_pci_remove()- Driver exit method to remove PTI from
+ * PCI bus.
+ * @pdev: variable containing pci info of PTI.
+ */
+static void __devexit pti_pci_remove(struct pci_dev *pdev)
+{
+ struct pti_dev *drv_data = pci_get_drvdata(pdev);
+
+ unregister_console(&pti_console);
+
+ tty_unregister_device(pti_tty_driver, 0);
+ tty_unregister_device(pti_tty_driver, 1);
+
+ iounmap(drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+
+ misc_deregister(&pti_char_driver);
+}
+
static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
@@ -933,25 +946,24 @@ static int __init pti_init(void)
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
- pti_tty_driver = NULL;
- return retval;
+ goto put_tty;
}
retval = pci_register_driver(&pti_pci_driver);
-
if (retval) {
pr_err("%s(%d): PCI registration failed of pti driver\n",
__func__, __LINE__);
pr_err("%s(%d): Error value returned: %d\n",
__func__, __LINE__, retval);
-
- tty_unregister_driver(pti_tty_driver);
- pr_err("%s(%d): Unregistering TTY part of pti driver\n",
- __func__, __LINE__);
- pti_tty_driver = NULL;
- return retval;
+ goto unreg_tty;
}
+ return 0;
+unreg_tty:
+ tty_unregister_driver(pti_tty_driver);
+put_tty:
+ put_tty_driver(pti_tty_driver);
+ pti_tty_driver = NULL;
return retval;
}
@@ -960,31 +972,9 @@ static int __init pti_init(void)
*/
static void __exit pti_exit(void)
{
- int retval;
-
- tty_unregister_device(pti_tty_driver, 0);
- tty_unregister_device(pti_tty_driver, 1);
-
- retval = tty_unregister_driver(pti_tty_driver);
- if (retval) {
- pr_err("%s(%d): TTY unregistration failed of pti driver\n",
- __func__, __LINE__);
- pr_err("%s(%d): Error value returned: %d\n",
- __func__, __LINE__, retval);
- }
-
+ tty_unregister_driver(pti_tty_driver);
pci_unregister_driver(&pti_pci_driver);
-
- retval = misc_deregister(&pti_char_driver);
- if (retval) {
- pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
- __func__, __LINE__);
- pr_err("%s(%d): Error value returned: %d\n",
- __func__, __LINE__, retval);
- }
-
- unregister_console(&pti_console);
- return;
+ put_tty_driver(pti_tty_driver);
}
module_init(pti_init);
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 5a2cbfac66d2..d2339ea37815 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
if (status & UART_MSR_DCTS) {
port->icount.cts++;
tty = tty_port_tty_get(&port->port);
- if (tty && (tty->termios->c_cflag & CRTSCTS)) {
+ if (tty && (tty->termios.c_cflag & CRTSCTS)) {
int cts = (status & UART_MSR_CTS);
if (tty->hw_stopped) {
if (cts) {
@@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
port->mctrl = TIOCM_OUT2;
- sdio_uart_change_speed(port, tty->termios, NULL);
+ sdio_uart_change_speed(port, &tty->termios, NULL);
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
sdio_uart_start_tx(port);
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_clear_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
return;
if (sdio_uart_claim_func(port) != 0)
@@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
sdio_uart_set_mctrl(port, TIOCM_RTS);
sdio_uart_irq(port->func);
@@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct sdio_uart_port *port = tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
if (sdio_uart_claim_func(port) != 0)
return;
- sdio_uart_change_speed(port, tty->termios, old_termios);
+ sdio_uart_change_speed(port, &tty->termios, old_termios);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
@@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func,
kfree(port);
} else {
struct device *dev;
- dev = tty_register_device(sdio_uart_tty_driver,
- port->index, &func->dev);
+ dev = tty_port_register_device(&port->port,
+ sdio_uart_tty_driver, port->index, &func->dev);
if (IS_ERR(dev)) {
sdio_uart_port_remove(port);
ret = PTR_ERR(dev);
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index a5999a74496a..87c0293a1eef 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -33,7 +33,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <plat/board.h>
#include <plat/mmc.h>
#include <asm/gpio.h>
#include <plat/dma.h>
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 3a09f93cc3b6..f871b31ece5a 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -40,7 +40,6 @@
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
-#include <plat/board.h>
#include <plat/mmc.h>
#include <plat/cpu.h>
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 861ca8f7e47d..78a524b49357 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -23,12 +23,16 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-omap.h>
+
#include <asm/io.h>
-#include <mach/hardware.h>
#include <asm/sizes.h>
-#include <linux/gpio.h>
+
#include <plat/board-ams-delta.h>
+#include <mach/hardware.h>
+
/*
* MTD structure for E3 (Delta)
*/
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ac4fd756eda3..27293e328517 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -101,6 +101,16 @@
#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0)
#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1)
+#define PREFETCH_CONFIG1_CS_SHIFT 24
+#define ECC_CONFIG_CS_SHIFT 1
+#define CS_MASK 0x7
+#define ENABLE_PREFETCH (0x1 << 7)
+#define DMA_MPU_MODE_SHIFT 2
+#define ECCSIZE1_SHIFT 22
+#define ECC1RESULTSIZE 0x1
+#define ECCCLEAR 0x100
+#define ECC1 0x1
+
/* oob info generated runtime depending on ecc algorithm and layout selected */
static struct nand_ecclayout omap_oobinfo;
/* Define some generic bad / good block scan pattern which are used
@@ -124,15 +134,18 @@ struct omap_nand_info {
int gpmc_cs;
unsigned long phys_base;
+ unsigned long mem_size;
struct completion comp;
struct dma_chan *dma;
- int gpmc_irq;
+ int gpmc_irq_fifo;
+ int gpmc_irq_count;
enum {
OMAP_NAND_IO_READ = 0, /* read */
OMAP_NAND_IO_WRITE, /* write */
} iomode;
u_char *buf;
int buf_len;
+ struct gpmc_nand_regs reg;
#ifdef CONFIG_MTD_NAND_OMAP_BCH
struct bch_control *bch;
@@ -141,6 +154,63 @@ struct omap_nand_info {
};
/**
+ * omap_prefetch_enable - configures and starts prefetch transfer
+ * @cs: cs (chip select) number
+ * @fifo_th: fifo threshold to be used for read/ write
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
+ unsigned int u32_count, int is_write, struct omap_nand_info *info)
+{
+ u32 val;
+
+ if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
+ return -1;
+
+ if (readl(info->reg.gpmc_prefetch_control))
+ return -EBUSY;
+
+ /* Set the amount of bytes to be prefetched */
+ writel(u32_count, info->reg.gpmc_prefetch_config2);
+
+ /* Set dma/mpu mode, the prefetch read / post write and
+ * enable the engine. Set which cs is has requested for.
+ */
+ val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
+ PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
+ (dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write));
+ writel(val, info->reg.gpmc_prefetch_config1);
+
+ /* Start the prefetch engine */
+ writel(0x1, info->reg.gpmc_prefetch_control);
+
+ return 0;
+}
+
+/**
+ * omap_prefetch_reset - disables and stops the prefetch engine
+ */
+static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
+{
+ u32 config1;
+
+ /* check if the same module/cs is trying to reset */
+ config1 = readl(info->reg.gpmc_prefetch_config1);
+ if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
+ return -EINVAL;
+
+ /* Stop the PFPW engine */
+ writel(0x0, info->reg.gpmc_prefetch_control);
+
+ /* Reset/disable the PFPW engine */
+ writel(0x0, info->reg.gpmc_prefetch_config1);
+
+ return 0;
+}
+
+/**
* omap_hwcontrol - hardware specific access to control-lines
* @mtd: MTD device structure
* @cmd: command to device
@@ -158,13 +228,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
- gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd);
+ writeb(cmd, info->reg.gpmc_nand_command);
else if (ctrl & NAND_ALE)
- gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd);
+ writeb(cmd, info->reg.gpmc_nand_address);
else /* NAND_NCE */
- gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd);
+ writeb(cmd, info->reg.gpmc_nand_data);
}
}
@@ -198,7 +268,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
iowrite8(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
- status = gpmc_read_status(GPMC_STATUS_BUFFER);
+ status = readl(info->reg.gpmc_status) &
+ GPMC_STATUS_BUFF_EMPTY;
} while (!status);
}
}
@@ -235,7 +306,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
iowrite16(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
- status = gpmc_read_status(GPMC_STATUS_BUFFER);
+ status = readl(info->reg.gpmc_status) &
+ GPMC_STATUS_BUFF_EMPTY;
} while (!status);
}
}
@@ -265,8 +337,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
}
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs,
- PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
+ ret = omap_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@@ -275,14 +347,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
omap_read_buf8(mtd, (u_char *)p, len);
} else {
do {
- r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ r_count = readl(info->reg.gpmc_prefetch_status);
+ r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
r_count = r_count >> 2;
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
p += r_count;
len -= r_count << 2;
} while (len);
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset(info->gpmc_cs);
+ omap_prefetch_reset(info->gpmc_cs, info);
}
}
@@ -301,6 +374,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
int i = 0, ret = 0;
u16 *p = (u16 *)buf;
unsigned long tim, limit;
+ u32 val;
/* take care of subpage writes */
if (len % 2 != 0) {
@@ -310,8 +384,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
}
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs,
- PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
+ ret = omap_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@@ -320,7 +394,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
omap_write_buf8(mtd, (u_char *)p, len);
} else {
while (len) {
- w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ w_count = readl(info->reg.gpmc_prefetch_status);
+ w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
w_count = w_count >> 1;
for (i = 0; (i < w_count) && len; i++, len -= 2)
iowrite16(*p++, info->nand.IO_ADDR_W);
@@ -329,11 +404,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
tim = 0;
limit = (loops_per_jiffy *
msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
- while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+ do {
cpu_relax();
+ val = readl(info->reg.gpmc_prefetch_status);
+ val = GPMC_PREFETCH_STATUS_COUNT(val);
+ } while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset(info->gpmc_cs);
+ omap_prefetch_reset(info->gpmc_cs, info);
}
}
@@ -365,6 +443,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
unsigned long tim, limit;
unsigned n;
int ret;
+ u32 val;
if (addr >= high_memory) {
struct page *p1;
@@ -396,9 +475,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
tx->callback_param = &info->comp;
dmaengine_submit(tx);
- /* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs,
- PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write);
+ /* configure and start prefetch transfer */
+ ret = omap_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy_unmap;
@@ -410,11 +489,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
wait_for_completion(&info->comp);
tim = 0;
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
- while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+
+ do {
cpu_relax();
+ val = readl(info->reg.gpmc_prefetch_status);
+ val = GPMC_PREFETCH_STATUS_COUNT(val);
+ } while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset(info->gpmc_cs);
+ omap_prefetch_reset(info->gpmc_cs, info);
dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
return 0;
@@ -471,13 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
{
struct omap_nand_info *info = (struct omap_nand_info *) dev;
u32 bytes;
- u32 irq_stat;
- irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS);
- bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ bytes = readl(info->reg.gpmc_prefetch_status);
+ bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes);
bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */
if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
- if (irq_stat & 0x2)
+ if (this_irq == info->gpmc_irq_count)
goto done;
if (info->buf_len && (info->buf_len < bytes))
@@ -494,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
(u32 *)info->buf, bytes >> 2);
info->buf = info->buf + bytes;
- if (irq_stat & 0x2)
+ if (this_irq == info->gpmc_irq_count)
goto done;
}
- gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
return IRQ_HANDLED;
done:
complete(&info->comp);
- /* disable irq */
- gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0);
- /* clear status */
- gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
+ disable_irq_nosync(info->gpmc_irq_fifo);
+ disable_irq_nosync(info->gpmc_irq_count);
return IRQ_HANDLED;
}
@@ -534,22 +613,22 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
init_completion(&info->comp);
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs,
- PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0);
+ ret = omap_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy;
info->buf_len = len;
- /* enable irq */
- gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
- (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
+
+ enable_irq(info->gpmc_irq_count);
+ enable_irq(info->gpmc_irq_fifo);
/* waiting for read to complete */
wait_for_completion(&info->comp);
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset(info->gpmc_cs);
+ omap_prefetch_reset(info->gpmc_cs, info);
return;
out_copy:
@@ -572,6 +651,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
struct omap_nand_info, mtd);
int ret = 0;
unsigned long tim, limit;
+ u32 val;
if (len <= mtd->oobsize) {
omap_write_buf_pref(mtd, buf, len);
@@ -583,27 +663,31 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
init_completion(&info->comp);
/* configure and start prefetch transfer : size=24 */
- ret = gpmc_prefetch_enable(info->gpmc_cs,
- (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1);
+ ret = omap_prefetch_enable(info->gpmc_cs,
+ (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy;
info->buf_len = len;
- /* enable irq */
- gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
- (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
+
+ enable_irq(info->gpmc_irq_count);
+ enable_irq(info->gpmc_irq_fifo);
/* waiting for write to complete */
wait_for_completion(&info->comp);
+
/* wait for data to flushed-out before reset the prefetch */
tim = 0;
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
- while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+ do {
+ val = readl(info->reg.gpmc_prefetch_status);
+ val = GPMC_PREFETCH_STATUS_COUNT(val);
cpu_relax();
+ } while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
- gpmc_prefetch_reset(info->gpmc_cs);
+ omap_prefetch_reset(info->gpmc_cs, info);
return;
out_copy:
@@ -843,7 +927,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
{
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
- return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code);
+ u32 val;
+
+ val = readl(info->reg.gpmc_ecc_config);
+ if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs)
+ return -EINVAL;
+
+ /* read ecc result */
+ val = readl(info->reg.gpmc_ecc1_result);
+ *ecc_code++ = val; /* P128e, ..., P1e */
+ *ecc_code++ = val >> 16; /* P128o, ..., P1o */
+ /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+ *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+
+ return 0;
}
/**
@@ -857,8 +954,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
mtd);
struct nand_chip *chip = mtd->priv;
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+ u32 val;
+
+ /* clear ecc and enable bits */
+ val = ECCCLEAR | ECC1;
+ writel(val, info->reg.gpmc_ecc_control);
+
+ /* program ecc and result sizes */
+ val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
+ ECC1RESULTSIZE);
+ writel(val, info->reg.gpmc_ecc_size_config);
- gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size);
+ switch (mode) {
+ case NAND_ECC_READ:
+ case NAND_ECC_WRITE:
+ writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
+ break;
+ case NAND_ECC_READSYN:
+ writel(ECCCLEAR, info->reg.gpmc_ecc_control);
+ break;
+ default:
+ dev_info(&info->pdev->dev,
+ "error: unrecognized Mode[%d]!\n", mode);
+ break;
+ }
+
+ /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
+ val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+ writel(val, info->reg.gpmc_ecc_config);
}
/**
@@ -886,10 +1009,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
else
timeo += (HZ * 20) / 1000;
- gpmc_nand_write(info->gpmc_cs,
- GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF));
+ writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) {
- status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
+ status = readb(info->reg.gpmc_nand_data);
if (status & NAND_STATUS_READY)
break;
cond_resched();
@@ -909,22 +1031,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
- val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
+ val = readl(info->reg.gpmc_status);
+
if ((val & 0x100) == 0x100) {
- /* Clear IRQ Interrupt */
- val |= 0x100;
- val &= ~(0x0);
- gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val);
+ return 1;
} else {
- unsigned int cnt = 0;
- while (cnt++ < 0x1FF) {
- if ((val & 0x100) == 0x100)
- return 0;
- val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
- }
+ return 0;
}
-
- return 1;
}
#ifdef CONFIG_MTD_NAND_OMAP_BCH
@@ -1155,6 +1268,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
int i, offset;
dma_cap_mask_t mask;
unsigned sig;
+ struct resource *res;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -1174,7 +1288,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->pdev = pdev;
info->gpmc_cs = pdata->cs;
- info->phys_base = pdata->phys_base;
+ info->reg = pdata->reg;
info->mtd.priv = &info->nand;
info->mtd.name = dev_name(&pdev->dev);
@@ -1183,16 +1297,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.options = pdata->devsize;
info->nand.options |= NAND_SKIP_BBTSCAN;
- /* NAND write protect off */
- gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "error getting memory resource\n");
+ goto out_free_info;
+ }
+
+ info->phys_base = res->start;
+ info->mem_size = resource_size(res);
- if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
+ if (!request_mem_region(info->phys_base, info->mem_size,
pdev->dev.driver->name)) {
err = -EBUSY;
goto out_free_info;
}
- info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
+ info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size);
if (!info->nand.IO_ADDR_R) {
err = -ENOMEM;
goto out_release_mem_region;
@@ -1265,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
break;
case NAND_OMAP_PREFETCH_IRQ:
- err = request_irq(pdata->gpmc_irq,
- omap_nand_irq, IRQF_SHARED, "gpmc-nand", info);
+ info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
+ if (info->gpmc_irq_fifo <= 0) {
+ dev_err(&pdev->dev, "error getting fifo irq\n");
+ err = -ENODEV;
+ goto out_release_mem_region;
+ }
+ err = request_irq(info->gpmc_irq_fifo, omap_nand_irq,
+ IRQF_SHARED, "gpmc-nand-fifo", info);
if (err) {
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
- pdata->gpmc_irq, err);
+ info->gpmc_irq_fifo, err);
+ info->gpmc_irq_fifo = 0;
+ goto out_release_mem_region;
+ }
+
+ info->gpmc_irq_count = platform_get_irq(pdev, 1);
+ if (info->gpmc_irq_count <= 0) {
+ dev_err(&pdev->dev, "error getting count irq\n");
+ err = -ENODEV;
+ goto out_release_mem_region;
+ }
+ err = request_irq(info->gpmc_irq_count, omap_nand_irq,
+ IRQF_SHARED, "gpmc-nand-count", info);
+ if (err) {
+ dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+ info->gpmc_irq_count, err);
+ info->gpmc_irq_count = 0;
goto out_release_mem_region;
- } else {
- info->gpmc_irq = pdata->gpmc_irq;
- info->nand.read_buf = omap_read_buf_irq_pref;
- info->nand.write_buf = omap_write_buf_irq_pref;
}
+
+ info->nand.read_buf = omap_read_buf_irq_pref;
+ info->nand.write_buf = omap_write_buf_irq_pref;
+
break;
default:
@@ -1363,7 +1506,11 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
out_release_mem_region:
if (info->dma)
dma_release_channel(info->dma);
- release_mem_region(info->phys_base, NAND_IO_SIZE);
+ if (info->gpmc_irq_count > 0)
+ free_irq(info->gpmc_irq_count, info);
+ if (info->gpmc_irq_fifo > 0)
+ free_irq(info->gpmc_irq_fifo, info);
+ release_mem_region(info->phys_base, info->mem_size);
out_free_info:
kfree(info);
@@ -1381,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev)
if (info->dma)
dma_release_channel(info->dma);
- if (info->gpmc_irq)
- free_irq(info->gpmc_irq, info);
+ if (info->gpmc_irq_count > 0)
+ free_irq(info->gpmc_irq_count, info);
+ if (info->gpmc_irq_fifo > 0)
+ free_irq(info->gpmc_irq_fifo, info);
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 252aaefcacfa..d944d6ef7da8 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -22,6 +22,8 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <mach/dma.h>
#include <plat/pxa3xx_nand.h>
@@ -1032,7 +1034,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
struct pxa3xx_nand_platform_data *pdata;
struct pxa3xx_nand_info *info;
struct pxa3xx_nand_host *host;
- struct nand_chip *chip;
+ struct nand_chip *chip = NULL;
struct mtd_info *mtd;
struct resource *r;
int ret, irq, cs;
@@ -1081,21 +1083,31 @@ static int alloc_nand_resource(struct platform_device *pdev)
}
clk_enable(info->clk);
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no resource defined for data DMA\n");
- ret = -ENXIO;
- goto fail_put_clk;
- }
- info->drcmr_dat = r->start;
+ /*
+ * This is a dirty hack to make this driver work from devicetree
+ * bindings. It can be removed once we have a prober DMA controller
+ * framework for DT.
+ */
+ if (pdev->dev.of_node && cpu_is_pxa3xx()) {
+ info->drcmr_dat = 97;
+ info->drcmr_cmd = 99;
+ } else {
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no resource defined for data DMA\n");
+ ret = -ENXIO;
+ goto fail_put_clk;
+ }
+ info->drcmr_dat = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (r == NULL) {
- dev_err(&pdev->dev, "no resource defined for command DMA\n");
- ret = -ENXIO;
- goto fail_put_clk;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r == NULL) {
+ dev_err(&pdev->dev, "no resource defined for command DMA\n");
+ ret = -ENXIO;
+ goto fail_put_clk;
+ }
+ info->drcmr_cmd = r->start;
}
- info->drcmr_cmd = r->start;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -1200,12 +1212,55 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static struct of_device_id pxa3xx_nand_dt_ids[] = {
+ { .compatible = "marvell,pxa3xx-nand" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
+{
+ struct pxa3xx_nand_platform_data *pdata;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+
+ if (!of_id)
+ return 0;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
+ pdata->enable_arbiter = 1;
+ if (of_get_property(np, "marvell,nand-keep-config", NULL))
+ pdata->keep_config = 1;
+ of_property_read_u32(np, "num-cs", &pdata->num_cs);
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static inline int pxa3xx_nand_probe_dt(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
static int pxa3xx_nand_probe(struct platform_device *pdev)
{
struct pxa3xx_nand_platform_data *pdata;
+ struct mtd_part_parser_data ppdata = {};
struct pxa3xx_nand_info *info;
int ret, cs, probe_success;
+ ret = pxa3xx_nand_probe_dt(pdev);
+ if (ret)
+ return ret;
+
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
@@ -1229,8 +1284,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
continue;
}
+ ppdata.of_node = pdev->dev.of_node;
ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
- NULL, pdata->parts[cs],
+ &ppdata, pdata->parts[cs],
pdata->nr_parts[cs]);
if (!ret)
probe_success = 1;
@@ -1306,6 +1362,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
static struct platform_driver pxa3xx_nand_driver = {
.driver = {
.name = "pxa3xx-nand",
+ .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids),
},
.probe = pxa3xx_nand_probe,
.remove = pxa3xx_nand_remove,
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index 398a82783848..9d49b1f4ff53 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -43,18 +43,17 @@
#include <asm/gpio.h>
#include <plat/dma.h>
-
-#include <plat/board.h>
+#include <plat/cpu.h>
#define DRIVER_NAME "omap2-onenand"
-#define ONENAND_IO_SIZE SZ_128K
#define ONENAND_BUFRAM_SIZE (1024 * 5)
struct omap2_onenand {
struct platform_device *pdev;
int gpmc_cs;
unsigned long phys_base;
+ unsigned int mem_size;
int gpio_irq;
struct mtd_info mtd;
struct onenand_chip onenand;
@@ -626,6 +625,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
struct omap2_onenand *c;
struct onenand_chip *this;
int r;
+ struct resource *res;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -647,20 +647,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
c->gpio_irq = 0;
}
- r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
- if (r < 0) {
- dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ r = -EINVAL;
+ dev_err(&pdev->dev, "error getting memory resource\n");
goto err_kfree;
}
- if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
+ c->phys_base = res->start;
+ c->mem_size = resource_size(res);
+
+ if (request_mem_region(c->phys_base, c->mem_size,
pdev->dev.driver->name) == NULL) {
- dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
- "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
+ dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
+ c->phys_base, c->mem_size);
r = -EBUSY;
- goto err_free_cs;
+ goto err_kfree;
}
- c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
+ c->onenand.base = ioremap(c->phys_base, c->mem_size);
if (c->onenand.base == NULL) {
r = -ENOMEM;
goto err_release_mem_region;
@@ -776,9 +780,7 @@ err_release_gpio:
err_iounmap:
iounmap(c->onenand.base);
err_release_mem_region:
- release_mem_region(c->phys_base, ONENAND_IO_SIZE);
-err_free_cs:
- gpmc_cs_free(c->gpmc_cs);
+ release_mem_region(c->phys_base, c->mem_size);
err_kfree:
kfree(c);
@@ -800,7 +802,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
gpio_free(c->gpio_irq);
}
iounmap(c->onenand.base);
- release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+ release_mem_region(c->phys_base, c->mem_size);
gpmc_cs_free(c->gpmc_cs);
kfree(c);
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index a580db29e503..26e7129332ab 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -83,6 +83,11 @@
#define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n))
#define INSTRUCTION_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94)
#define INSTRUCTION_RESET 0xC0
+#define RTS_TXB0 0x01
+#define RTS_TXB1 0x02
+#define RTS_TXB2 0x04
+#define INSTRUCTION_RTS(n) (0x80 | ((n) & 0x07))
+
/* MPC251x registers */
#define CANSTAT 0x0e
@@ -397,6 +402,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
int tx_buf_idx)
{
+ struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
u32 sid, eid, exide, rtr;
u8 buf[SPI_TRANSFER_BUF_LEN];
@@ -418,7 +424,10 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
buf[TXBDLC_OFF] = (rtr << DLC_RTR_SHIFT) | frame->can_dlc;
memcpy(buf + TXBDAT_OFF, frame->data, frame->can_dlc);
mcp251x_hw_tx_frame(spi, buf, frame->can_dlc, tx_buf_idx);
- mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx), TXBCTRL_TXREQ);
+
+ /* use INSTRUCTION_RTS, to avoid "repeated frame problem" */
+ priv->spi_tx_buf[0] = INSTRUCTION_RTS(1 << tx_buf_idx);
+ mcp251x_spi_trans(priv->spi, 1);
}
static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 21b553229ea4..dfd86a55f1dc 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -710,17 +710,15 @@ static inline u16 bnx2x_tx_avail(struct bnx2x *bp,
prod = txdata->tx_bd_prod;
cons = txdata->tx_bd_cons;
- /* NUM_TX_RINGS = number of "next-page" entries
- It will be used as a threshold */
- used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS;
+ used = SUB_S16(prod, cons);
#ifdef BNX2X_STOP_ON_ERROR
WARN_ON(used < 0);
- WARN_ON(used > bp->tx_ring_size);
- WARN_ON((bp->tx_ring_size - used) > MAX_TX_AVAIL);
+ WARN_ON(used > txdata->tx_ring_size);
+ WARN_ON((txdata->tx_ring_size - used) > MAX_TX_AVAIL);
#endif
- return (s16)(bp->tx_ring_size) - used;
+ return (s16)(txdata->tx_ring_size) - used;
}
static inline int bnx2x_tx_queue_has_work(struct bnx2x_fp_txdata *txdata)
@@ -1088,6 +1086,7 @@ static inline void bnx2x_init_txdata(struct bnx2x *bp,
txdata->txq_index = txq_index;
txdata->tx_cons_sb = tx_cons_sb;
txdata->parent_fp = fp;
+ txdata->tx_ring_size = IS_FCOE_FP(fp) ? MAX_TX_AVAIL : bp->tx_ring_size;
DP(NETIF_MSG_IFUP, "created tx data cid %d, txq %d\n",
txdata->cid, txdata->txq_index);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index 3e4cff9b1ebe..b926f58e983b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -401,11 +401,11 @@ static const struct reg_addr reg_addrs[] = {
{ 0x70000, 8, RI_ALL_ONLINE },
{ 0x70020, 8184, RI_ALL_OFFLINE },
{ 0x78000, 8192, RI_E3E3B0_OFFLINE },
- { 0x85000, 3, RI_ALL_ONLINE },
- { 0x8501c, 7, RI_ALL_ONLINE },
- { 0x85048, 1, RI_ALL_ONLINE },
- { 0x85200, 32, RI_ALL_ONLINE },
- { 0xb0000, 16384, RI_E1H_ONLINE },
+ { 0x85000, 3, RI_ALL_OFFLINE },
+ { 0x8501c, 7, RI_ALL_OFFLINE },
+ { 0x85048, 1, RI_ALL_OFFLINE },
+ { 0x85200, 32, RI_ALL_OFFLINE },
+ { 0xb0000, 16384, RI_E1H_OFFLINE },
{ 0xc1000, 7, RI_ALL_ONLINE },
{ 0xc103c, 2, RI_E2E3E3B0_ONLINE },
{ 0xc1800, 2, RI_ALL_ONLINE },
@@ -581,17 +581,12 @@ static const struct reg_addr reg_addrs[] = {
{ 0x140188, 3, RI_E1E1HE2E3_ONLINE },
{ 0x140194, 13, RI_ALL_ONLINE },
{ 0x140200, 6, RI_E1E1HE2E3_ONLINE },
- { 0x140220, 4, RI_E2E3_ONLINE },
- { 0x140240, 4, RI_E2E3_ONLINE },
{ 0x140260, 4, RI_E2E3_ONLINE },
{ 0x140280, 4, RI_E2E3_ONLINE },
- { 0x1402a0, 4, RI_E2E3_ONLINE },
- { 0x1402c0, 4, RI_E2E3_ONLINE },
{ 0x1402e0, 2, RI_E2E3_ONLINE },
{ 0x1402e8, 2, RI_E2E3E3B0_ONLINE },
{ 0x1402f0, 9, RI_E2E3_ONLINE },
{ 0x140314, 44, RI_E3B0_ONLINE },
- { 0x1403d0, 70, RI_E3B0_ONLINE },
{ 0x144000, 4, RI_E1E1H_ONLINE },
{ 0x148000, 4, RI_E1E1H_ONLINE },
{ 0x14c000, 4, RI_E1E1H_ONLINE },
@@ -704,7 +699,6 @@ static const struct reg_addr reg_addrs[] = {
{ 0x180398, 1, RI_E2E3E3B0_ONLINE },
{ 0x1803a0, 5, RI_E2E3E3B0_ONLINE },
{ 0x1803b4, 2, RI_E3E3B0_ONLINE },
- { 0x180400, 1, RI_ALL_ONLINE },
{ 0x180404, 255, RI_E1E1H_OFFLINE },
{ 0x181000, 4, RI_ALL_ONLINE },
{ 0x181010, 1020, RI_ALL_OFFLINE },
@@ -800,9 +794,9 @@ static const struct reg_addr reg_addrs[] = {
{ 0x1b905c, 1, RI_E3E3B0_ONLINE },
{ 0x1b9064, 1, RI_E3B0_ONLINE },
{ 0x1b9080, 10, RI_E3B0_ONLINE },
- { 0x1b9400, 14, RI_E2E3E3B0_ONLINE },
- { 0x1b943c, 19, RI_E2E3E3B0_ONLINE },
- { 0x1b9490, 10, RI_E2E3E3B0_ONLINE },
+ { 0x1b9400, 14, RI_E2E3E3B0_OFFLINE },
+ { 0x1b943c, 19, RI_E2E3E3B0_OFFLINE },
+ { 0x1b9490, 10, RI_E2E3E3B0_OFFLINE },
{ 0x1c0000, 2, RI_ALL_ONLINE },
{ 0x200000, 65, RI_ALL_ONLINE },
{ 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE },
@@ -814,7 +808,6 @@ static const struct reg_addr reg_addrs[] = {
{ 0x200398, 1, RI_E2E3E3B0_ONLINE },
{ 0x2003a0, 1, RI_E2E3E3B0_ONLINE },
{ 0x2003a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x200400, 1, RI_ALL_ONLINE },
{ 0x200404, 255, RI_E1E1H_OFFLINE },
{ 0x202000, 4, RI_ALL_ONLINE },
{ 0x202010, 2044, RI_ALL_OFFLINE },
@@ -921,7 +914,6 @@ static const struct reg_addr reg_addrs[] = {
{ 0x280398, 1, RI_E2E3E3B0_ONLINE },
{ 0x2803a0, 1, RI_E2E3E3B0_ONLINE },
{ 0x2803a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x280400, 1, RI_ALL_ONLINE },
{ 0x280404, 255, RI_E1E1H_OFFLINE },
{ 0x282000, 4, RI_ALL_ONLINE },
{ 0x282010, 2044, RI_ALL_OFFLINE },
@@ -1031,7 +1023,6 @@ static const struct reg_addr reg_addrs[] = {
{ 0x300398, 1, RI_E2E3E3B0_ONLINE },
{ 0x3003a0, 1, RI_E2E3E3B0_ONLINE },
{ 0x3003a8, 2, RI_E2E3E3B0_ONLINE },
- { 0x300400, 1, RI_ALL_ONLINE },
{ 0x300404, 255, RI_E1E1H_OFFLINE },
{ 0x302000, 4, RI_ALL_ONLINE },
{ 0x302010, 2044, RI_ALL_OFFLINE },
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index c37a68d68090..ebf40cd7aa10 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -775,7 +775,7 @@ static void bnx2x_get_regs(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
struct dump_hdr dump_hdr = {0};
- regs->version = 0;
+ regs->version = 1;
memset(p, 0, regs->len);
if (!netif_running(bp->dev))
@@ -1587,6 +1587,12 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
bp->link_params.req_flow_ctrl[cfg_idx] =
BNX2X_FLOW_CTRL_AUTO;
}
+ bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_NONE;
+ if (epause->rx_pause)
+ bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX;
+
+ if (epause->tx_pause)
+ bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX;
}
DP(BNX2X_MSG_ETHTOOL,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index f4beb46c4709..b046beb435b2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -2667,9 +2667,11 @@ int bnx2x_update_pfc(struct link_params *params,
return bnx2x_status;
DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n");
- if (CHIP_IS_E3(bp))
- bnx2x_update_pfc_xmac(params, vars, 0);
- else {
+
+ if (CHIP_IS_E3(bp)) {
+ if (vars->mac_type == MAC_TYPE_XMAC)
+ bnx2x_update_pfc_xmac(params, vars, 0);
+ } else {
val = REG_RD(bp, MISC_REG_RESET_REG_2);
if ((val &
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
@@ -5432,7 +5434,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
switch (speed_mask) {
case GP_STATUS_10M:
vars->line_speed = SPEED_10;
- if (vars->duplex == DUPLEX_FULL)
+ if (is_duplex == DUPLEX_FULL)
vars->link_status |= LINK_10TFD;
else
vars->link_status |= LINK_10THD;
@@ -5440,7 +5442,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
case GP_STATUS_100M:
vars->line_speed = SPEED_100;
- if (vars->duplex == DUPLEX_FULL)
+ if (is_duplex == DUPLEX_FULL)
vars->link_status |= LINK_100TXFD;
else
vars->link_status |= LINK_100TXHD;
@@ -5449,7 +5451,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
case GP_STATUS_1G:
case GP_STATUS_1G_KX:
vars->line_speed = SPEED_1000;
- if (vars->duplex == DUPLEX_FULL)
+ if (is_duplex == DUPLEX_FULL)
vars->link_status |= LINK_1000TFD;
else
vars->link_status |= LINK_1000THD;
@@ -5457,7 +5459,7 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
case GP_STATUS_2_5G:
vars->line_speed = SPEED_2500;
- if (vars->duplex == DUPLEX_FULL)
+ if (is_duplex == DUPLEX_FULL)
vars->link_status |= LINK_2500TFD;
else
vars->link_status |= LINK_2500THD;
@@ -5531,6 +5533,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
if (SINGLE_MEDIA_DIRECT(params)) {
+ vars->duplex = duplex;
bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
if (phy->req_line_speed == SPEED_AUTO_NEG)
bnx2x_xgxs_an_resolve(phy, params, vars,
@@ -5625,6 +5628,7 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
LINK_STATUS_PARALLEL_DETECTION_USED;
}
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+ vars->duplex = duplex;
}
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 21054987257a..211753e01f81 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -7561,8 +7561,14 @@ int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac,
}
rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
- if (rc < 0)
+
+ if (rc == -EEXIST) {
+ DP(BNX2X_MSG_SP, "Failed to schedule ADD operations: %d\n", rc);
+ /* do not treat adding same MAC as error */
+ rc = 0;
+ } else if (rc < 0)
BNX2X_ERR("%s MAC failed\n", (set ? "Set" : "Del"));
+
return rc;
}
@@ -10294,13 +10300,11 @@ static void __devinit bnx2x_get_fcoe_info(struct bnx2x *bp)
dev_info.port_hw_config[port].
fcoe_wwn_node_name_lower);
} else if (!IS_MF_SD(bp)) {
- u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg);
-
/*
* Read the WWN info only if the FCoE feature is enabled for
* this function.
*/
- if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD)
+ if (BNX2X_MF_EXT_PROTOCOL_FCOE(bp) && !CHIP_IS_E1x(bp))
bnx2x_get_ext_wwn_info(bp, func);
} else if (IS_MF_FCOE_SD(bp))
@@ -11073,7 +11077,14 @@ static int bnx2x_set_uc_list(struct bnx2x *bp)
netdev_for_each_uc_addr(ha, dev) {
rc = bnx2x_set_mac_one(bp, bnx2x_uc_addr(ha), mac_obj, true,
BNX2X_UC_LIST_MAC, &ramrod_flags);
- if (rc < 0) {
+ if (rc == -EEXIST) {
+ DP(BNX2X_MSG_SP,
+ "Failed to schedule ADD operations: %d\n", rc);
+ /* do not treat adding same MAC as error */
+ rc = 0;
+
+ } else if (rc < 0) {
+
BNX2X_ERR("Failed to schedule ADD operations: %d\n",
rc);
return rc;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 332db64dd5be..a1d0446b39b3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -101,6 +101,11 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
if (CHIP_REV_IS_SLOW(bp))
return;
+ /* Update MCP's statistics if possible */
+ if (bp->func_stx)
+ memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats,
+ sizeof(bp->func_stats));
+
/* loader */
if (bp->executer_idx) {
int loader_idx = PMF_DMAE_C(bp);
@@ -128,8 +133,6 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
} else if (bp->func_stx) {
*stats_comp = 0;
- memcpy(bnx2x_sp(bp, func_stats), &bp->func_stats,
- sizeof(bp->func_stats));
bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
}
}
@@ -1151,9 +1154,11 @@ static void bnx2x_stats_update(struct bnx2x *bp)
if (bp->port.pmf)
bnx2x_hw_stats_update(bp);
- if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) {
- BNX2X_ERR("storm stats were not updated for 3 times\n");
- bnx2x_panic();
+ if (bnx2x_storm_stats_update(bp)) {
+ if (bp->stats_pending++ == 3) {
+ BNX2X_ERR("storm stats were not updated for 3 times\n");
+ bnx2x_panic();
+ }
return;
}
diff --git a/drivers/net/ethernet/i825xx/znet.c b/drivers/net/ethernet/i825xx/znet.c
index bd1f1ef91e19..ba4e0cea3506 100644
--- a/drivers/net/ethernet/i825xx/znet.c
+++ b/drivers/net/ethernet/i825xx/znet.c
@@ -139,8 +139,11 @@ struct znet_private {
/* Only one can be built-in;-> */
static struct net_device *znet_dev;
+#define NETIDBLK_MAGIC "NETIDBLK"
+#define NETIDBLK_MAGIC_SIZE 8
+
struct netidblk {
- char magic[8]; /* The magic number (string) "NETIDBLK" */
+ char magic[NETIDBLK_MAGIC_SIZE]; /* The magic number (string) "NETIDBLK" */
unsigned char netid[8]; /* The physical station address */
char nettype, globalopt;
char vendor[8]; /* The machine vendor and product name. */
@@ -373,14 +376,16 @@ static int __init znet_probe (void)
struct znet_private *znet;
struct net_device *dev;
char *p;
+ char *plast = phys_to_virt(0x100000 - NETIDBLK_MAGIC_SIZE);
int err = -ENOMEM;
/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
- for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
- if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0)
+ for(p = (char *)phys_to_virt(0xf0000); p <= plast; p++)
+ if (*p == 'N' &&
+ strncmp(p, NETIDBLK_MAGIC, NETIDBLK_MAGIC_SIZE) == 0)
break;
- if (p >= (char *)phys_to_virt(0x100000)) {
+ if (p > plast) {
if (znet_debug > 1)
printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
return -ENODEV;
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 9010cea68bc3..b68d28a130e6 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -472,14 +472,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
}
if (adapter->rx_queue.queue_addr != NULL) {
- if (!dma_mapping_error(dev, adapter->rx_queue.queue_dma)) {
- dma_unmap_single(dev,
- adapter->rx_queue.queue_dma,
- adapter->rx_queue.queue_len,
- DMA_BIDIRECTIONAL);
- adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
- }
- kfree(adapter->rx_queue.queue_addr);
+ dma_free_coherent(dev, adapter->rx_queue.queue_len,
+ adapter->rx_queue.queue_addr,
+ adapter->rx_queue.queue_dma);
adapter->rx_queue.queue_addr = NULL;
}
@@ -556,10 +551,13 @@ static int ibmveth_open(struct net_device *netdev)
goto err_out;
}
+ dev = &adapter->vdev->dev;
+
adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) *
rxq_entries;
- adapter->rx_queue.queue_addr = kmalloc(adapter->rx_queue.queue_len,
- GFP_KERNEL);
+ adapter->rx_queue.queue_addr =
+ dma_alloc_coherent(dev, adapter->rx_queue.queue_len,
+ &adapter->rx_queue.queue_dma, GFP_KERNEL);
if (!adapter->rx_queue.queue_addr) {
netdev_err(netdev, "unable to allocate rx queue pages\n");
@@ -567,19 +565,13 @@ static int ibmveth_open(struct net_device *netdev)
goto err_out;
}
- dev = &adapter->vdev->dev;
-
adapter->buffer_list_dma = dma_map_single(dev,
adapter->buffer_list_addr, 4096, DMA_BIDIRECTIONAL);
adapter->filter_list_dma = dma_map_single(dev,
adapter->filter_list_addr, 4096, DMA_BIDIRECTIONAL);
- adapter->rx_queue.queue_dma = dma_map_single(dev,
- adapter->rx_queue.queue_addr,
- adapter->rx_queue.queue_len, DMA_BIDIRECTIONAL);
if ((dma_mapping_error(dev, adapter->buffer_list_dma)) ||
- (dma_mapping_error(dev, adapter->filter_list_dma)) ||
- (dma_mapping_error(dev, adapter->rx_queue.queue_dma))) {
+ (dma_mapping_error(dev, adapter->filter_list_dma))) {
netdev_err(netdev, "unable to map filter or buffer list "
"pages\n");
rc = -ENOMEM;
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 827b72dfce99..2f816c6aed72 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1234,13 +1234,13 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
mlx4_info(dev, "non-primary physical function, skipping.\n");
else
mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
- goto unmap_bf;
+ return err;
}
err = mlx4_load_fw(dev);
if (err) {
mlx4_err(dev, "Failed to start FW, aborting.\n");
- goto unmap_bf;
+ return err;
}
mlx4_cfg.log_pg_sz_m = 1;
@@ -1304,7 +1304,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
err = mlx4_init_slave(dev);
if (err) {
mlx4_err(dev, "Failed to initialize slave\n");
- goto unmap_bf;
+ return err;
}
err = mlx4_slave_cap(dev);
@@ -1324,7 +1324,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
err = mlx4_QUERY_ADAPTER(dev, &adapter);
if (err) {
mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n");
- goto err_close;
+ goto unmap_bf;
}
priv->eq_table.inta_pin = adapter.inta_pin;
@@ -1332,6 +1332,9 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
return 0;
+unmap_bf:
+ unmap_bf_area(dev);
+
err_close:
mlx4_close_hca(dev);
@@ -1344,8 +1347,6 @@ err_stop_fw:
mlx4_UNMAP_FA(dev);
mlx4_free_icm(dev, priv->fw.fw_icm, 0);
}
-unmap_bf:
- unmap_bf_area(dev);
return err;
}
@@ -1996,7 +1997,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
slave_start:
- if (mlx4_cmd_init(dev)) {
+ err = mlx4_cmd_init(dev);
+ if (err) {
mlx4_err(dev, "Failed to init command interface, aborting.\n");
goto err_sriov;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index a018ea2a43de..e151c21baf2b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -137,11 +137,11 @@ static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
return err;
}
-static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num,
+static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,
enum mlx4_steer_type steer,
u32 qpn)
{
- struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num];
+ struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[port - 1];
struct mlx4_promisc_qp *pqp;
list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
@@ -182,7 +182,7 @@ static int new_steering_entry(struct mlx4_dev *dev, u8 port,
/* If the given qpn is also a promisc qp,
* it should be inserted to duplicates list
*/
- pqp = get_promisc_qp(dev, 0, steer, qpn);
+ pqp = get_promisc_qp(dev, port, steer, qpn);
if (pqp) {
dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
if (!dqp) {
@@ -256,7 +256,7 @@ static int existing_steering_entry(struct mlx4_dev *dev, u8 port,
s_steer = &mlx4_priv(dev)->steer[port - 1];
- pqp = get_promisc_qp(dev, 0, steer, qpn);
+ pqp = get_promisc_qp(dev, port, steer, qpn);
if (!pqp)
return 0; /* nothing to do */
@@ -302,7 +302,7 @@ static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
s_steer = &mlx4_priv(dev)->steer[port - 1];
/* if qp is not promisc, it cannot be duplicated */
- if (!get_promisc_qp(dev, 0, steer, qpn))
+ if (!get_promisc_qp(dev, port, steer, qpn))
return false;
/* The qp is promisc qp so it is a duplicate on this index
@@ -352,7 +352,7 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
for (i = 0; i < members_count; i++) {
qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
- if (!get_promisc_qp(dev, 0, steer, qpn) && qpn != tqpn) {
+ if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
/* the qp is not promisc, the entry can't be removed */
goto out;
}
@@ -398,7 +398,7 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
mutex_lock(&priv->mcg_table.mutex);
- if (get_promisc_qp(dev, 0, steer, qpn)) {
+ if (get_promisc_qp(dev, port, steer, qpn)) {
err = 0; /* Noting to do, already exists */
goto out_mutex;
}
@@ -503,7 +503,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
s_steer = &mlx4_priv(dev)->steer[port - 1];
mutex_lock(&priv->mcg_table.mutex);
- pqp = get_promisc_qp(dev, 0, steer, qpn);
+ pqp = get_promisc_qp(dev, port, steer, qpn);
if (unlikely(!pqp)) {
mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
/* nothing to do */
@@ -650,13 +650,6 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
return err;
}
-struct mlx4_net_trans_rule_hw_ctrl {
- __be32 ctrl;
- __be32 vf_vep_port;
- __be32 qpn;
- __be32 reserved;
-};
-
static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
struct mlx4_net_trans_rule_hw_ctrl *hw)
{
@@ -680,87 +673,18 @@ static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
hw->qpn = cpu_to_be32(ctrl->qpn);
}
-struct mlx4_net_trans_rule_hw_ib {
- u8 size;
- u8 rsvd1;
- __be16 id;
- u32 rsvd2;
- __be32 qpn;
- __be32 qpn_mask;
- u8 dst_gid[16];
- u8 dst_gid_msk[16];
-} __packed;
-
-struct mlx4_net_trans_rule_hw_eth {
- u8 size;
- u8 rsvd;
- __be16 id;
- u8 rsvd1[6];
- u8 dst_mac[6];
- u16 rsvd2;
- u8 dst_mac_msk[6];
- u16 rsvd3;
- u8 src_mac[6];
- u16 rsvd4;
- u8 src_mac_msk[6];
- u8 rsvd5;
- u8 ether_type_enable;
- __be16 ether_type;
- __be16 vlan_id_msk;
- __be16 vlan_id;
-} __packed;
-
-struct mlx4_net_trans_rule_hw_tcp_udp {
- u8 size;
- u8 rsvd;
- __be16 id;
- __be16 rsvd1[3];
- __be16 dst_port;
- __be16 rsvd2;
- __be16 dst_port_msk;
- __be16 rsvd3;
- __be16 src_port;
- __be16 rsvd4;
- __be16 src_port_msk;
-} __packed;
-
-struct mlx4_net_trans_rule_hw_ipv4 {
- u8 size;
- u8 rsvd;
- __be16 id;
- __be32 rsvd1;
- __be32 dst_ip;
- __be32 dst_ip_msk;
- __be32 src_ip;
- __be32 src_ip_msk;
-} __packed;
-
-struct _rule_hw {
- union {
- struct {
- u8 size;
- u8 rsvd;
- __be16 id;
- };
- struct mlx4_net_trans_rule_hw_eth eth;
- struct mlx4_net_trans_rule_hw_ib ib;
- struct mlx4_net_trans_rule_hw_ipv4 ipv4;
- struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp;
- };
+const u16 __sw_id_hw[] = {
+ [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001,
+ [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005,
+ [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003,
+ [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002,
+ [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004,
+ [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006
};
static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
struct _rule_hw *rule_hw)
{
- static const u16 __sw_id_hw[] = {
- [MLX4_NET_TRANS_RULE_ID_ETH] = 0xE001,
- [MLX4_NET_TRANS_RULE_ID_IB] = 0xE005,
- [MLX4_NET_TRANS_RULE_ID_IPV6] = 0xE003,
- [MLX4_NET_TRANS_RULE_ID_IPV4] = 0xE002,
- [MLX4_NET_TRANS_RULE_ID_TCP] = 0xE004,
- [MLX4_NET_TRANS_RULE_ID_UDP] = 0xE006
- };
-
static const size_t __rule_hw_sz[] = {
[MLX4_NET_TRANS_RULE_ID_ETH] =
sizeof(struct mlx4_net_trans_rule_hw_eth),
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 4d9df8f2a126..dba69d98734a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -690,6 +690,82 @@ struct mlx4_steer {
struct list_head steer_entries[MLX4_NUM_STEERS];
};
+struct mlx4_net_trans_rule_hw_ctrl {
+ __be32 ctrl;
+ __be32 vf_vep_port;
+ __be32 qpn;
+ __be32 reserved;
+};
+
+struct mlx4_net_trans_rule_hw_ib {
+ u8 size;
+ u8 rsvd1;
+ __be16 id;
+ u32 rsvd2;
+ __be32 qpn;
+ __be32 qpn_mask;
+ u8 dst_gid[16];
+ u8 dst_gid_msk[16];
+} __packed;
+
+struct mlx4_net_trans_rule_hw_eth {
+ u8 size;
+ u8 rsvd;
+ __be16 id;
+ u8 rsvd1[6];
+ u8 dst_mac[6];
+ u16 rsvd2;
+ u8 dst_mac_msk[6];
+ u16 rsvd3;
+ u8 src_mac[6];
+ u16 rsvd4;
+ u8 src_mac_msk[6];
+ u8 rsvd5;
+ u8 ether_type_enable;
+ __be16 ether_type;
+ __be16 vlan_id_msk;
+ __be16 vlan_id;
+} __packed;
+
+struct mlx4_net_trans_rule_hw_tcp_udp {
+ u8 size;
+ u8 rsvd;
+ __be16 id;
+ __be16 rsvd1[3];
+ __be16 dst_port;
+ __be16 rsvd2;
+ __be16 dst_port_msk;
+ __be16 rsvd3;
+ __be16 src_port;
+ __be16 rsvd4;
+ __be16 src_port_msk;
+} __packed;
+
+struct mlx4_net_trans_rule_hw_ipv4 {
+ u8 size;
+ u8 rsvd;
+ __be16 id;
+ __be32 rsvd1;
+ __be32 dst_ip;
+ __be32 dst_ip_msk;
+ __be32 src_ip;
+ __be32 src_ip_msk;
+} __packed;
+
+struct _rule_hw {
+ union {
+ struct {
+ u8 size;
+ u8 rsvd;
+ __be16 id;
+ };
+ struct mlx4_net_trans_rule_hw_eth eth;
+ struct mlx4_net_trans_rule_hw_ib ib;
+ struct mlx4_net_trans_rule_hw_ipv4 ipv4;
+ struct mlx4_net_trans_rule_hw_tcp_udp tcp_udp;
+ };
+};
+
struct mlx4_priv {
struct mlx4_dev dev;
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 94ceddd17ab2..293c9e820c49 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -42,6 +42,7 @@
#include <linux/mlx4/cmd.h>
#include <linux/mlx4/qp.h>
#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
#include "mlx4.h"
#include "fw.h"
@@ -2776,18 +2777,133 @@ ex_put:
return err;
}
+/*
+ * MAC validation for Flow Steering rules.
+ * VF can attach rules only with a mac address which is assigned to it.
+ */
+static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header,
+ struct list_head *rlist)
+{
+ struct mac_res *res, *tmp;
+ __be64 be_mac;
+
+ /* make sure it isn't multicast or broadcast mac*/
+ if (!is_multicast_ether_addr(eth_header->eth.dst_mac) &&
+ !is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
+ list_for_each_entry_safe(res, tmp, rlist, list) {
+ be_mac = cpu_to_be64(res->mac << 16);
+ if (!memcmp(&be_mac, eth_header->eth.dst_mac, ETH_ALEN))
+ return 0;
+ }
+ pr_err("MAC %pM doesn't belong to VF %d, Steering rule rejected\n",
+ eth_header->eth.dst_mac, slave);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * In case of missing eth header, append eth header with a MAC address
+ * assigned to the VF.
+ */
+static int add_eth_header(struct mlx4_dev *dev, int slave,
+ struct mlx4_cmd_mailbox *inbox,
+ struct list_head *rlist, int header_id)
+{
+ struct mac_res *res, *tmp;
+ u8 port;
+ struct mlx4_net_trans_rule_hw_ctrl *ctrl;
+ struct mlx4_net_trans_rule_hw_eth *eth_header;
+ struct mlx4_net_trans_rule_hw_ipv4 *ip_header;
+ struct mlx4_net_trans_rule_hw_tcp_udp *l4_header;
+ __be64 be_mac = 0;
+ __be64 mac_msk = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+ ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
+ port = be32_to_cpu(ctrl->vf_vep_port) & 0xff;
+ eth_header = (struct mlx4_net_trans_rule_hw_eth *)(ctrl + 1);
+
+ /* Clear a space in the inbox for eth header */
+ switch (header_id) {
+ case MLX4_NET_TRANS_RULE_ID_IPV4:
+ ip_header =
+ (struct mlx4_net_trans_rule_hw_ipv4 *)(eth_header + 1);
+ memmove(ip_header, eth_header,
+ sizeof(*ip_header) + sizeof(*l4_header));
+ break;
+ case MLX4_NET_TRANS_RULE_ID_TCP:
+ case MLX4_NET_TRANS_RULE_ID_UDP:
+ l4_header = (struct mlx4_net_trans_rule_hw_tcp_udp *)
+ (eth_header + 1);
+ memmove(l4_header, eth_header, sizeof(*l4_header));
+ break;
+ default:
+ return -EINVAL;
+ }
+ list_for_each_entry_safe(res, tmp, rlist, list) {
+ if (port == res->port) {
+ be_mac = cpu_to_be64(res->mac << 16);
+ break;
+ }
+ }
+ if (!be_mac) {
+ pr_err("Failed adding eth header to FS rule, Can't find matching MAC for port %d .\n",
+ port);
+ return -EINVAL;
+ }
+
+ memset(eth_header, 0, sizeof(*eth_header));
+ eth_header->size = sizeof(*eth_header) >> 2;
+ eth_header->id = cpu_to_be16(__sw_id_hw[MLX4_NET_TRANS_RULE_ID_ETH]);
+ memcpy(eth_header->dst_mac, &be_mac, ETH_ALEN);
+ memcpy(eth_header->dst_mac_msk, &mac_msk, ETH_ALEN);
+
+ return 0;
+
+}
+
int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd)
{
+
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+ struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
int err;
+ struct mlx4_net_trans_rule_hw_ctrl *ctrl;
+ struct _rule_hw *rule_header;
+ int header_id;
if (dev->caps.steering_mode !=
MLX4_STEERING_MODE_DEVICE_MANAGED)
return -EOPNOTSUPP;
+ ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
+ rule_header = (struct _rule_hw *)(ctrl + 1);
+ header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
+
+ switch (header_id) {
+ case MLX4_NET_TRANS_RULE_ID_ETH:
+ if (validate_eth_header_mac(slave, rule_header, rlist))
+ return -EINVAL;
+ break;
+ case MLX4_NET_TRANS_RULE_ID_IPV4:
+ case MLX4_NET_TRANS_RULE_ID_TCP:
+ case MLX4_NET_TRANS_RULE_ID_UDP:
+ pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n");
+ if (add_eth_header(dev, slave, inbox, rlist, header_id))
+ return -EINVAL;
+ vhcr->in_modifier +=
+ sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;
+ break;
+ default:
+ pr_err("Corrupted mailbox.\n");
+ return -EINVAL;
+ }
+
err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
vhcr->in_modifier, 0,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
diff --git a/drivers/net/ethernet/seeq/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c
index bb8c8222122b..4d15bf413bdc 100644
--- a/drivers/net/ethernet/seeq/sgiseeq.c
+++ b/drivers/net/ethernet/seeq/sgiseeq.c
@@ -751,6 +751,7 @@ static int __devinit sgiseeq_probe(struct platform_device *pdev)
sp->srings = sr;
sp->rx_desc = sp->srings->rxvector;
sp->tx_desc = sp->srings->txvector;
+ spin_lock_init(&sp->tx_lock);
/* A couple calculations now, saves many cycles later. */
setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS);
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index b5ba3084c7fc..3e5519a0acc7 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
{
#define COSMISC_CONSTANT 6
- struct uart_port port = {
- .irq = 0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 0,
- .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
-
- .membase = (unsigned char __iomem *) uart,
- .mapbase = (unsigned long) uart,
+ struct uart_8250_port port = {
+ .port = {
+ .irq = 0,
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = (22000000 << 1) / COSMISC_CONSTANT,
+
+ .membase = (unsigned char __iomem *) uart,
+ .mapbase = (unsigned long) uart,
+ }
};
unsigned char lcr;
@@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
uart->iu_scr = COSMISC_CONSTANT,
uart->iu_lcr = lcr;
uart->iu_lcr;
- serial8250_register_port(&port);
+ serial8250_register_8250_port(&port);
}
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 3352b2443e58..30087ca23a0f 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty;
mutex_lock(&tty->termios_mutex);
- old_termios = *(tty->termios);
- cflag = tty->termios->c_cflag;
+ old_termios = tty->termios;
+ cflag = tty->termios.c_cflag;
tty_encode_baud_rate(tty, speed, speed);
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
@@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
int cflag;
mutex_lock(&tty->termios_mutex);
- old_termios = *(tty->termios);
- cflag = tty->termios->c_cflag;
+ old_termios = tty->termios;
+ cflag = tty->termios.c_cflag;
if (stop)
cflag &= ~CREAD;
else
cflag |= CREAD;
- tty->termios->c_cflag = cflag;
+ tty->termios.c_cflag = cflag;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
mutex_unlock(&tty->termios_mutex);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 62f30b46fa42..605a4baa9b7b 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
struct hso_serial *serial = tty->driver_data;
- struct ktermios *termios;
if (!serial) {
printk(KERN_ERR "%s: no tty structures", __func__);
@@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
/*
* Fix up unsupported bits
*/
- termios = tty->termios;
- termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
+ tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
- termios->c_cflag &=
+ tty->termios.c_cflag &=
~(CSIZE /* no size */
| PARENB /* disable parity bit */
| CBAUD /* clear current baud rate */
| CBAUDEX); /* clear current buad rate */
- termios->c_cflag |= CS8; /* character size 8 bits */
+ tty->termios.c_cflag |= CS8; /* character size 8 bits */
/* baud rate 115200 */
tty_encode_baud_rate(tty, 115200, 115200);
@@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
if (old)
D5("Termios called with: cflags new[%d] - old[%d]",
- tty->termios->c_cflag, old->c_cflag);
+ tty->termios.c_cflag, old->c_cflag);
/* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags);
if (serial->port.count)
_hso_serial_set_termios(tty, old);
else
- tty->termios = old;
+ tty->termios = *old;
spin_unlock_irqrestore(&serial->serial_lock, flags);
/* done */
@@ -2289,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
if (minor < 0)
goto exit;
+ tty_port_init(&serial->port);
+
/* register our minor number */
- serial->parent->dev = tty_register_device(tty_drv, minor,
- &serial->parent->interface->dev);
+ serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
+ minor, &serial->parent->interface->dev);
dev = serial->parent->dev;
dev_set_drvdata(dev, serial->parent);
i = device_create_file(dev, &dev_attr_hsotype);
@@ -2300,7 +2300,6 @@ 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 */
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index adfab3fc5478..b1ba68f1a049 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -297,7 +297,7 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
if (ret < 0)
goto err;
- if (info->subdriver && info->subdriver->suspend)
+ if (intf == info->control && info->subdriver && info->subdriver->suspend)
ret = info->subdriver->suspend(intf, message);
if (ret < 0)
usbnet_resume(intf);
@@ -310,13 +310,14 @@ static int qmi_wwan_resume(struct usb_interface *intf)
struct usbnet *dev = usb_get_intfdata(intf);
struct qmi_wwan_state *info = (void *)&dev->data;
int ret = 0;
+ bool callsub = (intf == info->control && info->subdriver && info->subdriver->resume);
- if (info->subdriver && info->subdriver->resume)
+ if (callsub)
ret = info->subdriver->resume(intf);
if (ret < 0)
goto err;
ret = usbnet_resume(intf);
- if (ret < 0 && info->subdriver && info->subdriver->resume && info->subdriver->suspend)
+ if (ret < 0 && callsub && info->subdriver->suspend)
info->subdriver->suspend(intf, PMSG_SUSPEND);
err:
return ret;
@@ -398,7 +399,6 @@ static const struct usb_device_id products[] = {
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
{QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
- {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
{QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */
{QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */
{QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */
@@ -440,6 +440,7 @@ static const struct usb_device_id products[] = {
{QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */
{QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
{QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
+ {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
{QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */
{QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */
{QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index 7be49ea60b6d..8e22417fa6c1 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -656,7 +656,7 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
return -EIO;
}
- *datap = *attrdata;
+ *datap = le16_to_cpu(*attrdata);
kfree(attrdata);
return result;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index fd4b26d46fd5..fc9f578a1e25 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1201,19 +1201,26 @@ deferred:
}
EXPORT_SYMBOL_GPL(usbnet_start_xmit);
-static void rx_alloc_submit(struct usbnet *dev, gfp_t flags)
+static int rx_alloc_submit(struct usbnet *dev, gfp_t flags)
{
struct urb *urb;
int i;
+ int ret = 0;
/* don't refill the queue all at once */
for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
urb = usb_alloc_urb(0, flags);
if (urb != NULL) {
- if (rx_submit(dev, urb, flags) == -ENOLINK)
- return;
+ ret = rx_submit(dev, urb, flags);
+ if (ret)
+ goto err;
+ } else {
+ ret = -ENOMEM;
+ goto err;
}
}
+err:
+ return ret;
}
/*-------------------------------------------------------------------------*/
@@ -1257,7 +1264,8 @@ static void usbnet_bh (unsigned long param)
int temp = dev->rxq.qlen;
if (temp < RX_QLEN(dev)) {
- rx_alloc_submit(dev, GFP_ATOMIC);
+ if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK)
+ return;
if (temp != dev->rxq.qlen)
netif_dbg(dev, link, dev->net,
"rxqlen %d --> %d\n",
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index aaaca9aa2293..3f575afd8cfc 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 2c9f7d7ed4cc..0ed3846f9cbb 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -142,6 +142,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
};
int training_power;
int i, val;
+ u32 am2pm_mask = ah->paprd_ratemask;
if (IS_CHAN_2GHZ(ah->curchan))
training_power = ar9003_get_training_power_2g(ah);
@@ -158,10 +159,13 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
}
ah->paprd_training_power = training_power;
+ if (AR_SREV_9330(ah))
+ am2pm_mask = 0;
+
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
ah->paprd_ratemask);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
- ah->paprd_ratemask);
+ am2pm_mask);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
ah->paprd_ratemask_ht40);
@@ -782,6 +786,102 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
}
EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
+static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah,
+ struct ath9k_hw_cal_data *caldata,
+ int chain)
+{
+ u32 *pa_in = caldata->pa_table[chain];
+ int capdiv_offset, quick_drop_offset;
+ int capdiv2g, quick_drop;
+ int count = 0;
+ int i;
+
+ if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah))
+ return false;
+
+ capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G);
+
+ quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
+
+ if (quick_drop)
+ quick_drop -= 0x40;
+
+ for (i = 0; i < NUM_BIN + 1; i++) {
+ if (pa_in[i] == 1400)
+ count++;
+ }
+
+ if (AR_SREV_9485(ah)) {
+ if (pa_in[23] < 800) {
+ capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);
+ capdiv2g += capdiv_offset;
+ if (capdiv2g > 7) {
+ capdiv2g = 7;
+ if (pa_in[23] < 600) {
+ quick_drop++;
+ if (quick_drop > 0)
+ quick_drop = 0;
+ }
+ }
+ } else if (pa_in[23] == 1400) {
+ quick_drop_offset = min_t(int, count / 3, 2);
+ quick_drop += quick_drop_offset;
+ capdiv2g += quick_drop_offset / 2;
+
+ if (capdiv2g > 7)
+ capdiv2g = 7;
+
+ if (quick_drop > 0) {
+ quick_drop = 0;
+ capdiv2g -= quick_drop_offset;
+ if (capdiv2g < 0)
+ capdiv2g = 0;
+ }
+ } else {
+ return false;
+ }
+ } else if (AR_SREV_9330(ah)) {
+ if (pa_in[23] < 1000) {
+ capdiv_offset = (1000 - pa_in[23]) / 100;
+ capdiv2g += capdiv_offset;
+ if (capdiv_offset > 3) {
+ capdiv_offset = 1;
+ quick_drop--;
+ }
+
+ capdiv2g += capdiv_offset;
+ if (capdiv2g > 6)
+ capdiv2g = 6;
+ if (quick_drop < -4)
+ quick_drop = -4;
+ } else if (pa_in[23] == 1400) {
+ if (count > 3) {
+ quick_drop++;
+ capdiv2g -= count / 4;
+ if (quick_drop > -2)
+ quick_drop = -2;
+ } else {
+ capdiv2g--;
+ }
+
+ if (capdiv2g < 0)
+ capdiv2g = 0;
+ } else {
+ return false;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
+ AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g);
+ REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
+ AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
+ quick_drop);
+
+ return true;
+}
+
int ar9003_paprd_create_curve(struct ath_hw *ah,
struct ath9k_hw_cal_data *caldata, int chain)
{
@@ -817,6 +917,9 @@ int ar9003_paprd_create_curve(struct ath_hw *ah,
if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
status = -2;
+ if (ar9003_paprd_retrain_pa_in(ah, caldata, chain))
+ status = -EINPROGRESS;
+
REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 7bfbaf065a43..84d3d4956861 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -625,6 +625,10 @@
#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0)
#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc)
+#define AR_PHY_65NM_CH0_TXRF3 0x16048
+#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e
+#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1
+
#define AR_PHY_65NM_CH0_SYNTH4 0x1608c
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002)
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1)
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index bacdb8fb4ef4..9f83f71742a5 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -341,7 +341,8 @@ void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
{
struct ath_btcoex *btcoex = &sc->btcoex;
- ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
+ if (btcoex->hw_timer_enabled)
+ ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer);
}
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 60b6a9daff7e..48af40151d23 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -463,9 +463,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.spurchans[i][1] = AR_NO_SPUR;
}
- /* PAPRD needs some more work to be enabled */
- ah->config.paprd_disable = 1;
-
ah->config.rx_intr_mitigation = true;
ah->config.pcieSerDesWrite = true;
@@ -978,9 +975,6 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
else
imr_reg |= AR_IMR_TXOK;
- if (opmode == NL80211_IFTYPE_AP)
- imr_reg |= AR_IMR_MIB;
-
ENABLE_REGWRITE_BUFFER(ah);
REG_WRITE(ah, AR_IMR, imr_reg);
@@ -1778,6 +1772,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
/* Operating channel changed, reset channel calibration data */
memset(caldata, 0, sizeof(*caldata));
ath9k_init_nfcal_hist_buffer(ah, chan);
+ } else if (caldata) {
+ caldata->paprd_packet_sent = false;
}
ah->noise = ath9k_hw_getchan_noise(ah, chan);
@@ -2502,7 +2498,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->tx_desc_len = sizeof(struct ar9003_txc);
pCap->txs_len = sizeof(struct ar9003_txs);
if (!ah->config.paprd_disable &&
- ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+ ah->eep_ops->get_eeprom(ah, EEP_PAPRD) &&
+ !AR_SREV_9462(ah))
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
} else {
pCap->tx_desc_len = sizeof(struct ath_desc);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index ce7332c64efb..6599a75f01fe 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -405,6 +405,7 @@ struct ath9k_hw_cal_data {
int8_t iCoff;
int8_t qCoff;
bool rtt_done;
+ bool paprd_packet_sent;
bool paprd_done;
bool nfcal_pending;
bool nfcal_interference;
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index d4549e9aac5c..825a29cc9313 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -254,8 +254,9 @@ void ath_paprd_calibrate(struct work_struct *work)
int chain_ok = 0;
int chain;
int len = 1800;
+ int ret;
- if (!caldata)
+ if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done)
return;
ath9k_ps_wakeup(sc);
@@ -282,13 +283,6 @@ void ath_paprd_calibrate(struct work_struct *work)
continue;
chain_ok = 0;
-
- ath_dbg(common, CALIBRATE,
- "Sending PAPRD frame for thermal measurement on chain %d\n",
- chain);
- if (!ath_paprd_send_frame(sc, skb, chain))
- goto fail_paprd;
-
ar9003_paprd_setup_gain_table(ah, chain);
ath_dbg(common, CALIBRATE,
@@ -302,7 +296,13 @@ void ath_paprd_calibrate(struct work_struct *work)
break;
}
- if (ar9003_paprd_create_curve(ah, caldata, chain)) {
+ ret = ar9003_paprd_create_curve(ah, caldata, chain);
+ if (ret == -EINPROGRESS) {
+ ath_dbg(common, CALIBRATE,
+ "PAPRD curve on chain %d needs to be re-trained\n",
+ chain);
+ break;
+ } else if (ret) {
ath_dbg(common, CALIBRATE,
"PAPRD create curve failed on chain %d\n",
chain);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 2c9da6b2ecb1..0d4155aec48d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2018,6 +2018,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
+ if (sc->sc_ah->caldata)
+ sc->sc_ah->caldata->paprd_packet_sent = true;
+
if (!(tx_flags & ATH_TX_ERROR))
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index a299d42da8e7..58f89fa9c9f8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -519,7 +519,7 @@ static void brcmf_usb_tx_complete(struct urb *urb)
else
devinfo->bus_pub.bus->dstats.tx_errors++;
- dev_kfree_skb(req->skb);
+ brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
@@ -540,7 +540,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
devinfo->bus_pub.bus->dstats.rx_packets++;
} else {
devinfo->bus_pub.bus->dstats.rx_errors++;
- dev_kfree_skb(skb);
+ brcmu_pkt_buf_free_skb(skb);
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
return;
}
@@ -550,13 +550,15 @@ static void brcmf_usb_rx_complete(struct urb *urb)
if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
brcmf_dbg(ERROR, "rx protocol error\n");
brcmu_pkt_buf_free_skb(skb);
+ brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
devinfo->bus_pub.bus->dstats.rx_errors++;
} else {
brcmf_rx_packet(devinfo->dev, ifidx, skb);
brcmf_usb_rx_refill(devinfo, req);
}
} else {
- dev_kfree_skb(skb);
+ brcmu_pkt_buf_free_skb(skb);
+ brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
}
return;
@@ -581,14 +583,13 @@ static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->rx_pipe,
skb->data, skb_tailroom(skb), brcmf_usb_rx_complete,
req);
- req->urb->transfer_flags |= URB_ZERO_PACKET;
req->devinfo = devinfo;
+ brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
- if (ret == 0) {
- brcmf_usb_enq(devinfo, &devinfo->rx_postq, req);
- } else {
- dev_kfree_skb(req->skb);
+ if (ret) {
+ brcmf_usb_del_fromq(devinfo, req);
+ brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req);
}
@@ -683,23 +684,22 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq);
if (!req) {
+ brcmu_pkt_buf_free_skb(skb);
brcmf_dbg(ERROR, "no req to send\n");
return -ENOMEM;
}
- if (!req->urb) {
- brcmf_dbg(ERROR, "no urb for req %p\n", req);
- return -ENOBUFS;
- }
req->skb = skb;
req->devinfo = devinfo;
usb_fill_bulk_urb(req->urb, devinfo->usbdev, devinfo->tx_pipe,
skb->data, skb->len, brcmf_usb_tx_complete, req);
req->urb->transfer_flags |= URB_ZERO_PACKET;
+ brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
ret = usb_submit_urb(req->urb, GFP_ATOMIC);
- if (!ret) {
- brcmf_usb_enq(devinfo, &devinfo->tx_postq, req);
- } else {
+ if (ret) {
+ brcmf_dbg(ERROR, "brcmf_usb_tx usb_submit_urb FAILED\n");
+ brcmf_usb_del_fromq(devinfo, req);
+ brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req);
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 28c5fbb4af26..c36e92312443 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -1876,16 +1876,17 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
}
if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
- scb_val.val = cpu_to_le32(0);
+ memset(&scb_val, 0, sizeof(scb_val));
err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
sizeof(struct brcmf_scb_val_le));
- if (err)
+ if (err) {
WL_ERR("Could not get rssi (%d)\n", err);
-
- rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- WL_CONN("RSSI %d dBm\n", rssi);
+ } else {
+ rssi = le32_to_cpu(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_CONN("RSSI %d dBm\n", rssi);
+ }
}
done:
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index e970897f6ab5..4cb234349fbf 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1326,6 +1326,11 @@ static int if_sdio_suspend(struct device *dev)
mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
+ /* If we're powered off anyway, just let the mmc layer remove the
+ * card. */
+ if (!lbs_iface_active(card->priv))
+ return -ENOSYS;
+
dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
sdio_func_id(func), flags);
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index c68adec3cc8b..565527aee0ea 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -170,7 +170,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
cmd_code = le16_to_cpu(host_cmd->command);
cmd_size = le16_to_cpu(host_cmd->size);
- skb_trim(cmd_node->cmd_skb, cmd_size);
+ /* Adjust skb length */
+ if (cmd_node->cmd_skb->len > cmd_size)
+ /*
+ * cmd_size is less than sizeof(struct host_cmd_ds_command).
+ * Trim off the unused portion.
+ */
+ skb_trim(cmd_node->cmd_skb, cmd_size);
+ else if (cmd_node->cmd_skb->len < cmd_size)
+ /*
+ * cmd_size is larger than sizeof(struct host_cmd_ds_command)
+ * because we have appended custom IE TLV. Increase skb length
+ * accordingly.
+ */
+ skb_put(cmd_node->cmd_skb, cmd_size - cmd_node->cmd_skb->len);
do_gettimeofday(&tstamp);
dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 8b9dbd76a252..64328af496f5 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1611,6 +1611,7 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Allocate eeprom data.
@@ -1624,6 +1625,14 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00_set_field32(&reg, GPIOCSR_BIT8, 1);
+ rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt2400pci_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index d3a4a68cc439..7564ae992b73 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -670,6 +670,7 @@
#define GPIOCSR_BIT5 FIELD32(0x00000020)
#define GPIOCSR_BIT6 FIELD32(0x00000040)
#define GPIOCSR_BIT7 FIELD32(0x00000080)
+#define GPIOCSR_BIT8 FIELD32(0x00000100)
/*
* BBPPCSR: BBP Pin control register.
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index d2cf8a4bc8b5..3de0406735f6 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1929,6 +1929,7 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Allocate eeprom data.
@@ -1942,6 +1943,14 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00_set_field32(&reg, GPIOCSR_DIR0, 1);
+ rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt2500pci_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 3aae36bb0a9e..89fee311d8fd 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -283,7 +283,7 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
u16 reg;
rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
- return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
+ return rt2x00_get_field16(reg, MAC_CSR19_BIT7);
}
#ifdef CONFIG_RT2X00_LIB_LEDS
@@ -1768,6 +1768,7 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u16 reg;
/*
* Allocate eeprom data.
@@ -1781,6 +1782,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR19_BIT8, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR19, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt2500usb_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index b493306a7eed..196bd5103e4f 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -189,14 +189,15 @@
* MAC_CSR19: GPIO control register.
*/
#define MAC_CSR19 0x0426
-#define MAC_CSR19_BIT0 FIELD32(0x0001)
-#define MAC_CSR19_BIT1 FIELD32(0x0002)
-#define MAC_CSR19_BIT2 FIELD32(0x0004)
-#define MAC_CSR19_BIT3 FIELD32(0x0008)
-#define MAC_CSR19_BIT4 FIELD32(0x0010)
-#define MAC_CSR19_BIT5 FIELD32(0x0020)
-#define MAC_CSR19_BIT6 FIELD32(0x0040)
-#define MAC_CSR19_BIT7 FIELD32(0x0080)
+#define MAC_CSR19_BIT0 FIELD16(0x0001)
+#define MAC_CSR19_BIT1 FIELD16(0x0002)
+#define MAC_CSR19_BIT2 FIELD16(0x0004)
+#define MAC_CSR19_BIT3 FIELD16(0x0008)
+#define MAC_CSR19_BIT4 FIELD16(0x0010)
+#define MAC_CSR19_BIT5 FIELD16(0x0020)
+#define MAC_CSR19_BIT6 FIELD16(0x0040)
+#define MAC_CSR19_BIT7 FIELD16(0x0080)
+#define MAC_CSR19_BIT8 FIELD16(0x0100)
/*
* MAC_CSR20: LED control register.
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index cb8c2aca54e4..b93516d832fb 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -4089,6 +4089,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
msleep(1);
rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
}
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 98aa426a3564..4765bbd654cd 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -983,6 +983,7 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Allocate eeprom data.
@@ -996,6 +997,14 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00pci_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+ rt2x00_set_field32(&reg, GPIO_CTRL_CFG_GPIOD_BIT2, 1);
+ rt2x00pci_register_write(rt2x00dev, GPIO_CTRL_CFG, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt2800_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 6cf336595e25..6b4226b71618 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -667,8 +667,16 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
skb_pull(entry->skb, RXINFO_DESC_SIZE);
/*
- * FIXME: we need to check for rx_pkt_len validity
+ * Check for rx_pkt_len validity. Return if invalid, leaving
+ * rxdesc->size zeroed out by the upper level.
*/
+ if (unlikely(rx_pkt_len == 0 ||
+ rx_pkt_len > entry->queue->data_size)) {
+ ERROR(entry->queue->rt2x00dev,
+ "Bad frame size %d, forcing to 0\n", rx_pkt_len);
+ return;
+ }
+
rxd = (__le32 *)(entry->skb->data + rx_pkt_len);
/*
@@ -736,6 +744,7 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Allocate eeprom data.
@@ -749,6 +758,14 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+ rt2x00_set_field32(&reg, GPIO_CTRL_CFG_GPIOD_BIT2, 1);
+ rt2x00usb_register_write(rt2x00dev, GPIO_CTRL_CFG, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt2800_probe_hw_mode(rt2x00dev);
@@ -1157,6 +1174,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x1690, 0x0744) },
{ USB_DEVICE(0x1690, 0x0761) },
{ USB_DEVICE(0x1690, 0x0764) },
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x179d) },
/* Cisco */
{ USB_DEVICE(0x167b, 0x4001) },
/* EnGenius */
@@ -1222,7 +1241,6 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x0b05, 0x1760) },
{ USB_DEVICE(0x0b05, 0x1761) },
{ USB_DEVICE(0x0b05, 0x1790) },
- { USB_DEVICE(0x0b05, 0x179d) },
/* AzureWave */
{ USB_DEVICE(0x13d3, 0x3262) },
{ USB_DEVICE(0x13d3, 0x3284) },
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index a6b88bd4a1a5..3f07e36f462b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -629,7 +629,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
*/
if (unlikely(rxdesc.size == 0 ||
rxdesc.size > entry->queue->data_size)) {
- WARNING(rt2x00dev, "Wrong frame size %d max %d.\n",
+ ERROR(rt2x00dev, "Wrong frame size %d max %d.\n",
rxdesc.size, entry->queue->data_size);
dev_kfree_skb(entry->skb);
goto renew_skb;
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 3f7bc5cadf9a..b8ec96163922 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -2832,6 +2832,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Disable power saving.
@@ -2850,6 +2851,14 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT13, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt61pci_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index e3cd6db76b0e..8f3da5a56766 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -372,6 +372,7 @@ struct hw_pairwise_ta_entry {
#define MAC_CSR13_BIT10 FIELD32(0x00000400)
#define MAC_CSR13_BIT11 FIELD32(0x00000800)
#define MAC_CSR13_BIT12 FIELD32(0x00001000)
+#define MAC_CSR13_BIT13 FIELD32(0x00002000)
/*
* MAC_CSR14: LED control register.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index ba6e434b859d..248436c13ce0 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2177,6 +2177,7 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ u32 reg;
/*
* Allocate eeprom data.
@@ -2190,6 +2191,14 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
return retval;
/*
+ * Enable rfkill polling by setting GPIO direction of the
+ * rfkill switch GPIO pin correctly.
+ */
+ rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT15, 0);
+ rt2x00usb_register_write(rt2x00dev, MAC_CSR13, reg);
+
+ /*
* Initialize hw specifications.
*/
retval = rt73usb_probe_hw_mode(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 9f6b470414d3..df1cc116b83b 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -282,6 +282,9 @@ struct hw_pairwise_ta_entry {
#define MAC_CSR13_BIT10 FIELD32(0x00000400)
#define MAC_CSR13_BIT11 FIELD32(0x00000800)
#define MAC_CSR13_BIT12 FIELD32(0x00001000)
+#define MAC_CSR13_BIT13 FIELD32(0x00002000)
+#define MAC_CSR13_BIT14 FIELD32(0x00004000)
+#define MAC_CSR13_BIT15 FIELD32(0x00008000)
/*
* MAC_CSR14: LED control register.
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 5d6de380e42b..352f96180bc7 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -271,6 +271,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
if (!parport_SPP_supported (p)) {
/* No port. */
kfree (priv);
+ kfree(ops);
return NULL;
}
parport_PS2_supported (p);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index e9c32274df3f..1631eeaf440e 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -62,6 +62,7 @@ enum parport_pc_pci_cards {
timedia_9079a,
timedia_9079b,
timedia_9079c,
+ wch_ch353_2s1p,
};
/* each element directly indexed from enum list, above */
@@ -145,6 +146,7 @@ static struct parport_pc_pci cards[] __devinitdata = {
/* timedia_9079a */ { 1, { { 2, 3 }, } },
/* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } },
+ /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
};
static struct pci_device_id parport_serial_pci_tbl[] = {
@@ -243,7 +245,8 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
-
+ /* WCH CARDS */
+ { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@@ -460,6 +463,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
.base_baud = 921600,
.uart_offset = 8,
},
+ [wch_ch353_2s1p] = {
+ .flags = FL_BASE0|FL_BASE_BARS,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
};
struct parport_serial_private {
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index 7fca6ce5952b..304360cd213e 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -17,6 +17,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -916,11 +917,66 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
seq_printf(s, " " DRIVER_NAME);
}
+static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct sirfsoc_pmx *spmx = 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, "sirf,function", &function);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_count_strings(np, "sirf,pins");
+ if (ret < 0)
+ return ret;
+
+ count += ret;
+ }
+
+ if (!count) {
+ dev_err(spmx->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, "sirf,function", &function);
+ of_property_for_each_string(np, "sirf,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;
+}
+
+static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ kfree(map);
+}
+
static struct pinctrl_ops sirfsoc_pctrl_ops = {
.get_groups_count = sirfsoc_get_groups_count,
.get_group_name = sirfsoc_get_group_name,
.get_group_pins = sirfsoc_get_group_pins,
.pin_dbg_show = sirfsoc_pin_dbg_show,
+ .dt_node_to_map = sirfsoc_dt_node_to_map,
+ .dt_free_map = sirfsoc_dt_free_map,
};
struct sirfsoc_pmx_func {
@@ -1221,7 +1277,7 @@ out_no_gpio_remap:
}
static const struct of_device_id pinmux_ids[] __devinitconst = {
- { .compatible = "sirf,prima2-gpio-pinmux" },
+ { .compatible = "sirf,prima2-pinctrl" },
{}
};
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 3782e1cd3697..934d861a3235 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -2196,10 +2196,8 @@ static int __init acer_wmi_init(void)
interface->capability &= ~ACER_CAP_BRIGHTNESS;
pr_info("Brightness must be controlled by acpi video driver\n");
} else {
-#ifdef CONFIG_ACPI_VIDEO
pr_info("Disabling ACPI video driver\n");
acpi_video_unregister();
-#endif
}
if (wmi_has_guid(WMID_GUID3)) {
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index dfb1a92ce949..db8f63841b42 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -101,7 +101,7 @@ static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
for (i = 0; i < 4; i++) {
tmpval = (val >> (i * 8)) & 0xff;
- outb(tmpval, port + i);
+ outb(tmpval, gmux_data->iostart + port + i);
}
}
@@ -142,8 +142,9 @@ static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
u8 val;
mutex_lock(&gmux_data->index_lock);
- outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
gmux_index_wait_ready(gmux_data);
+ outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+ gmux_index_wait_complete(gmux_data);
val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
mutex_unlock(&gmux_data->index_lock);
@@ -166,8 +167,9 @@ static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
u32 val;
mutex_lock(&gmux_data->index_lock);
- outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
gmux_index_wait_ready(gmux_data);
+ outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
+ gmux_index_wait_complete(gmux_data);
val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
mutex_unlock(&gmux_data->index_lock);
@@ -461,18 +463,22 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
if (gmux_is_indexed(gmux_data)) {
+ u32 version;
mutex_init(&gmux_data->index_lock);
gmux_data->indexed = true;
+ version = gmux_read32(gmux_data,
+ GMUX_PORT_VERSION_MAJOR);
+ ver_major = (version >> 24) & 0xff;
+ ver_minor = (version >> 16) & 0xff;
+ ver_release = (version >> 8) & 0xff;
} else {
pr_info("gmux device not present\n");
ret = -ENODEV;
goto err_release;
}
- pr_info("Found indexed gmux\n");
- } else {
- pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
- ver_release);
}
+ pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
+ ver_release, (gmux_data->indexed ? "indexed" : "classic"));
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_PLATFORM;
@@ -505,9 +511,7 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
* Disable the other backlight choices.
*/
acpi_video_dmi_promote_vendor();
-#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
acpi_video_unregister();
-#endif
apple_bl_unregister();
gmux_data->power_state = VGA_SWITCHEROO_ON;
@@ -593,9 +597,7 @@ static void __devexit gmux_remove(struct pnp_dev *pnp)
kfree(gmux_data);
acpi_video_dmi_demote_vendor();
-#if defined (CONFIG_ACPI_VIDEO) || defined (CONFIG_ACPI_VIDEO_MODULE)
acpi_video_register();
-#endif
apple_bl_register();
}
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index e38f91be0b10..4b568df56643 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -85,7 +85,7 @@ static char *wled_type = "unknown";
static char *bled_type = "unknown";
module_param(wled_type, charp, 0444);
-MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
+MODULE_PARM_DESC(wled_type, "Set the wled type on boot "
"(unknown, led or rfkill). "
"default is unknown");
@@ -863,9 +863,9 @@ static ssize_t show_infos(struct device *dev,
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
- rv = acpi_evaluate_integer(asus->handle, "HRWS", NULL, &temp);
+ rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp);
if (!ACPI_FAILURE(rv))
- len += sprintf(page + len, "HRWS value : %#x\n",
+ len += sprintf(page + len, "HWRS value : %#x\n",
(uint) temp);
/*
* Another value for userspace: the ASYM method returns 0x02 for
@@ -1751,9 +1751,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
* The significance of others is yet to be found.
*/
status =
- acpi_evaluate_integer(asus->handle, "HRWS", NULL, &hwrs_result);
+ acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result);
if (!ACPI_FAILURE(status))
- pr_notice(" HRWS returned %x", (int)hwrs_result);
+ pr_notice(" HWRS returned %x", (int)hwrs_result);
if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
asus->have_rsts = true;
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 2eb9fe8e8efd..c0e9ff489b24 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -47,9 +47,7 @@
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#ifdef CONFIG_ACPI_VIDEO
#include <acpi/video.h>
-#endif
#include "asus-wmi.h"
@@ -1704,10 +1702,8 @@ static int asus_wmi_add(struct platform_device *pdev)
if (asus->driver->quirks->wmi_backlight_power)
acpi_video_dmi_promote_vendor();
if (!acpi_video_backlight_support()) {
-#ifdef CONFIG_ACPI_VIDEO
pr_info("Disabling ACPI video driver\n");
acpi_video_unregister();
-#endif
err = asus_wmi_backlight_init(asus);
if (err && err != -ENODEV)
goto fail_backlight;
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index dab91b48d22c..5ca264179f4e 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -610,12 +610,12 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
if (!bus) {
pr_warn("Unable to find PCI bus 1?\n");
- goto out_unlock;
+ goto out_put_dev;
}
if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
pr_err("Unable to read PCI config space?\n");
- goto out_unlock;
+ goto out_put_dev;
}
absent = (l == 0xffffffff);
@@ -627,7 +627,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
absent ? "absent" : "present");
pr_warn("skipped wireless hotplug as probably "
"inappropriate for this model\n");
- goto out_unlock;
+ goto out_put_dev;
}
if (!blocked) {
@@ -635,7 +635,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
if (dev) {
/* Device already present */
pci_dev_put(dev);
- goto out_unlock;
+ goto out_put_dev;
}
dev = pci_scan_single_device(bus, 0);
if (dev) {
@@ -650,6 +650,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
pci_dev_put(dev);
}
}
+out_put_dev:
+ pci_dev_put(port);
}
out_unlock:
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index c1ca7bcebb66..dd90d15f5210 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -26,9 +26,7 @@
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/ctype.h>
-#ifdef CONFIG_ACPI_VIDEO
#include <acpi/video.h>
-#endif
/*
* This driver is needed because a number of Samsung laptops do not hook
@@ -1558,9 +1556,7 @@ static int __init samsung_init(void)
samsung->handle_backlight = false;
} else if (samsung->quirks->broken_acpi_video) {
pr_info("Disabling ACPI video driver\n");
-#ifdef CONFIG_ACPI_VIDEO
acpi_video_unregister();
-#endif
}
#endif
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 80e377949314..52daaa816e53 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -545,7 +545,7 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
*/
static int acpi_evalf(acpi_handle handle,
- void *res, char *method, char *fmt, ...)
+ int *res, char *method, char *fmt, ...)
{
char *fmt0 = fmt;
struct acpi_object_list params;
@@ -606,7 +606,7 @@ static int acpi_evalf(acpi_handle handle,
success = (status == AE_OK &&
out_obj.type == ACPI_TYPE_INTEGER);
if (success && res)
- *(int *)res = out_obj.integer.value;
+ *res = out_obj.integer.value;
break;
case 'v': /* void */
success = status == AE_OK;
@@ -7386,17 +7386,18 @@ static int fan_get_status(u8 *status)
* Add TPACPI_FAN_RD_ACPI_FANS ? */
switch (fan_status_access_mode) {
- case TPACPI_FAN_RD_ACPI_GFAN:
+ case TPACPI_FAN_RD_ACPI_GFAN: {
/* 570, 600e/x, 770e, 770x */
+ int res;
- if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ if (unlikely(!acpi_evalf(gfan_handle, &res, NULL, "d")))
return -EIO;
if (likely(status))
- *status = s & 0x07;
+ *status = res & 0x07;
break;
-
+ }
case TPACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c
index 44efc6e202af..d4957b4edb62 100644
--- a/drivers/power/avs/smartreflex.c
+++ b/drivers/power/avs/smartreflex.c
@@ -27,6 +27,8 @@
#include <linux/pm_runtime.h>
#include <linux/power/smartreflex.h>
+#include <plat/cpu.h>
+
#define SMARTREFLEX_NAME_LEN 16
#define NVALUE_NAME_LEN 40
#define SR_DISABLE_TIMEOUT 200
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 0b66d0f25922..4b6688909fee 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -100,6 +100,13 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
writel(period_cycles, pc->mmio_base + CAP3);
}
+ if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
+ reg_val = readw(pc->mmio_base + ECCTL2);
+ /* Disable APWM mode to put APWM output Low */
+ reg_val &= ~ECCTL2_APWM_MODE;
+ writew(reg_val, pc->mmio_base + ECCTL2);
+ }
+
pm_runtime_put_sync(pc->chip.dev);
return 0;
}
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index c3756d1be194..b1996bcd5b78 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip {
struct pwm_chip chip;
unsigned int clk_rate;
void __iomem *mmio_base;
+ unsigned long period_cycles[NUM_PWM_CHANNEL];
};
static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c;
unsigned long period_cycles, duty_cycles;
unsigned short ps_divval, tb_divval;
+ int i;
if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
return -ERANGE;
@@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
duty_cycles = (unsigned long)c;
}
+ /*
+ * Period values should be same for multiple PWM channels as IP uses
+ * same period register for multiple channels.
+ */
+ for (i = 0; i < NUM_PWM_CHANNEL; i++) {
+ if (pc->period_cycles[i] &&
+ (pc->period_cycles[i] != period_cycles)) {
+ /*
+ * Allow channel to reconfigure period if no other
+ * channels being configured.
+ */
+ if (i == pwm->hwpwm)
+ continue;
+
+ dev_err(chip->dev, "Period value conflicts with channel %d\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ pc->period_cycles[pwm->hwpwm] = period_cycles;
+
/* Configure clock prescaler to support Low frequency PWM wave */
if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
&tb_divval)) {
@@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
+ struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+
if (test_bit(PWMF_ENABLED, &pwm->flags)) {
dev_warn(chip->dev, "Removing PWM device without disabling\n");
pm_runtime_put_sync(chip->dev);
}
+
+ /* set period value to zero on free */
+ pc->period_cycles[pwm->hwpwm] = 0;
}
static const struct pwm_ops ehrpwm_pwm_ops = {
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 6caa222af77a..ab00cab905b7 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65217.h>
@@ -281,37 +282,130 @@ static const struct regulator_desc regulators[] = {
NULL),
};
+#ifdef CONFIG_OF
+static struct of_regulator_match reg_matches[] = {
+ { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
+ { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
+ { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
+ { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
+ { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
+ { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
+ { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
+};
+
+static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
+{
+ struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *node = tps->dev->of_node;
+ struct tps65217_board *pdata;
+ struct device_node *regs;
+ int i, count;
+
+ regs = of_find_node_by_name(node, "regulators");
+ if (!regs)
+ return NULL;
+
+ count = of_regulator_match(pdev->dev.parent, regs,
+ reg_matches, TPS65217_NUM_REGULATOR);
+ of_node_put(regs);
+ if ((count < 0) || (count > TPS65217_NUM_REGULATOR))
+ return NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ for (i = 0; i < count; i++) {
+ if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+ continue;
+
+ pdata->tps65217_init_data[i] = reg_matches[i].init_data;
+ pdata->of_node[i] = reg_matches[i].of_node;
+ }
+
+ return pdata;
+}
+#else
+static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
+{
+ return NULL;
+}
+#endif
+
static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
{
+ struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct tps65217_board *pdata = dev_get_platdata(tps->dev);
+ struct regulator_init_data *reg_data;
struct regulator_dev *rdev;
- struct tps65217 *tps;
- struct tps_info *info = &tps65217_pmic_regs[pdev->id];
struct regulator_config config = { };
+ int i, ret;
- /* Already set by core driver */
- tps = dev_to_tps65217(pdev->dev.parent);
- tps->info[pdev->id] = info;
+ if (tps->dev->of_node)
+ pdata = tps65217_parse_dt(pdev);
- config.dev = &pdev->dev;
- config.of_node = pdev->dev.of_node;
- config.init_data = pdev->dev.platform_data;
- config.driver_data = tps;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Platform data not found\n");
+ return -EINVAL;
+ }
- rdev = regulator_register(&regulators[pdev->id], &config);
- if (IS_ERR(rdev))
- return PTR_ERR(rdev);
+ if (tps65217_chip_id(tps) != TPS65217) {
+ dev_err(&pdev->dev, "Invalid tps chip version\n");
+ return -ENODEV;
+ }
- platform_set_drvdata(pdev, rdev);
+ platform_set_drvdata(pdev, tps);
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
+
+ reg_data = pdata->tps65217_init_data[i];
+
+ /*
+ * Regulator API handles empty constraints but not NULL
+ * constraints
+ */
+ if (!reg_data)
+ continue;
+
+ /* Register the regulators */
+ tps->info[i] = &tps65217_pmic_regs[i];
+
+ config.dev = tps->dev;
+ config.init_data = reg_data;
+ config.driver_data = tps;
+ config.regmap = tps->regmap;
+ if (tps->dev->of_node)
+ config.of_node = pdata->of_node[i];
+
+ rdev = regulator_register(&regulators[i], &config);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "failed to register %s regulator\n",
+ pdev->name);
+ ret = PTR_ERR(rdev);
+ goto err_unregister_regulator;
+ }
+
+ /* Save regulator for cleanup */
+ tps->rdev[i] = rdev;
+ }
return 0;
+
+err_unregister_regulator:
+ while (--i >= 0)
+ regulator_unregister(tps->rdev[i]);
+
+ return ret;
}
static int __devexit tps65217_regulator_remove(struct platform_device *pdev)
{
- struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct tps65217 *tps = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
+ regulator_unregister(tps->rdev[i]);
platform_set_drvdata(pdev, NULL);
- regulator_unregister(rdev);
return 0;
}
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index bf3c2f669c3c..2e5970fe9eeb 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -462,16 +462,10 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id ab8500_rtc_match[] = {
- { .compatible = "stericsson,ab8500-rtc", },
- {}
-};
-
static struct platform_driver ab8500_rtc_driver = {
.driver = {
.name = "ab8500-rtc",
.owner = THIS_MODULE,
- .of_match_table = ab8500_rtc_match,
},
.probe = ab8500_rtc_probe,
.remove = __devexit_p(ab8500_rtc_remove),
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index 0075c8fd93d8..f771b2ee4b18 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -27,6 +27,8 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <mach/hardware.h>
@@ -396,6 +398,14 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static struct of_device_id pxa_rtc_dt_ids[] = {
+ { .compatible = "marvell,pxa-rtc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids);
+#endif
+
#ifdef CONFIG_PM
static int pxa_rtc_suspend(struct device *dev)
{
@@ -425,6 +435,7 @@ static struct platform_driver pxa_rtc_driver = {
.remove = __exit_p(pxa_rtc_remove),
.driver = {
.name = "pxa-rtc",
+ .of_match_table = of_match_ptr(pxa_rtc_dt_ids),
#ifdef CONFIG_PM
.pm = &pxa_rtc_pm_ops,
#endif
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6c0116d48c74..9ffb6d5f17aa 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev)
static void raw3215_remove (struct ccw_device *cdev)
{
struct raw3215_info *raw;
+ unsigned int line;
ccw_device_set_offline(cdev);
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
+ spin_lock(&raw3215_device_lock);
+ for (line = 0; line < NR_3215; line++)
+ if (raw3215[line] == raw)
+ break;
+ raw3215[line] = NULL;
+ spin_unlock(&raw3215_device_lock);
dev_set_drvdata(&cdev->dev, NULL);
raw3215_free_info(raw);
}
@@ -935,6 +942,19 @@ static int __init con3215_init(void)
console_initcall(con3215_init);
#endif
+static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct raw3215_info *raw;
+
+ raw = raw3215[tty->index];
+ if (raw == NULL)
+ return -ENODEV;
+
+ tty->driver_data = raw;
+
+ return tty_port_install(&raw->port, driver, tty);
+}
+
/*
* tty3215_open
*
@@ -942,14 +962,9 @@ console_initcall(con3215_init);
*/
static int tty3215_open(struct tty_struct *tty, struct file * filp)
{
- struct raw3215_info *raw;
+ struct raw3215_info *raw = tty->driver_data;
int retval;
- raw = raw3215[tty->index];
- if (raw == NULL)
- return -ENODEV;
-
- tty->driver_data = raw;
tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */
@@ -1110,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty)
}
static const struct tty_operations tty3215_ops = {
+ .install = tty3215_install,
.open = tty3215_open,
.close = tty3215_close,
.write = tty3215_write,
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 0792c85baafe..30ec09e3d037 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -567,6 +567,7 @@ sclp_tty_init(void)
driver->init_termios.c_lflag = ISIG | ECHO;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_ops);
+ tty_port_link_device(&sclp_port, driver, 0);
rc = tty_register_driver(driver);
if (rc) {
put_tty_driver(driver);
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index edfc0fd73dc6..7e60f3d2f3f9 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void)
driver->init_termios = tty_std_termios;
driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &sclp_vt220_ops);
+ tty_port_link_device(&sclp_vt220_port, driver, 0);
rc = tty_register_driver(driver);
if (rc)
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 1928f3458d10..482ee028f842 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = {
};
/*
- * This routine is called whenever a 3270 tty is opened.
+ * This routine is called whenever a 3270 tty is opened first time.
*/
-static int
-tty3270_open(struct tty_struct *tty, struct file * filp)
+static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;
- if (tty->count > 1)
- return 0;
/* Check if the tty3270 is already there. */
view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
@@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
/* why to reassign? */
tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
- return 0;
+ return tty_port_install(&tp->port, driver, tty);
}
if (tty3270_max_index < tty->index + 1)
tty3270_max_index = tty->index + 1;
@@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
- tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;
@@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
kbd_ascebc(tp->kbd, tp->view.ascebc);
raw3270_activate_view(&tp->view);
+
+ rc = tty_port_install(&tp->port, driver, tty);
+ if (rc) {
+ raw3270_put_view(&tp->view);
+ return rc;
+ }
+
+ tty->driver_data = tp;
+
return 0;
}
@@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
if (tp) {
tty->driver_data = NULL;
tty_port_tty_set(&tp->port, NULL);
- raw3270_put_view(&tp->view);
}
}
+static void tty3270_cleanup(struct tty_struct *tty)
+{
+ struct tty3270 *tp = tty->driver_data;
+
+ if (tp)
+ raw3270_put_view(&tp->view);
+}
+
/*
* We always have room.
*/
@@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
#endif
static const struct tty_operations tty3270_ops = {
- .open = tty3270_open,
+ .install = tty3270_install,
+ .cleanup = tty3270_cleanup,
.close = tty3270_close,
.write = tty3270_write,
.put_char = tty3270_put_char,
@@ -1781,7 +1794,7 @@ static int __init tty3270_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
- driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
@@ -1800,6 +1813,7 @@ tty3270_exit(void)
driver = tty3270_driver;
tty3270_driver = NULL;
tty_unregister_driver(driver);
+ put_tty_driver(driver);
tty3270_del_views();
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index dc27598785e5..ed38454228c6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -4066,7 +4066,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&instance->cmd_pool_lock);
spin_lock_init(&instance->hba_lock);
spin_lock_init(&instance->completion_lock);
- spin_lock_init(&poll_aen_lock);
mutex_init(&instance->aen_mutex);
mutex_init(&instance->reset_mutex);
@@ -5392,6 +5391,8 @@ static int __init megasas_init(void)
printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
MEGASAS_EXT_VERSION);
+ spin_lock_init(&poll_aen_lock);
+
support_poll_for_event = 2;
support_device_change = 1;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 9d46fcbe7755..b25757d1e91b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -2424,10 +2424,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
/* command line tunables for max controller queue depth */
- if (max_queue_depth != -1)
- max_request_credit = (max_queue_depth < facts->RequestCredit)
- ? max_queue_depth : facts->RequestCredit;
- else
+ if (max_queue_depth != -1 && max_queue_depth != 0) {
+ max_request_credit = min_t(u16, max_queue_depth +
+ ioc->hi_priority_depth + ioc->internal_depth,
+ facts->RequestCredit);
+ if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
+ max_request_credit = MAX_HBA_QUEUE_DEPTH;
+ } else
max_request_credit = min_t(u16, facts->RequestCredit,
MAX_HBA_QUEUE_DEPTH);
@@ -2502,7 +2505,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* set the scsi host can_queue depth
* with some internal commands that could be outstanding
*/
- ioc->shost->can_queue = ioc->scsiio_depth - (2);
+ ioc->shost->can_queue = ioc->scsiio_depth;
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "
"can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue));
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 4a6381c87253..de2337f255a7 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -42,6 +42,8 @@
#include <trace/events/scsi.h>
+static void scsi_eh_done(struct scsi_cmnd *scmd);
+
#define SENSE_TIMEOUT (10*HZ)
/*
@@ -241,6 +243,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (! scsi_command_normalize_sense(scmd, &sshdr))
return FAILED; /* no valid sense data */
+ if (scmd->cmnd[0] == TEST_UNIT_READY && scmd->scsi_done != scsi_eh_done)
+ /*
+ * nasty: for mid-layer issued TURs, we need to return the
+ * actual sense data without any recovery attempt. For eh
+ * issued ones, we need to try to recover and interpret
+ */
+ return SUCCESS;
+
if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ffd77739ae3e..faa790fba134 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -776,7 +776,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */
- req->errors = result;
if (result) {
if (sense_valid && req->sense) {
/*
@@ -792,6 +791,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
if (!sense_deferred)
error = __scsi_error_from_host_byte(cmd, result);
}
+ /*
+ * __scsi_error_from_host_byte may have reset the host_byte
+ */
+ req->errors = cmd->result;
req->resid_len = scsi_get_resid(cmd);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56a93794c470..d947ffc20ceb 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -764,6 +764,16 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
sdev->model = (char *) (sdev->inquiry + 16);
sdev->rev = (char *) (sdev->inquiry + 32);
+ if (strncmp(sdev->vendor, "ATA ", 8) == 0) {
+ /*
+ * sata emulation layer device. This is a hack to work around
+ * the SATL power management specifications which state that
+ * when the SATL detects the device has gone into standby
+ * mode, it shall respond with NOT READY.
+ */
+ sdev->allow_restart = 1;
+ }
+
if (*bflags & BLIST_ISROM) {
sdev->type = TYPE_ROM;
sdev->removable = 1;
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 9b0d71696039..a3996a1c6345 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -53,7 +53,8 @@
#include <asm/mach-types.h>
#include <plat/mux.h>
-#include <plat/omap7xx.h> /* OMAP7XX_IO_CONF registers */
+
+#include <mach/omap7xx.h> /* OMAP7XX_IO_CONF registers */
/* FIXME address is now a platform device resource,
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index d0cafd637199..f2ffd963f1c3 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -51,10 +51,12 @@ enum android_alarm_return_flags {
#define ANDROID_ALARM_WAIT _IO('a', 1)
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
+#define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size)
+
/* Set alarm */
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
-#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
+#define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec)
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 6c81e377262c..cc8931fde839 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -1412,6 +1412,13 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in dio200_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via dio200_attach()
+ * has been removed.
+ */
+ pci_dev_get(pci_dev);
return dio200_pci_common_attach(dev, pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index aabba9886b7d..f50287903038 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -565,6 +565,13 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev,
dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in pc236_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via pc236_attach()
+ * has been removed.
+ */
+ pci_dev_get(pci_dev);
return pc236_pci_common_attach(dev, pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 40ec1ffebba6..8191c4e28e0a 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -298,6 +298,13 @@ static int __devinit pc263_attach_pci(struct comedi_device *dev,
dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in pc263_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via pc263_attach()
+ * has been removed.
+ */
+ pci_dev_get(pci_dev);
return pc263_pci_common_attach(dev, pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index 4e17f13e57f6..8bf109e7bb05 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -1503,6 +1503,13 @@ pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
DRIVER_NAME ": BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in pci224_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via pci224_attach()
+ * has been removed.
+ */
+ pci_dev_get(pci_dev);
return pci224_attach_common(dev, pci_dev, NULL);
}
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 1b67d0c61fa7..66e74bd12267 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2925,6 +2925,13 @@ static int __devinit pci230_attach_pci(struct comedi_device *dev,
"amplc_pci230: BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in pci230_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via pci230_attach()
+ * has been removed.
+ */
+ pci_dev_get(pci_dev);
return pci230_attach_common(dev, pci_dev);
}
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 874e02e47668..67a914a10b55 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -378,7 +378,7 @@ das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
int chan;
lsb = data[0] & 0xff;
- msb = (data[0] >> 8) & 0xf;
+ msb = (data[0] >> 8) & 0xff;
chan = CR_CHAN(insn->chanspec);
@@ -623,7 +623,7 @@ static const struct das08_board_struct das08_boards[] = {
.ai = das08_ai_rinsn,
.ai_nbits = 16,
.ai_pg = das08_pg_none,
- .ai_encoding = das08_encode12,
+ .ai_encoding = das08_encode16,
.ao = das08jr_ao_winsn,
.ao_nbits = 16,
.di = das08jr_di_rbits,
@@ -922,6 +922,13 @@ das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev)
dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
return -EINVAL;
}
+ /*
+ * Need to 'get' the PCI device to match the 'put' in das08_detach().
+ * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
+ * support for manual attachment of PCI devices via das08_attach()
+ * has been removed.
+ */
+ pci_dev_get(pdev);
return das08_pci_attach_common(dev, pdev);
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 18d108fd967a..f3da59063ed2 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -121,8 +121,10 @@ static int lis3l02dq_get_buffer_element(struct iio_dev *indio_dev,
if (rx_array == NULL)
return -ENOMEM;
ret = lis3l02dq_read_all(indio_dev, rx_array);
- if (ret < 0)
+ if (ret < 0) {
+ kfree(rx_array);
return ret;
+ }
for (i = 0; i < scan_count; i++)
data[i] = combine_8_to_16(rx_array[i*4+1],
rx_array[i*4+3]);
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 095837285f4f..19a064d649e3 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -647,6 +647,8 @@ static ssize_t ad7192_write_frequency(struct device *dev,
ret = strict_strtoul(buf, 10, &lval);
if (ret)
return ret;
+ if (lval == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 93aa431287ac..eb8e9d69efd3 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -195,6 +195,8 @@ static ssize_t adis16260_write_frequency(struct device *dev,
ret = strict_strtol(buf, 10, &val);
if (ret)
return ret;
+ if (val == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
if (spi_get_device_id(st->us)) {
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index 1f4c17779b5a..a618327e06ed 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -234,6 +234,8 @@ static ssize_t adis16400_write_frequency(struct device *dev,
ret = strict_strtol(buf, 10, &val);
if (ret)
return ret;
+ if (val == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index f04ece7fbc2f..3ccff189f258 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -425,6 +425,8 @@ static ssize_t ade7753_write_frequency(struct device *dev,
ret = strict_strtol(buf, 10, &val);
if (ret)
return ret;
+ if (val == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 6cee28a5e877..abb1e9c8d094 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -445,6 +445,8 @@ static ssize_t ade7754_write_frequency(struct device *dev,
ret = strict_strtol(buf, 10, &val);
if (ret)
return ret;
+ if (val == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index b3f7e0fa9612..eb0a2a98f388 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -385,6 +385,8 @@ static ssize_t ade7759_write_frequency(struct device *dev,
ret = strict_strtol(buf, 10, &val);
if (ret)
return ret;
+ if (val == 0)
+ return -EINVAL;
mutex_lock(&indio_dev->mlock);
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
index fd0e30132ca2..a68d981c259f 100644
--- a/drivers/staging/ipack/devices/ipoctal.c
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -502,7 +502,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
ipoctal->pointer_read[i] = 0;
ipoctal->pointer_write[i] = 0;
ipoctal->nb_bytes[i] = 0;
- tty_register_device(tty, i, NULL);
+ tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL);
/*
* Enable again the RX. TX will be enabled when
@@ -617,7 +617,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
struct ipoctal *ipoctal = tty->driver_data;
speed_t baud;
- cflag = tty->termios->c_cflag;
+ 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,
@@ -643,7 +643,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
default:
mr1 |= MR1_CHRL_8_BITS;
/* By default, select CS8 */
- tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+ tty->termios.c_cflag = (cflag & ~CSIZE) | CS8;
break;
}
@@ -657,7 +657,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
mr1 |= MR1_PARITY_OFF;
/* Mark or space parity is not supported */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
/* Set stop bits */
if (cflag & CSTOPB)
@@ -690,10 +690,10 @@ static void ipoctal_set_termios(struct tty_struct *tty,
}
baud = tty_get_baud_rate(tty);
- tty_termios_encode_baud_rate(tty->termios, baud, baud);
+ tty_termios_encode_baud_rate(&tty->termios, baud, baud);
/* Set baud rate */
- switch (tty->termios->c_ospeed) {
+ switch (baud) {
case 75:
csr |= TX_CLK_75 | RX_CLK_75;
break;
@@ -734,7 +734,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
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);
+ tty_termios_encode_baud_rate(&tty->termios, 38400, 38400);
break;
}
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 695ea35f75b0..d0a7e408efe9 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -837,7 +837,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
}
ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
- ARRAY_SIZE(nvec_devices), base, 0);
+ ARRAY_SIZE(nvec_devices), base, 0, NULL);
if (ret)
dev_err(nvec->dev, "error adding subdevices\n");
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c
index 5e2856c0e0bb..55e9c8655850 100644
--- a/drivers/staging/omapdrm/omap_connector.c
+++ b/drivers/staging/omapdrm/omap_connector.c
@@ -48,13 +48,20 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode,
mode->vsync_end = mode->vsync_start + timings->vsw;
mode->vtotal = mode->vsync_end + timings->vbp;
- /* note: whether or not it is interlaced, +/- h/vsync, etc,
- * which should be set in the mode flags, is not exposed in
- * the omap_video_timings struct.. but hdmi driver tracks
- * those separately so all we have to have to set the mode
- * is the way to recover these timings values, and the
- * omap_dss_driver would do the rest.
- */
+ mode->flags = 0;
+
+ if (timings->interlace)
+ mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+ if (timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
}
static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings,
@@ -71,6 +78,22 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings,
timings->vfp = mode->vsync_start - mode->vdisplay;
timings->vsw = mode->vsync_end - mode->vsync_start;
timings->vbp = mode->vtotal - mode->vsync_end;
+
+ timings->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ timings->hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ else
+ timings->hsync_level = OMAPDSS_SIG_ACTIVE_LOW;
+
+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ timings->vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ else
+ timings->vsync_level = OMAPDSS_SIG_ACTIVE_LOW;
+
+ timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
}
static void omap_connector_dpms(struct drm_connector *connector, int mode)
@@ -187,7 +210,7 @@ static int omap_connector_get_modes(struct drm_connector *connector)
}
} else {
struct drm_display_mode *mode = drm_mode_create(dev);
- struct omap_video_timings timings;
+ struct omap_video_timings timings = {0};
dssdrv->get_timings(dssdev, &timings);
@@ -291,7 +314,7 @@ void omap_connector_mode_set(struct drm_connector *connector,
struct omap_connector *omap_connector = to_omap_connector(connector);
struct omap_dss_device *dssdev = omap_connector->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
- struct omap_video_timings timings;
+ struct omap_video_timings timings = {0};
copy_timings_drm_to_omap(&timings, mode);
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index d98321945802..758ce0a8d82e 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -8,6 +8,7 @@
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include "ozconfig.h"
@@ -213,7 +214,7 @@ static int oz_set_active_pd(u8 *addr)
if (old_pd)
oz_pd_put(old_pd);
} else {
- if (!memcmp(addr, "\0\0\0\0\0\0", sizeof(addr))) {
+ if (is_zero_ether_addr(addr)) {
spin_lock_bh(&g_cdev.lock);
pd = g_cdev.active_pd;
g_cdev.active_pd = 0;
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 0e26d5f6cf2d..495ee1205e02 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -117,13 +117,8 @@ void r8712_recv_indicatepkt(struct _adapter *padapter,
if (skb == NULL)
goto _recv_indicatepkt_drop;
skb->data = precv_frame->u.hdr.rx_data;
-#ifdef NET_SKBUFF_DATA_USES_OFFSET
- skb->tail = (sk_buff_data_t)(precv_frame->u.hdr.rx_tail -
- precv_frame->u.hdr.rx_head);
-#else
- skb->tail = (sk_buff_data_t)precv_frame->u.hdr.rx_tail;
-#endif
skb->len = precv_frame->u.hdr.len;
+ skb_set_tail_pointer(skb, skb->len);
if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index 8a362f7af379..c90de969be8f 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -315,10 +315,8 @@ static void qt_read_bulk_callback(struct urb *urb)
}
tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
+ if (!tty)
return;
- }
data = urb->transfer_buffer;
@@ -364,7 +362,7 @@ static void qt_read_bulk_callback(struct urb *urb)
goto exit;
}
- if (tty && RxCount) {
+ if (RxCount) {
flag_data = 0;
for (i = 0; i < RxCount; ++i) {
/* Look ahead code here */
@@ -428,7 +426,7 @@ static void qt_read_bulk_callback(struct urb *urb)
dbg("%s - failed resubmitting read urb, error %d",
__func__, result);
else {
- if (tty && RxCount) {
+ if (RxCount) {
tty_flip_buffer_push(tty);
tty_schedule_flip(tty);
}
@@ -897,8 +895,6 @@ static int qt_open(struct tty_struct *tty,
* Put this here to make it responsive to stty and defaults set by
* the tty layer
*/
- /* FIXME: is this needed? */
- /* qt_set_termios(tty, port, NULL); */
/* Check to see if we've set up our endpoint info yet */
if (port0->open_ports == 1) {
@@ -1195,7 +1191,7 @@ static void qt_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned char new_LCR = 0;
unsigned int cflag = termios->c_cflag;
unsigned int index;
@@ -1204,7 +1200,7 @@ static void qt_set_termios(struct tty_struct *tty,
index = tty->index - port->serial->minor;
- switch (cflag) {
+ switch (cflag & CSIZE) {
case CS5:
new_LCR |= SERIAL_5_DATA;
break;
@@ -1215,6 +1211,8 @@ static void qt_set_termios(struct tty_struct *tty,
new_LCR |= SERIAL_7_DATA;
break;
default:
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS8;
case CS8:
new_LCR |= SERIAL_8_DATA;
break;
@@ -1301,7 +1299,7 @@ static void qt_set_termios(struct tty_struct *tty,
dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
}
- tty->termios->c_cflag &= ~CMSPAR;
+ termios->c_cflag &= ~CMSPAR;
/* FIXME: Error cases should be returning the actual bits changed only */
}
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
index 614271f9b99f..55d68b5ad165 100644
--- a/drivers/staging/speakup/serialio.h
+++ b/drivers/staging/speakup/serialio.h
@@ -1,8 +1,7 @@
#ifndef _SPEAKUP_SERIAL_H
#define _SPEAKUP_SERIAL_H
-#include <linux/serial.h> /* for rs_table, serial constants &
- serial_uart_config */
+#include <linux/serial.h> /* for rs_table, serial constants */
#include <linux/serial_reg.h> /* for more serial constants */
#ifndef __sparc__
#include <asm/serial.h>
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c
index 870f934f4f3b..453ef748bf45 100644
--- a/drivers/staging/tidspbridge/core/wdt.c
+++ b/drivers/staging/tidspbridge/core/wdt.c
@@ -25,7 +25,7 @@
#include <dspbridge/host_os.h>
-#define OMAP34XX_WDT3_BASE (L4_PER_34XX_BASE + 0x30000)
+#define INT_34XX_WDT3_IRQ (36 + NR_IRQS)
static struct dsp_wdt_setting dsp_wdt;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index e4bdf2a2b582..3aa895ec6507 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -200,7 +200,7 @@ s_vProcessRxMACHeader (
} else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
cbHeaderSize += 6;
pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
- if ((*pwType == cpu_to_le16(ETH_P_IPX)) ||
+ if ((*pwType == cpu_to_be16(ETH_P_IPX)) ||
(*pwType == cpu_to_le16(0xF380))) {
cbHeaderSize -= 8;
pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index bb464527fc1b..b6e04e7b629b 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -1699,7 +1699,7 @@ s_bPacketToWirelessUsb(
// 802.1H
if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
- if ((psEthHeader->wType == cpu_to_le16(ETH_P_IPX)) ||
+ if ((psEthHeader->wType == cpu_to_be16(ETH_P_IPX)) ||
(psEthHeader->wType == cpu_to_le16(0xF380))) {
memcpy((PBYTE) (pbyPayloadHead),
abySNAP_Bridgetunnel, 6);
@@ -2838,10 +2838,10 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb)
Packet_Type = skb->data[ETH_HLEN+1];
Descriptor_type = skb->data[ETH_HLEN+1+1+2];
Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]);
- if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) {
- /* 802.1x OR eapol-key challenge frame transfer */
- if (((Protocol_Version == 1) || (Protocol_Version == 2)) &&
- (Packet_Type == 3)) {
+ if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) {
+ /* 802.1x OR eapol-key challenge frame transfer */
+ if (((Protocol_Version == 1) || (Protocol_Version == 2)) &&
+ (Packet_Type == 3)) {
bTxeapol_key = TRUE;
if(!(Key_info & BIT3) && //WPA or RSN group-key challenge
(Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key
@@ -2987,19 +2987,19 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb)
}
}
- if (pDevice->sTxEthHeader.wType == cpu_to_le16(ETH_P_PAE)) {
- if (pDevice->byBBType != BB_TYPE_11A) {
- pDevice->wCurrentRate = RATE_1M;
- pDevice->byACKRate = RATE_1M;
- pDevice->byTopCCKBasicRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_6M;
- } else {
- pDevice->wCurrentRate = RATE_6M;
- pDevice->byACKRate = RATE_6M;
- pDevice->byTopCCKBasicRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_6M;
- }
- }
+ if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) {
+ if (pDevice->byBBType != BB_TYPE_11A) {
+ pDevice->wCurrentRate = RATE_1M;
+ pDevice->byACKRate = RATE_1M;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_6M;
+ } else {
+ pDevice->wCurrentRate = RATE_6M;
+ pDevice->byACKRate = RATE_6M;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_6M;
+ }
+ }
DBG_PRT(MSG_LEVEL_DEBUG,
KERN_INFO "dma_tx: pDevice->wCurrentRate = %d\n",
@@ -3015,7 +3015,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb)
if (bNeedEncryption == TRUE) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType));
- if ((pDevice->sTxEthHeader.wType) == cpu_to_le16(ETH_P_PAE)) {
+ if ((pDevice->sTxEthHeader.wType) == cpu_to_be16(ETH_P_PAE)) {
bNeedEncryption = FALSE;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType));
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index fabff4d650ef..0970127344e6 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -327,9 +327,9 @@ int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
return result;
}
-int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_scan_request *request)
+int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
+ struct net_device *dev = request->wdev->netdev;
struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
wlandevice_t *wlandev = dev->ml_priv;
struct p80211msg_dot11req_scan msg1;
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index c214977b4ab4..52b43b7b83d7 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1251,13 +1251,12 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
void *pampd, struct tmem_pool *pool,
struct tmem_oid *oid, uint32_t index)
{
- int ret = 0;
-
BUG_ON(!is_ephemeral(pool));
- zbud_decompress((struct page *)(data), pampd);
+ if (zbud_decompress((struct page *)(data), pampd) < 0)
+ return -EINVAL;
zbud_free_and_delist((struct zbud_hdr *)pampd);
atomic_dec(&zcache_curr_eph_pampd_count);
- return ret;
+ return 0;
}
/*
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 0694d9b1bce6..6aba4395e8d8 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -221,6 +221,7 @@ static int iscsi_login_zero_tsih_s1(
{
struct iscsi_session *sess = NULL;
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+ int ret;
sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
if (!sess) {
@@ -257,9 +258,17 @@ static int iscsi_login_zero_tsih_s1(
return -ENOMEM;
}
spin_lock(&sess_idr_lock);
- idr_get_new(&sess_idr, NULL, &sess->session_index);
+ ret = idr_get_new(&sess_idr, NULL, &sess->session_index);
spin_unlock(&sess_idr_lock);
+ if (ret < 0) {
+ pr_err("idr_get_new() for sess_idr failed\n");
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ kfree(sess);
+ return -ENOMEM;
+ }
+
sess->creation_time = get_jiffies_64();
spin_lock_init(&sess->session_stats_lock);
/*
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 91799973081a..41641ba54828 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -218,6 +218,13 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd)
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
return -EINVAL;
}
+ if (cmd->data_length < 4) {
+ pr_warn("SET TARGET PORT GROUPS parameter list length %u too"
+ " small\n", cmd->data_length);
+ cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+ return -EINVAL;
+ }
+
buf = transport_kmap_data_sg(cmd);
/*
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index cf2c66f3c116..9fc9a6006ca0 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -669,6 +669,13 @@ int target_report_luns(struct se_cmd *se_cmd)
unsigned char *buf;
u32 lun_count = 0, offset = 8, i;
+ if (se_cmd->data_length < 16) {
+ pr_warn("REPORT LUNS allocation length %u too small\n",
+ se_cmd->data_length);
+ se_cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -EINVAL;
+ }
+
buf = transport_kmap_data_sg(se_cmd);
if (!buf)
return -ENOMEM;
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 76db75e836ed..9ba495477fd2 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -325,17 +325,30 @@ static int iblock_execute_unmap(struct se_cmd *cmd)
struct iblock_dev *ibd = dev->dev_ptr;
unsigned char *buf, *ptr = NULL;
sector_t lba;
- int size = cmd->data_length;
+ int size;
u32 range;
int ret = 0;
int dl, bd_dl;
+ if (cmd->data_length < 8) {
+ pr_warn("UNMAP parameter list length %u too small\n",
+ cmd->data_length);
+ cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+ return -EINVAL;
+ }
+
buf = transport_kmap_data_sg(cmd);
dl = get_unaligned_be16(&buf[0]);
bd_dl = get_unaligned_be16(&buf[2]);
- size = min(size - 8, bd_dl);
+ size = cmd->data_length - 8;
+ if (bd_dl > size)
+ pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
+ cmd->data_length, bd_dl);
+ else
+ size = bd_dl;
+
if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) {
cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
ret = -EINVAL;
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 1e946502c378..956c84c6b666 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -1540,6 +1540,14 @@ static int core_scsi3_decode_spec_i_port(
tidh_new->dest_local_nexus = 1;
list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+ if (cmd->data_length < 28) {
+ pr_warn("SPC-PR: Received PR OUT parameter list"
+ " length too small: %u\n", cmd->data_length);
+ cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+ ret = -EINVAL;
+ goto out;
+ }
+
buf = transport_kmap_data_sg(cmd);
/*
* For a PERSISTENT RESERVE OUT specify initiator ports payload,
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 5552fa7426bc..9d7ce3daa262 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -667,7 +667,8 @@ static void pscsi_free_device(void *p)
kfree(pdv);
}
-static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
+static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg,
+ unsigned char *sense_buffer)
{
struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
struct scsi_device *sd = pdv->pdv_sd;
@@ -679,7 +680,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
* not been allocated because TCM is handling the emulation directly.
*/
if (!pt)
- return 0;
+ return;
cdb = &pt->pscsi_cdb[0];
result = pt->pscsi_result;
@@ -687,11 +688,11 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
* Hack to make sure that Write-Protect modepage is set if R/O mode is
* forced.
*/
+ if (!cmd->se_deve || !cmd->data_length)
+ goto after_mode_sense;
+
if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
(status_byte(result) << 1) == SAM_STAT_GOOD) {
- if (!cmd->se_deve)
- goto after_mode_sense;
-
if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) {
unsigned char *buf = transport_kmap_data_sg(cmd);
@@ -708,7 +709,7 @@ static int pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg)
}
after_mode_sense:
- if (sd->type != TYPE_TAPE)
+ if (sd->type != TYPE_TAPE || !cmd->data_length)
goto after_mode_select;
/*
@@ -750,10 +751,10 @@ after_mode_sense:
}
after_mode_select:
- if (status_byte(result) & CHECK_CONDITION)
- return 1;
-
- return 0;
+ if (sense_buffer && (status_byte(result) & CHECK_CONDITION)) {
+ memcpy(sense_buffer, pt->pscsi_sense, TRANSPORT_SENSE_BUFFER);
+ cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
+ }
}
enum {
@@ -1184,13 +1185,6 @@ fail:
return -ENOMEM;
}
-static unsigned char *pscsi_get_sense_buffer(struct se_cmd *cmd)
-{
- struct pscsi_plugin_task *pt = cmd->priv;
-
- return pt->pscsi_sense;
-}
-
/* pscsi_get_device_rev():
*
*
@@ -1273,7 +1267,6 @@ static struct se_subsystem_api pscsi_template = {
.check_configfs_dev_params = pscsi_check_configfs_dev_params,
.set_configfs_dev_params = pscsi_set_configfs_dev_params,
.show_configfs_dev_params = pscsi_show_configfs_dev_params,
- .get_sense_buffer = pscsi_get_sense_buffer,
.get_device_rev = pscsi_get_device_rev,
.get_device_type = pscsi_get_device_type,
.get_blocks = pscsi_get_blocks,
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 4c861de538c9..388a922c8f6d 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -877,9 +877,11 @@ static int spc_emulate_modesense(struct se_cmd *cmd)
static int spc_emulate_request_sense(struct se_cmd *cmd)
{
unsigned char *cdb = cmd->t_task_cdb;
- unsigned char *buf;
+ unsigned char *rbuf;
u8 ua_asc = 0, ua_ascq = 0;
- int err = 0;
+ unsigned char buf[SE_SENSE_BUF];
+
+ memset(buf, 0, SE_SENSE_BUF);
if (cdb[1] & 0x01) {
pr_err("REQUEST_SENSE description emulation not"
@@ -888,20 +890,21 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)
return -ENOSYS;
}
- buf = transport_kmap_data_sg(cmd);
-
- if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
+ rbuf = transport_kmap_data_sg(cmd);
+ if (cmd->scsi_sense_reason != 0) {
+ /*
+ * Out of memory. We will fail with CHECK CONDITION, so
+ * we must not clear the unit attention condition.
+ */
+ target_complete_cmd(cmd, CHECK_CONDITION);
+ return 0;
+ } else if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
/*
* CURRENT ERROR, UNIT ATTENTION
*/
buf[0] = 0x70;
buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
- if (cmd->data_length < 18) {
- buf[7] = 0x00;
- err = -EINVAL;
- goto end;
- }
/*
* The Additional Sense Code (ASC) from the UNIT ATTENTION
*/
@@ -915,11 +918,6 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)
buf[0] = 0x70;
buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
- if (cmd->data_length < 18) {
- buf[7] = 0x00;
- err = -EINVAL;
- goto end;
- }
/*
* NO ADDITIONAL SENSE INFORMATION
*/
@@ -927,8 +925,11 @@ static int spc_emulate_request_sense(struct se_cmd *cmd)
buf[7] = 0x0A;
}
-end:
- transport_kunmap_data_sg(cmd);
+ if (rbuf) {
+ memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+ transport_kunmap_data_sg(cmd);
+ }
+
target_complete_cmd(cmd, GOOD);
return 0;
}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4de3186dc44e..269f54488397 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -567,6 +567,34 @@ static void target_complete_failure_work(struct work_struct *work)
transport_generic_request_failure(cmd);
}
+/*
+ * Used when asking transport to copy Sense Data from the underlying
+ * Linux/SCSI struct scsi_cmnd
+ */
+static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
+{
+ unsigned char *buffer = cmd->sense_buffer;
+ struct se_device *dev = cmd->se_dev;
+ u32 offset = 0;
+
+ WARN_ON(!cmd->se_lun);
+
+ if (!dev)
+ return NULL;
+
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
+ return NULL;
+
+ offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
+
+ /* Automatically padded */
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+
+ pr_debug("HBA_[%u]_PLUG[%s]: Requesting sense for SAM STATUS: 0x%02x\n",
+ dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
+ return &buffer[offset];
+}
+
void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
{
struct se_device *dev = cmd->se_dev;
@@ -580,11 +608,11 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
cmd->transport_state &= ~CMD_T_BUSY;
if (dev && dev->transport->transport_complete) {
- if (dev->transport->transport_complete(cmd,
- cmd->t_data_sg) != 0) {
- cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
+ dev->transport->transport_complete(cmd,
+ cmd->t_data_sg,
+ transport_get_sense_buffer(cmd));
+ if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)
success = 1;
- }
}
/*
@@ -1181,15 +1209,20 @@ int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
/* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
goto out_invalid_cdb_field;
}
-
+ /*
+ * For the overflow case keep the existing fabric provided
+ * ->data_length. Otherwise for the underflow case, reset
+ * ->data_length to the smaller SCSI expected data transfer
+ * length.
+ */
if (size > cmd->data_length) {
cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
cmd->residual_count = (size - cmd->data_length);
} else {
cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
cmd->residual_count = (cmd->data_length - size);
+ cmd->data_length = size;
}
- cmd->data_length = size;
}
return 0;
@@ -1816,61 +1849,6 @@ execute:
EXPORT_SYMBOL(target_execute_cmd);
/*
- * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
- */
-static int transport_get_sense_data(struct se_cmd *cmd)
-{
- unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
- struct se_device *dev = cmd->se_dev;
- unsigned long flags;
- u32 offset = 0;
-
- WARN_ON(!cmd->se_lun);
-
- if (!dev)
- return 0;
-
- spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return 0;
- }
-
- if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
- goto out;
-
- if (!dev->transport->get_sense_buffer) {
- pr_err("dev->transport->get_sense_buffer is NULL\n");
- goto out;
- }
-
- sense_buffer = dev->transport->get_sense_buffer(cmd);
- if (!sense_buffer) {
- pr_err("ITT 0x%08x cmd %p: Unable to locate"
- " sense buffer for task with sense\n",
- cmd->se_tfo->get_task_tag(cmd), cmd);
- goto out;
- }
-
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
- offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
-
- memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
-
- /* Automatically padded */
- cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
-
- pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
- dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
- return 0;
-
-out:
- spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return -1;
-}
-
-/*
* Process all commands up to the last received ORDERED task attribute which
* requires another blocking boundary
*/
@@ -1985,7 +1963,7 @@ static void transport_handle_queue_full(
static void target_complete_ok_work(struct work_struct *work)
{
struct se_cmd *cmd = container_of(work, struct se_cmd, work);
- int reason = 0, ret;
+ int ret;
/*
* Check if we need to move delayed/dormant tasks from cmds on the
@@ -2002,23 +1980,19 @@ static void target_complete_ok_work(struct work_struct *work)
schedule_work(&cmd->se_dev->qf_work_queue);
/*
- * Check if we need to retrieve a sense buffer from
+ * Check if we need to send a sense buffer from
* the struct se_cmd in question.
*/
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
- if (transport_get_sense_data(cmd) < 0)
- reason = TCM_NON_EXISTENT_LUN;
-
- if (cmd->scsi_status) {
- ret = transport_send_check_condition_and_sense(
- cmd, reason, 1);
- if (ret == -EAGAIN || ret == -ENOMEM)
- goto queue_full;
+ WARN_ON(!cmd->scsi_status);
+ ret = transport_send_check_condition_and_sense(
+ cmd, 0, 1);
+ if (ret == -EAGAIN || ret == -ENOMEM)
+ goto queue_full;
- transport_lun_remove_cmd(cmd);
- transport_cmd_check_stop_to_fabric(cmd);
- return;
- }
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
+ return;
}
/*
* Check for a callback, used by amongst other things
@@ -2216,7 +2190,6 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)
struct page **pages;
int i;
- BUG_ON(!sg);
/*
* We need to take into account a possible offset here for fabrics like
* tcm_loop who may be using a contig buffer from the SCSI midlayer for
@@ -2224,13 +2197,17 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)
*/
if (!cmd->t_data_nents)
return NULL;
- else if (cmd->t_data_nents == 1)
+
+ BUG_ON(!sg);
+ if (cmd->t_data_nents == 1)
return kmap(sg_page(sg)) + sg->offset;
/* >1 page. use vmap */
pages = kmalloc(sizeof(*pages) * cmd->t_data_nents, GFP_KERNEL);
- if (!pages)
+ if (!pages) {
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
return NULL;
+ }
/* convert sg[] to pages[] */
for_each_sg(cmd->t_data_sg, sg, cmd->t_data_nents, i) {
@@ -2239,8 +2216,10 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)
cmd->t_data_vmap = vmap(pages, cmd->t_data_nents, VM_MAP, PAGE_KERNEL);
kfree(pages);
- if (!cmd->t_data_vmap)
+ if (!cmd->t_data_vmap) {
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
return NULL;
+ }
return cmd->t_data_vmap + cmd->t_data_sg[0].offset;
}
@@ -2326,19 +2305,14 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
* into the fabric for data transfers, go ahead and complete it right
* away.
*/
- if (!cmd->data_length) {
+ if (!cmd->data_length &&
+ cmd->t_task_cdb[0] != REQUEST_SENSE &&
+ cmd->se_dev->transport->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
spin_lock_irq(&cmd->t_state_lock);
cmd->t_state = TRANSPORT_COMPLETE;
cmd->transport_state |= CMD_T_ACTIVE;
spin_unlock_irq(&cmd->t_state_lock);
- if (cmd->t_task_cdb[0] == REQUEST_SENSE) {
- u8 ua_asc = 0, ua_ascq = 0;
-
- core_scsi3_ua_clear_for_request_sense(cmd,
- &ua_asc, &ua_ascq);
- }
-
INIT_WORK(&cmd->work, target_complete_ok_work);
queue_work(target_completion_wq, &cmd->work);
return 0;
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 6cc4358f68c1..42d0a2581a87 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -420,7 +420,7 @@ static void check_modem_status(struct serial_state *info)
tty_hangup(port->tty);
}
}
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
if (port->tty->hw_stopped) {
if (!(status & SER_CTS)) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
@@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
custom.adkcon = AC_UARTBRK;
mb();
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
info->MCR &= ~(SER_DTR|SER_RTS);
rtsdtr_ctrl(info->MCR);
@@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
int bits;
unsigned long flags;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* Byte size is always 8 bits plus parity bit if requested */
@@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
/* FIXME: Will need updating for new tty in the end */
- tty->termios->c_cflag &= ~CBAUD;
- tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ tty->termios.c_cflag &= ~CBAUD;
+ tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(tty);
if (!baud)
baud = 9600;
@@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
info->MCR &= ~SER_RTS;
local_irq_save(flags);
@@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty)
else
rs_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
info->MCR |= SER_RTS;
local_irq_save(flags);
rtsdtr_ctrl(info->MCR);
@@ -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;
}
@@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct serial_state *info = tty->driver_data;
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
change_speed(tty, info, old_termios);
@@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
if (!(old_termios->c_cflag & CBAUD) &&
(cflag & CBAUD)) {
info->MCR |= SER_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= SER_RTS;
}
@@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ (tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
#endif
}
@@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
- error = tty_register_driver(serial_driver);
- if (error)
- goto fail_put_tty_driver;
-
state = rs_table;
state->port = (int)&custom.serdatr; /* Just to give it a value */
state->custom_divisor = 0;
@@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
state->icount.overrun = state->icount.brk = 0;
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
+ tty_port_link_device(&state->tport, serial_driver, 0);
+
+ error = tty_register_driver(serial_driver);
+ if (error)
+ goto fail_put_tty_driver;
printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 61fc74fe1747..02b7d3a09696 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -263,6 +263,7 @@ static int __init bfin_jc_init(void)
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
+ tty_port_link_device(&port, bfin_jc_driver, 0);
ret = tty_register_driver(bfin_jc_driver);
if (ret)
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabdd69df..0a6a0bc1b598 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -727,7 +727,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
else
tty_hangup(tty);
}
- if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
+ if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
if (tty->hw_stopped) {
if (mdm_status & CyCTS) {
/* cy_start isn't used
@@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
info->port.xmit_buf = NULL;
free_page((unsigned long)temp);
}
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
free_page((unsigned long)temp);
}
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
tty_port_lower_dtr_rts(&info->port);
set_bit(TTY_IO_ERROR, &tty->flags);
@@ -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;
}
@@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
int baud, baud_rate = 0;
int i;
- if (!tty->termios) /* XXX can this happen at all? */
- return;
-
if (info->line == -1)
return;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/*
* Set up the tty->alt_speed kludge
@@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
cy_set_line_char(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
cy_start(tty);
}
@@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* or not. Hence, this may change.....
*/
if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ (tty->termios.c_cflag & CLOCAL))
wake_up_interruptible(&info->port.open_wait);
#endif
} /* cy_set_termios */
@@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty)
info->throttle = 1;
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
card = info->card;
if (!cy_is_Z(card)) {
spin_lock_irqsave(&card->card_lock, flags);
@@ -3289,9 +3286,10 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
static int __init cy_detect_isa(void)
{
#ifdef CONFIG_ISA
+ struct cyclades_card *card;
unsigned short cy_isa_irq, nboard;
void __iomem *cy_isa_address;
- unsigned short i, j, cy_isa_nchan;
+ unsigned short i, j, k, cy_isa_nchan;
int isparam = 0;
nboard = 0;
@@ -3349,7 +3347,8 @@ static int __init cy_detect_isa(void)
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == NULL)
+ card = &cy_card[j];
+ if (card->base_addr == NULL)
break;
}
if (j == NR_CARDS) { /* no more cy_cards available */
@@ -3363,7 +3362,7 @@ static int __init cy_detect_isa(void)
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
- 0, "Cyclom-Y", &cy_card[j])) {
+ 0, "Cyclom-Y", card)) {
printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
"could not allocate IRQ#%d.\n",
(unsigned long)cy_isa_address, cy_isa_irq);
@@ -3372,16 +3371,16 @@ static int __init cy_detect_isa(void)
}
/* set cy_card */
- cy_card[j].base_addr = cy_isa_address;
- cy_card[j].ctl_addr.p9050 = NULL;
- cy_card[j].irq = (int)cy_isa_irq;
- cy_card[j].bus_index = 0;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
- cy_card[j].nports = cy_isa_nchan;
- if (cy_init_card(&cy_card[j])) {
- cy_card[j].base_addr = NULL;
- free_irq(cy_isa_irq, &cy_card[j]);
+ card->base_addr = cy_isa_address;
+ card->ctl_addr.p9050 = NULL;
+ card->irq = (int)cy_isa_irq;
+ card->bus_index = 0;
+ card->first_line = cy_next_channel;
+ card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
+ card->nports = cy_isa_nchan;
+ if (cy_init_card(card)) {
+ card->base_addr = NULL;
+ free_irq(cy_isa_irq, card);
iounmap(cy_isa_address);
continue;
}
@@ -3393,9 +3392,10 @@ static int __init cy_detect_isa(void)
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
cy_isa_irq, cy_isa_nchan, cy_next_channel);
- for (j = cy_next_channel;
- j < cy_next_channel + cy_isa_nchan; j++)
- tty_register_device(cy_serial_driver, j, NULL);
+ for (k = 0, j = cy_next_channel;
+ j < cy_next_channel + cy_isa_nchan; j++, k++)
+ tty_port_register_device(&card->ports[k].port,
+ cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@@ -3695,10 +3695,11 @@ err:
static int __devinit cy_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ struct cyclades_card *card;
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
u32 uninitialized_var(mailbox);
- unsigned int device_id, nchan = 0, card_no, i;
+ unsigned int device_id, nchan = 0, card_no, i, j;
unsigned char plx_ver;
int retval, irq;
@@ -3829,7 +3830,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* fill the next cy_card structure available */
for (card_no = 0; card_no < NR_CARDS; card_no++) {
- if (cy_card[card_no].base_addr == NULL)
+ card = &cy_card[card_no];
+ if (card->base_addr == NULL)
break;
}
if (card_no == NR_CARDS) { /* no more cy_cards available */
@@ -3843,27 +3845,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
/* allocate IRQ */
retval = request_irq(irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+ IRQF_SHARED, "Cyclom-Y", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
}
- cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
+ card->num_chips = nchan / CyPORTS_PER_CHIP;
} else {
struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl;
zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
- cy_card[card_no].hw_ver = mailbox;
- cy_card[card_no].num_chips = (unsigned int)-1;
- cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
+ card->hw_ver = mailbox;
+ card->num_chips = (unsigned int)-1;
+ card->board_ctrl = &zfw_ctrl->board_ctrl;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
retval = request_irq(irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z",
- &cy_card[card_no]);
+ IRQF_SHARED, "Cyclades-Z", card);
if (retval) {
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
@@ -3873,17 +3874,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* set cy_card */
- cy_card[card_no].base_addr = addr2;
- cy_card[card_no].ctl_addr.p9050 = addr0;
- cy_card[card_no].irq = irq;
- cy_card[card_no].bus_index = 1;
- cy_card[card_no].first_line = cy_next_channel;
- cy_card[card_no].nports = nchan;
- retval = cy_init_card(&cy_card[card_no]);
+ card->base_addr = addr2;
+ card->ctl_addr.p9050 = addr0;
+ card->irq = irq;
+ card->bus_index = 1;
+ card->first_line = cy_next_channel;
+ card->nports = nchan;
+ retval = cy_init_card(card);
if (retval)
goto err_null;
- pci_set_drvdata(pdev, &cy_card[card_no]);
+ pci_set_drvdata(pdev, card);
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
@@ -3909,14 +3910,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
- for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
- tty_register_device(cy_serial_driver, i, &pdev->dev);
+ for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
+ tty_port_register_device(&card->ports[j].port,
+ cy_serial_driver, i, &pdev->dev);
cy_next_channel += nchan;
return 0;
err_null:
- cy_card[card_no].base_addr = NULL;
- free_irq(irq, &cy_card[card_no]);
+ card->base_addr = NULL;
+ free_irq(irq, card);
err_unmap:
iounmap(addr0);
if (addr2)
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 4813684cb634..4ab936b7aac6 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
goto error;
}
- bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
+ tty_port_init(&bc->port);
+ bc->port.ops = &ehv_bc_tty_port_ops;
+
+ bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
+ &pdev->dev);
if (IS_ERR(bc->dev)) {
ret = PTR_ERR(bc->dev);
dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
goto error;
}
- tty_port_init(&bc->port);
- bc->port.ops = &ehv_bc_tty_port_ops;
-
dev_set_drvdata(&pdev->dev, bc);
dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 2d691eb7c40a..7f80f15681cd 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty)
hvc_kick();
}
+static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct hvc_struct *hp;
+ int rc;
+
+ /* Auto increments kref reference if found. */
+ if (!(hp = hvc_get_by_index(tty->index)))
+ return -ENODEV;
+
+ tty->driver_data = hp;
+
+ rc = tty_port_install(&hp->port, driver, tty);
+ if (rc)
+ tty_port_put(&hp->port);
+ return rc;
+}
+
/*
* The TTY interface won't be used until after the vio layer has exposed the vty
* adapter to the kernel.
*/
static int hvc_open(struct tty_struct *tty, struct file * filp)
{
- struct hvc_struct *hp;
+ struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
int rc = 0;
- /* Auto increments kref reference if found. */
- if (!(hp = hvc_get_by_index(tty->index)))
- return -ENODEV;
-
spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
if (hp->port.count++ > 0) {
@@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
} /* else count == 0 */
spin_unlock_irqrestore(&hp->port.lock, flags);
- tty->driver_data = hp;
tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
@@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp->vtermno, hp->port.count);
spin_unlock_irqrestore(&hp->port.lock, flags);
}
+}
+
+static void hvc_cleanup(struct tty_struct *tty)
+{
+ struct hvc_struct *hp = tty->driver_data;
tty_port_put(&hp->port);
}
@@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
#endif
static const struct tty_operations hvc_ops = {
+ .install = hvc_install,
.open = hvc_open,
.close = hvc_close,
+ .cleanup = hvc_cleanup,
.write = hvc_write,
.hangup = hvc_hangup,
.unthrottle = hvc_unthrottle,
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index d56788c83974..cab5c7adf8e8 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
return NULL;
}
-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
+static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct hvcs_struct *hvcsd;
- int rc, retval = 0;
- unsigned long flags;
- unsigned int irq;
struct vio_dev *vdev;
- unsigned long unit_address;
-
- if (tty->driver_data)
- goto fast_open;
+ unsigned long unit_address, flags;
+ unsigned int irq;
+ int retval;
/*
* Is there a vty-server that shares the same index?
* This function increments the kref index.
*/
- if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+ hvcsd = hvcs_get_by_index(tty->index);
+ if (!hvcsd) {
printk(KERN_WARNING "HVCS: open failed, no device associated"
" with tty->index %d.\n", tty->index);
return -ENODEV;
@@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hvcsd->lock, flags);
- if (hvcsd->connected == 0)
- if ((retval = hvcs_partner_connect(hvcsd)))
- goto error_release;
+ if (hvcsd->connected == 0) {
+ retval = hvcs_partner_connect(hvcsd);
+ if (retval) {
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ printk(KERN_WARNING "HVCS: partner connect failed.\n");
+ goto err_put;
+ }
+ }
- hvcsd->port.count = 1;
+ hvcsd->port.count = 0;
hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
@@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* This must be done outside of the spinlock because it requests irqs
* and will grab the spinlock and free the connection if it fails.
*/
- if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- tty_port_put(&hvcsd->port);
+ retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
+ if (retval) {
printk(KERN_WARNING "HVCS: enable device failed.\n");
- return rc;
+ goto err_put;
}
- goto open_success;
+ retval = tty_port_install(&hvcsd->port, driver, tty);
+ if (retval)
+ goto err_irq;
-fast_open:
- hvcsd = tty->driver_data;
+ return 0;
+err_irq:
+ spin_lock_irqsave(&hvcsd->lock, flags);
+ vio_disable_interrupts(hvcsd->vdev);
+ spin_unlock_irqrestore(&hvcsd->lock, flags);
+ free_irq(irq, hvcsd);
+err_put:
+ tty_port_put(&hvcsd->port);
+
+ return retval;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+ unsigned long flags;
spin_lock_irqsave(&hvcsd->lock, flags);
- tty_port_get(&hvcsd->port);
hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
-open_success:
hvcs_kick();
printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
hvcsd->vdev->unit_address );
return 0;
-
-error_release:
- spin_unlock_irqrestore(&hvcsd->lock, flags);
- tty_port_put(&hvcsd->port);
-
- printk(KERN_WARNING "HVCS: partner connect failed.\n");
- return retval;
}
static void hvcs_close(struct tty_struct *tty, struct file *filp)
@@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
- tty_port_put(&hvcsd->port);
return;
} else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+static void hvcs_cleanup(struct tty_struct * tty)
+{
+ struct hvcs_struct *hvcsd = tty->driver_data;
+
tty_port_put(&hvcsd->port);
}
@@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
}
static const struct tty_operations hvcs_ops = {
+ .install = hvcs_install,
.open = hvcs_open,
.close = hvcs_close,
+ .cleanup = hvcs_cleanup,
.hangup = hvcs_hangup,
.write = hvcs_write,
.write_room = hvcs_write_room,
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index 6f5bc49c441f..0083bc1f63f4 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1080,6 +1080,8 @@ static int __init hvsi_init(void)
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;
+ tty_port_link_device(&hp->port, hvsi_driver, i);
+
ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 59c135dd5d20..3396eb9d57a3 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
spin_unlock_irqrestore(&hp->lock, flags);
/* Clear our own DTR */
- if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL))
+ if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
hvsilib_write_mctrl(pv, 0);
/* Tear down the connection */
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index f8b5fa0093a3..160f0ad9589d 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -476,7 +476,7 @@ static int add_tty(int j,
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
- tty_register_device(ipw_tty_driver, j, NULL);
+ tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
if (secondary_channel_idx != -1)
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index e1235accab74..d7492e183607 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -600,7 +600,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
port->status &= ~ISI_DCD;
}
- if (port->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (header & ISI_CTS) {
port->port.tty->hw_stopped = 0;
@@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty)
/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
if (baud < 1 || baud > 4)
- tty->termios->c_cflag &= ~CBAUDEX;
+ tty->termios.c_cflag &= ~CBAUDEX;
else
baud += 15;
}
@@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty,
if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
return;
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
+ if (tty->termios.c_cflag == old_termios->c_cflag &&
+ tty->termios.c_iflag == old_termios->c_iflag)
return;
spin_lock_irqsave(&port->card->card_lock, flags);
@@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty,
spin_unlock_irqrestore(&port->card->card_lock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
isicom_start(tty);
}
@@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
goto errunri;
for (index = 0; index < board->port_count; index++)
- tty_register_device(isicom_normal, board->index * 16 + index,
+ tty_port_register_device(&board->ports[index].port,
+ isicom_normal, board->index * 16 + index,
&pdev->dev);
return 0;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index 324467d28a54..56e616b9109a 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock);
static unsigned long baseaddr[MAX_BOARDS];
static unsigned int type[MAX_BOARDS];
static unsigned int numports[MAX_BOARDS];
+static struct tty_port moxa_service_port;
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
@@ -367,10 +368,10 @@ static int moxa_ioctl(struct tty_struct *tty,
tmp.dcd = 1;
ttyp = tty_port_tty_get(&p->port);
- if (!ttyp || !ttyp->termios)
+ if (!ttyp)
tmp.cflag = p->cflag;
else
- tmp.cflag = ttyp->termios->c_cflag;
+ tmp.cflag = ttyp->termios.c_cflag;
tty_kref_put(ttyp);
copy:
if (copy_to_user(argm, &tmp, sizeof(tmp)))
@@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
const struct firmware *fw;
const char *file;
struct moxa_port *p;
- unsigned int i;
+ unsigned int i, first_idx;
int ret;
brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
@@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
mod_timer(&moxaTimer, jiffies + HZ / 50);
spin_unlock_bh(&moxa_lock);
+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (i = 0; i < brd->numPorts; i++)
+ tty_port_register_device(&brd->ports[i].port, moxaDriver,
+ first_idx + i, dev);
+
return 0;
err_free:
kfree(brd->ports);
@@ -896,7 +902,7 @@ err:
static void moxa_board_deinit(struct moxa_board_conf *brd)
{
- unsigned int a, opened;
+ unsigned int a, opened, first_idx;
mutex_lock(&moxa_openlock);
spin_lock_bh(&moxa_lock);
@@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
mutex_lock(&moxa_openlock);
}
+ first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+ for (a = 0; a < brd->numPorts; a++)
+ tty_unregister_device(moxaDriver, first_idx + a);
+
iounmap(brd->basemem);
brd->basemem = NULL;
kfree(brd->ports);
@@ -967,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
+ retval = -ENOMEM;
goto err_reg;
}
@@ -1031,9 +1042,14 @@ static int __init moxa_init(void)
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
- moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
- if (!moxaDriver)
- return -ENOMEM;
+
+ tty_port_init(&moxa_service_port);
+
+ moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV);
+ if (IS_ERR(moxaDriver))
+ return PTR_ERR(moxaDriver);
moxaDriver->name = "ttyMX";
moxaDriver->major = ttymajor;
@@ -1044,8 +1060,9 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
- moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
+ /* Having one more port only for ioctls is ugly */
+ tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@@ -1178,7 +1195,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
mutex_lock(&ch->port.mutex);
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
- moxa_set_tty_param(tty, tty->termios);
+ moxa_set_tty_param(tty, &tty->termios);
MoxaPortLineCtrl(ch, 1, 1);
MoxaPortEnable(ch);
MoxaSetFifo(ch, ch->type == PORT_16550A);
@@ -1193,7 +1210,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
static void moxa_close(struct tty_struct *tty, struct file *filp)
{
struct moxa_port *ch = tty->driver_data;
- ch->cflag = tty->termios->c_cflag;
+ ch->cflag = tty->termios.c_cflag;
tty_port_close(&ch->port, tty, filp);
}
@@ -1464,7 +1481,7 @@ static void moxa_poll(unsigned long ignored)
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts = tty->termios;
+ register struct ktermios *ts = &tty->termios;
struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 90cc680c4f0e..cfda47dabd28 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty,
int ret = 0;
unsigned char status;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
if (!info->ioaddr)
return ret;
@@ -830,7 +830,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
wake_up_interruptible(&port->port.open_wait);
}
- if (port->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&port->port)) {
if (tty->hw_stopped) {
if (status & UART_MSR_CTS) {
tty->hw_stopped = 0;
@@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(port);
- if (!tty || !tty->termios)
+ if (!tty)
ms.cflag = ip->normal_termios.c_cflag;
else
- ms.cflag = tty->termios->c_cflag;
+ ms.cflag = tty->termios.c_cflag;
tty_kref_put(tty);
spin_lock_irq(&ip->slock);
status = inb(ip->ioaddr + UART_MSR);
@@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
tty = tty_port_tty_get(&ip->port);
- if (!tty || !tty->termios) {
+ if (!tty) {
cflag = ip->normal_termios.c_cflag;
iflag = ip->normal_termios.c_iflag;
me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
} else {
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
me->baudrate[p] = tty_get_baud_rate(tty);
}
tty_kref_put(tty);
@@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
}
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->ioaddr + UART_MCR);
}
@@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
spin_unlock_irqrestore(&info->slock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) &&
- !(tty->termios->c_iflag & IXON)) {
+ !(tty->termios.c_iflag & IXON)) {
tty->stopped = 0;
if (info->board->chip_flag) {
@@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
+static bool allow_overlapping_vector;
+module_param(allow_overlapping_vector, bool, S_IRUGO);
+MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
+
+static bool mxser_overlapping_vector(struct mxser_board *brd)
+{
+ return allow_overlapping_vector &&
+ brd->vector >= brd->ports[0].ioaddr &&
+ brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
+}
+
+static int mxser_request_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return 0;
+ return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
+}
+
+static void mxser_release_vector(struct mxser_board *brd)
+{
+ if (mxser_overlapping_vector(brd))
+ return;
+ release_region(brd->vector, 1);
+}
+
static void mxser_release_ISA_res(struct mxser_board *brd)
{
free_irq(brd->irq, brd);
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
- release_region(brd->vector, 1);
+ mxser_release_vector(brd);
}
static int __devinit mxser_initbrd(struct mxser_board *brd,
@@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
{
- int id, i, bits;
+ int id, i, bits, ret;
unsigned short regs[16], irq;
unsigned char scratch, scratch2;
@@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
8 * brd->info->nports - 1);
return -EIO;
}
- if (!request_region(brd->vector, 1, "mxser(vector)")) {
+
+ ret = mxser_request_vector(brd);
+ if (ret) {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
printk(KERN_ERR "mxser: can't request interrupt vector region: "
"0x%.8lx-0x%.8lx\n",
brd->ports[0].ioaddr, brd->ports[0].ioaddr +
8 * brd->info->nports - 1);
- return -EIO;
+ return ret;
}
return brd->info->nports;
@@ -2598,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
goto err_rel3;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+ tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
+ brd->idx + i, &pdev->dev);
pci_set_drvdata(pdev, brd);
@@ -2695,7 +2723,8 @@ static int __init mxser_module_init(void)
brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
+ tty_port_register_device(&brd->ports[i].port,
+ mxvar_sdriver, brd->idx + i, NULL);
m++;
}
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c43b683b6eb8..3e210a430fb3 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -108,7 +108,7 @@ struct gsm_mux_net {
*/
struct gsm_msg {
- struct gsm_msg *next;
+ struct list_head list;
u8 addr; /* DLCI address + flags */
u8 ctrl; /* Control byte + flags */
unsigned int len; /* Length of data block (can be zero) */
@@ -245,8 +245,7 @@ struct gsm_mux {
unsigned int tx_bytes; /* TX data outstanding */
#define TX_THRESH_HI 8192
#define TX_THRESH_LO 2048
- struct gsm_msg *tx_head; /* Pending data packets */
- struct gsm_msg *tx_tail;
+ struct list_head tx_list; /* Pending data packets */
/* Control messages */
struct timer_list t2_timer; /* Retransmit timer for commands */
@@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
m->len = len;
m->addr = addr;
m->ctrl = ctrl;
- m->next = NULL;
+ INIT_LIST_HEAD(&m->list);
return m;
}
@@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
*
* The tty device has called us to indicate that room has appeared in
* the transmit queue. Ram more data into the pipe if we have any
+ * If we have been flow-stopped by a CMD_FCOFF, then we can only
+ * send messages on DLCI0 until CMD_FCON
*
* FIXME: lock against link layer control transmissions
*/
static void gsm_data_kick(struct gsm_mux *gsm)
{
- struct gsm_msg *msg = gsm->tx_head;
+ struct gsm_msg *msg, *nmsg;
int len;
int skip_sof = 0;
- /* FIXME: We need to apply this solely to data messages */
- if (gsm->constipated)
- return;
-
- while (gsm->tx_head != NULL) {
- msg = gsm->tx_head;
+ list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
+ if (gsm->constipated && msg->addr)
+ continue;
if (gsm->encoding != 0) {
gsm->txframe[0] = GSM1_SOF;
len = gsm_stuff_frame(msg->data,
@@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
len - skip_sof) < 0)
break;
/* FIXME: Can eliminate one SOF in many more cases */
- gsm->tx_head = msg->next;
- if (gsm->tx_head == NULL)
- gsm->tx_tail = NULL;
gsm->tx_bytes -= msg->len;
- kfree(msg);
/* For a burst of frames skip the extra SOF within the
burst */
skip_sof = 1;
+
+ list_del(&msg->list);
+ kfree(msg);
}
}
@@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
msg->data = dp;
/* Add to the actual output queue */
- if (gsm->tx_tail)
- gsm->tx_tail->next = msg;
- else
- gsm->tx_head = msg;
- gsm->tx_tail = msg;
+ list_add_tail(&msg->list, &gsm->tx_list);
gsm->tx_bytes += msg->len;
gsm_data_kick(gsm);
}
@@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* dlci->skb is locked by tx_lock */
if (dlci->skb == NULL) {
- dlci->skb = skb_dequeue(&dlci->skb_list);
+ dlci->skb = skb_dequeue_tail(&dlci->skb_list);
if (dlci->skb == NULL)
return 0;
first = 1;
@@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
if (len > gsm->mtu) {
if (dlci->adaption == 3) {
/* Over long frame, bin it */
- kfree_skb(dlci->skb);
+ dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
return 0;
}
@@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
/* FIXME: need a timer or something to kick this so it can't
get stuck with no work outstanding and no buffer free */
- if (msg == NULL)
+ if (msg == NULL) {
+ skb_queue_tail(&dlci->skb_list, dlci->skb);
+ dlci->skb = NULL;
return -ENOMEM;
+ }
dp = msg->data;
if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
@@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
skb_pull(dlci->skb, len);
__gsm_data_queue(dlci, msg);
if (last) {
- kfree_skb(dlci->skb);
+ dev_kfree_skb_any(dlci->skb);
dlci->skb = NULL;
}
return size;
@@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
{
unsigned long flags;
+ int sweep;
+
+ if (dlci->constipated)
+ return;
spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
/* If we have nothing running then we need to fire up */
+ sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
if (dlci->gsm->tx_bytes == 0) {
if (dlci->net)
gsm_dlci_data_output_framed(dlci->gsm, dlci);
else
gsm_dlci_data_output(dlci->gsm, dlci);
- } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
- gsm_dlci_data_sweep(dlci->gsm);
+ }
+ if (sweep)
+ gsm_dlci_data_sweep(dlci->gsm);
spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
}
@@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
{
int mlines = 0;
u8 brk = 0;
+ int fc;
/* The modem status command can either contain one octet (v.24 signals)
or two octets (v.24 signals + break signals). The length field will
@@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
else {
brk = modem & 0x7f;
modem = (modem >> 7) & 0x7f;
- };
+ }
/* Flow control/ready to communicate */
- if (modem & MDM_FC) {
+ fc = (modem & MDM_FC) || !(modem & MDM_RTR);
+ if (fc && !dlci->constipated) {
/* Need to throttle our output on this device */
dlci->constipated = 1;
- }
- if (modem & MDM_RTC) {
- mlines |= TIOCM_DSR | TIOCM_DTR;
+ } else if (!fc && dlci->constipated) {
dlci->constipated = 0;
gsm_dlci_data_kick(dlci);
}
+
/* Map modem bits */
+ if (modem & MDM_RTC)
+ mlines |= TIOCM_DSR | TIOCM_DTR;
if (modem & MDM_RTR)
mlines |= TIOCM_RTS | TIOCM_CTS;
if (modem & MDM_IC)
@@ -1061,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
/* Carrier drop -> hangup */
if (tty) {
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
- if (!(tty->termios->c_cflag & CLOCAL))
+ if (!(tty->termios.c_cflag & CLOCAL))
tty_hangup(tty);
if (brk & 0x01)
tty_insert_flip_char(tty, 0, TTY_BREAK);
@@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
u8 *data, int clen)
{
u8 buf[1];
+ unsigned long flags;
+
switch (command) {
case CMD_CLD: {
struct gsm_dlci *dlci = gsm->dlci[0];
@@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
gsm_control_reply(gsm, CMD_TEST, data, clen);
break;
case CMD_FCON:
- /* Modem wants us to STFU */
- gsm->constipated = 1;
- gsm_control_reply(gsm, CMD_FCON, NULL, 0);
- break;
- case CMD_FCOFF:
/* Modem can accept data again */
gsm->constipated = 0;
- gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+ gsm_control_reply(gsm, CMD_FCON, NULL, 0);
/* Kick the link in case it is idling */
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
+ break;
+ case CMD_FCOFF:
+ /* Modem wants us to STFU */
+ gsm->constipated = 1;
+ gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
break;
case CMD_MSC:
/* Out of band modem line change indicator for a DLCI */
@@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref)
dlci->gsm->dlci[dlci->addr] = NULL;
kfifo_free(dlci->fifo);
while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
- kfree_skb(dlci->skb);
+ dev_kfree_skb(dlci->skb);
kfree(dlci);
}
@@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
{
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
- struct gsm_msg *txq;
+ struct gsm_msg *txq, *ntxq;
struct gsm_control *gc;
gsm->dead = 1;
@@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
if (gsm->dlci[i])
gsm_dlci_release(gsm->dlci[i]);
/* Now wipe the queues */
- for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
- gsm->tx_head = txq->next;
+ list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
kfree(txq);
- }
- gsm->tx_tail = NULL;
+ INIT_LIST_HEAD(&gsm->tx_list);
}
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
@@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void)
}
spin_lock_init(&gsm->lock);
kref_init(&gsm->ref);
+ INIT_LIST_HEAD(&gsm->tx_list);
gsm->t1 = T1;
gsm->t2 = T2;
@@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
gsm->error(gsm, *dp, flags);
break;
default:
- WARN_ONCE("%s: unknown flag %d\n",
+ WARN_ONCE(1, "%s: unknown flag %d\n",
tty_name(tty, buf), flags);
break;
}
@@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_data_kick(gsm);
if (gsm->tx_bytes < TX_THRESH_LO) {
- spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_data_sweep(gsm);
- spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
@@ -2868,14 +2876,14 @@ static const struct tty_port_operations gsm_port_ops = {
.dtr_rts = gsm_dtr_rts,
};
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_mux *gsm;
struct gsm_dlci *dlci;
- struct tty_port *port;
unsigned int line = tty->index;
unsigned int mux = line >> 6;
+ bool alloc = false;
+ int ret;
line = line & 0x3F;
@@ -2889,14 +2897,35 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
gsm = gsm_mux[mux];
if (gsm->dead)
return -EL2HLT;
+ /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
+ perspective as we don't have to worry about this if DLCI0 is lost */
+ if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
+ return -EL2NSYNC;
dlci = gsm->dlci[line];
- if (dlci == NULL)
+ if (dlci == NULL) {
+ alloc = true;
dlci = gsm_dlci_alloc(gsm, line);
+ }
if (dlci == NULL)
return -ENOMEM;
- port = &dlci->port;
- port->count++;
+ ret = tty_port_install(&dlci->port, driver, tty);
+ if (ret) {
+ if (alloc)
+ dlci_put(dlci);
+ return ret;
+ }
+
tty->driver_data = dlci;
+
+ return 0;
+}
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+ struct gsm_dlci *dlci = tty->driver_data;
+ struct tty_port *port = &dlci->port;
+
+ port->count++;
dlci_get(dlci);
dlci_get(dlci->gsm->dlci[0]);
mux_get(dlci->gsm);
@@ -3043,13 +3072,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
the RPN control message. This however rapidly gets nasty as we
then have to remap modem signals each way according to whether
our virtual cable is null modem etc .. */
- tty_termios_copy_hw(tty->termios, old);
+ tty_termios_copy_hw(&tty->termios, old);
}
static void gsmtty_throttle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1;
/* Send an MSC with DTR cleared */
@@ -3059,7 +3088,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
static void gsmtty_unthrottle(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0;
/* Send an MSC with DTR set */
@@ -3085,6 +3114,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops = {
+ .install = gsmtty_install,
.open = gsmtty_open,
.close = gsmtty_close,
.write = gsmtty_write,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c31459a2f..1e6405070ce6 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
- tty_lock();
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1077,7 +1077,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 +1107,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 +1156,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 +1175,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 ee1c268f5f9d..8c0b7b42319c 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
static void n_tty_set_room(struct tty_struct *tty)
{
- /* tty->read_cnt is not read locked ? */
- int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+ int left;
int old_left;
+ /* tty->read_cnt is not read locked ? */
+ if (I_PARMRK(tty)) {
+ /* Multiply read_cnt by 3, since each byte might take up to
+ * three times as many spaces when PARMRK is set (depending on
+ * its flags, e.g. parity error). */
+ left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+ } else
+ left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
/*
* If we are doing input canonicalization, and there are no
* pending newlines, let characters through without limit, so
@@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
tty_throttle(tty);
+
+ /* FIXME: there is a tiny race here if the receive room check runs
+ before the other work executes and empties the buffer (upping
+ the receiving room and unthrottling. We then throttle and get
+ stuck. This has been observed and traced down by Vincent Pillet/
+ We need to address this when we sort out out the rx path locking */
}
int is_ignored(int sig)
@@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
BUG_ON(!tty);
if (old)
- canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+ canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
if (canon_change) {
memset(&tty->read_flags, 0, sizeof tty->read_flags);
tty->canon_head = tty->read_tail;
@@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
do_it_again:
- BUG_ON(!tty->read_buf);
+ if (WARN_ON(!tty->read_buf))
+ return -EAGAIN;
c = job_control(tty, file);
if (c < 0)
@@ -1832,13 +1847,13 @@ do_it_again:
if (tty->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */
+ spin_lock_irqsave(&tty->read_lock, flags);
while (nr && tty->read_cnt) {
int eol;
eol = test_and_clear_bit(tty->read_tail,
tty->read_flags);
c = tty->read_buf[tty->read_tail];
- spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = ((tty->read_tail+1) &
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
@@ -1856,15 +1871,19 @@ do_it_again:
if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
+ spin_lock_irqsave(&tty->read_lock, flags);
break;
}
nr--;
}
if (eol) {
tty_audit_push(tty);
+ spin_lock_irqsave(&tty->read_lock, flags);
break;
}
+ spin_lock_irqsave(&tty->read_lock, flags);
}
+ spin_unlock_irqrestore(&tty->read_lock, flags);
if (retval)
break;
} else {
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index e7592f9037da..b917c9424954 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
port->dc = dc;
tty_port_init(&port->port);
port->port.ops = &noz_tty_port_ops;
- tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
- &pdev->dev);
+ tty_dev = tty_port_register_device(&port->port, ntty_driver,
+ dc->index_start + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
ret = PTR_ERR(tty_dev);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 5505ffc91da4..2bace847eb39 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -47,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;
@@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&devpts_mutex);
}
#endif
- tty_unlock();
+ tty_unlock(tty);
tty_vhangup(tty->link);
- tty_lock();
+ tty_lock(tty);
}
}
@@ -231,8 +232,8 @@ out:
static void pty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
- tty->termios->c_cflag &= ~(CSIZE | PARENB);
- tty->termios->c_cflag |= (CS8 | CREAD);
+ tty->termios.c_cflag &= ~(CSIZE | PARENB);
+ tty->termios.c_cflag |= (CS8 | CREAD);
}
/**
@@ -282,60 +283,110 @@ done:
return 0;
}
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+/**
+ * pty_common_install - set up the pty pair
+ * @driver: the pty driver
+ * @tty: the tty being instantiated
+ * @bool: legacy, true if this is BSD style
+ *
+ * Perform the initial set up for the tty/pty pair. Called from the
+ * tty layer when the port is first opened.
+ *
+ * Locking: the caller must hold the tty_mutex
+ */
+static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
+ bool legacy)
{
struct tty_struct *o_tty;
+ struct tty_port *ports[2];
int idx = tty->index;
- int retval;
+ int retval = -ENOMEM;
o_tty = alloc_tty_struct();
if (!o_tty)
- return -ENOMEM;
+ goto err;
+ ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
+ ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
+ if (!ports[0] || !ports[1])
+ goto err_free_tty;
if (!try_module_get(driver->other->owner)) {
/* This cannot in fact currently happen */
- retval = -ENOMEM;
goto err_free_tty;
}
initialize_tty_struct(o_tty, driver->other, idx);
- /* We always use new tty termios data so we can do this
- the easy way .. */
- retval = tty_init_termios(tty);
- if (retval)
- goto err_deinit_tty;
-
- retval = tty_init_termios(o_tty);
- if (retval)
- goto err_free_termios;
+ if (legacy) {
+ /* We always use new tty termios data so we can do this
+ the easy way .. */
+ retval = tty_init_termios(tty);
+ if (retval)
+ goto err_deinit_tty;
+
+ retval = tty_init_termios(o_tty);
+ if (retval)
+ goto err_free_termios;
+
+ driver->other->ttys[idx] = o_tty;
+ driver->ttys[idx] = tty;
+ } else {
+ memset(&tty->termios_locked, 0, sizeof(tty->termios_locked));
+ tty->termios = driver->init_termios;
+ memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked));
+ o_tty->termios = driver->other->init_termios;
+ }
/*
* Everything allocated ... set up the o_tty structure.
*/
- driver->other->ttys[idx] = o_tty;
tty_driver_kref_get(driver->other);
if (driver->subtype == PTY_TYPE_MASTER)
o_tty->count++;
/* Establish the links in both directions */
tty->link = o_tty;
o_tty->link = tty;
+ tty_port_init(ports[0]);
+ tty_port_init(ports[1]);
+ o_tty->port = ports[0];
+ tty->port = ports[1];
tty_driver_kref_get(driver);
tty->count++;
- driver->ttys[idx] = tty;
return 0;
err_free_termios:
- tty_free_termios(tty);
+ if (legacy)
+ tty_free_termios(tty);
err_deinit_tty:
deinitialize_tty_struct(o_tty);
module_put(o_tty->driver->owner);
err_free_tty:
+ kfree(ports[0]);
+ kfree(ports[1]);
free_tty_struct(o_tty);
+err:
return retval;
}
+static void pty_cleanup(struct tty_struct *tty)
+{
+ kfree(tty->port);
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ return pty_common_install(driver, tty, true);
+}
+
+static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct tty_struct *pair = tty->link;
+ driver->ttys[tty->index] = NULL;
+ if (pair)
+ pair->driver->ttys[pair->index] = NULL;
+}
+
static int pty_bsd_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -366,7 +417,9 @@ static const struct tty_operations master_pty_ops_bsd = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_bsd_ioctl,
- .resize = pty_resize
+ .cleanup = pty_cleanup,
+ .resize = pty_resize,
+ .remove = pty_remove
};
static const struct tty_operations slave_pty_ops_bsd = {
@@ -379,7 +432,9 @@ static const struct tty_operations slave_pty_ops_bsd = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
- .resize = pty_resize
+ .cleanup = pty_cleanup,
+ .resize = pty_resize,
+ .remove = pty_remove
};
static void __init legacy_pty_init(void)
@@ -389,12 +444,18 @@ static void __init legacy_pty_init(void)
if (legacy_count <= 0)
return;
- pty_driver = alloc_tty_driver(legacy_count);
- if (!pty_driver)
+ pty_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pty_driver))
panic("Couldn't allocate pty driver");
- pty_slave_driver = alloc_tty_driver(legacy_count);
- if (!pty_slave_driver)
+ pty_slave_driver = tty_alloc_driver(legacy_count,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pty_slave_driver))
panic("Couldn't allocate pty slave driver");
pty_driver->driver_name = "pty_master";
@@ -410,7 +471,6 @@ static void __init legacy_pty_init(void)
pty_driver->init_termios.c_lflag = 0;
pty_driver->init_termios.c_ispeed = 38400;
pty_driver->init_termios.c_ospeed = 38400;
- pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &master_pty_ops_bsd);
@@ -424,8 +484,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver->init_termios.c_ispeed = 38400;
pty_slave_driver->init_termios.c_ospeed = 38400;
- pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW;
pty_slave_driver->other = pty_driver;
tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
@@ -497,78 +555,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
return tty;
}
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
- tty_driver_remove_tty(tty->driver, tty);
- /* We have our own method as we don't use the tty index */
- kfree(tty->termios);
-}
-
/* We have no need to install and remove our tty objects as devpts does all
the work for us */
static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
{
- struct tty_struct *o_tty;
- int idx = tty->index;
-
- o_tty = alloc_tty_struct();
- if (!o_tty)
- return -ENOMEM;
- if (!try_module_get(driver->other->owner)) {
- /* This cannot in fact currently happen */
- goto err_free_tty;
- }
- initialize_tty_struct(o_tty, driver->other, idx);
-
- tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
- if (tty->termios == NULL)
- goto err_free_mem;
- *tty->termios = driver->init_termios;
- tty->termios_locked = tty->termios + 1;
-
- o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
- if (o_tty->termios == NULL)
- goto err_free_mem;
- *o_tty->termios = driver->other->init_termios;
- o_tty->termios_locked = o_tty->termios + 1;
-
- tty_driver_kref_get(driver->other);
- if (driver->subtype == PTY_TYPE_MASTER)
- o_tty->count++;
- /* Establish the links in both directions */
- tty->link = o_tty;
- o_tty->link = tty;
- /*
- * All structures have been allocated, so now we install them.
- * Failures after this point use release_tty to clean up, so
- * there's no need to null out the local pointers.
- */
- tty_driver_kref_get(driver);
- tty->count++;
- return 0;
-err_free_mem:
- deinitialize_tty_struct(o_tty);
- kfree(o_tty->termios);
- kfree(tty->termios);
- module_put(o_tty->driver->owner);
-err_free_tty:
- free_tty_struct(o_tty);
- return -ENOMEM;
-}
-
-static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
+ return pty_common_install(driver, tty, false);
}
-static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
}
static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup,
.install = pty_unix98_install,
- .remove = ptm_unix98_remove,
+ .remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -578,14 +580,14 @@ static const struct tty_operations ptm_unix98_ops = {
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
- .shutdown = pty_unix98_shutdown,
- .resize = pty_resize
+ .resize = pty_resize,
+ .cleanup = pty_cleanup
};
static const struct tty_operations pty_unix98_ops = {
.lookup = pts_unix98_lookup,
.install = pty_unix98_install,
- .remove = pts_unix98_remove,
+ .remove = pty_unix98_remove,
.open = pty_open,
.close = pty_close,
.write = pty_write,
@@ -594,7 +596,7 @@ static const struct tty_operations pty_unix98_ops = {
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
- .shutdown = pty_unix98_shutdown
+ .cleanup = pty_cleanup,
};
/**
@@ -622,26 +624,27 @@ 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);
- mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
- mutex_unlock(&devpts_mutex);
- tty_lock();
- 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(&tty_mutex);
+
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
@@ -654,16 +657,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;
}
@@ -672,11 +676,21 @@ static struct file_operations ptmx_fops;
static void __init unix98_pty_init(void)
{
- ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
- if (!ptm_driver)
+ ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(ptm_driver))
panic("Couldn't allocate Unix98 ptm driver");
- pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
- if (!pts_driver)
+ pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+ TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_DEVPTS_MEM |
+ TTY_DRIVER_DYNAMIC_ALLOC);
+ if (IS_ERR(pts_driver))
panic("Couldn't allocate Unix98 pts driver");
ptm_driver->driver_name = "pty_master";
@@ -692,8 +706,6 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->init_termios.c_ispeed = 38400;
ptm_driver->init_termios.c_ospeed = 38400;
- ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &ptm_unix98_ops);
@@ -707,8 +719,6 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->init_termios.c_ispeed = 38400;
pts_driver->init_termios.c_ospeed = 38400;
- pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_unix98_ops);
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 777d5f9cf6cc..9700d34b20a3 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
spin_lock_init(&info->slock);
mutex_init(&info->write_mtx);
rp_table[line] = info;
- tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
- NULL);
+ tty_port_register_device(&info->port, rocket_driver, line,
+ pci_dev ? &pci_dev->dev : NULL);
}
/*
@@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info,
unsigned rocketMode;
int bits, baud, divisor;
CHANNEL_t *cp;
- struct ktermios *t = tty->termios;
+ struct ktermios *t = &tty->termios;
cp = &info->channel;
cflag = t->c_cflag;
@@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
tty->alt_speed = 460800;
configure_r_port(tty, info, NULL);
- if (tty->termios->c_cflag & CBAUD) {
+ if (tty->termios.c_cflag & CBAUD) {
sSetDTR(cp);
sSetRTS(cp);
}
@@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty,
if (rocket_paranoia_check(info, "rp_set_termios"))
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/*
* This driver doesn't support CS5 or CS6
*/
if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
- tty->termios->c_cflag =
+ tty->termios.c_cflag =
((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
/* Or CMSPAR */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
configure_r_port(tty, info, old_termios);
cp = &info->channel;
/* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
+ if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
sClrDTR(cp);
sClrRTS(cp);
}
/* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
- if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
+ if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
+ if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
sSetRTS(cp);
sSetDTR(cp);
}
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rp_start(tty);
}
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 3ed20e435e59..66c38a3f74ce 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
unsigned cflag;
int i;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
if (!(port = info->port))
return;
@@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
return;
- info->is_cons = (tty->termios->c_line == N_TTY);
+ info->is_cons = (tty->termios.c_line == N_TTY);
printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
}
@@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
+ tty->termios.c_line = N_TTY;
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
@@ -1189,12 +1189,6 @@ rs68328_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &rs_ops);
- if (tty_register_driver(serial_driver)) {
- put_tty_driver(serial_driver);
- printk(KERN_ERR "Couldn't register serial driver\n");
- return -ENOMEM;
- }
-
local_irq_save(flags);
for(i=0;i<NR_PORTS;i++) {
@@ -1224,8 +1218,17 @@ rs68328_init(void)
0,
"M68328_UART", info))
panic("Unable to attach 68328 serial interrupt\n");
+
+ tty_port_link_device(&info->tport, serial_driver, i);
}
local_irq_restore(flags);
+
+ if (tty_register_driver(serial_driver)) {
+ put_tty_driver(serial_driver);
+ printk(KERN_ERR "Couldn't register serial driver\n");
+ return -ENOMEM;
+ }
+
return 0;
}
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 8123f784bcda..d4e0b07cb130 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -2202,6 +2202,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
+ int fifo_bug = 0;
switch (termios->c_cflag & CSIZE) {
case CS5:
@@ -2221,8 +2222,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
+ if (termios->c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
+ if (up->bugs & UART_BUG_PARITY)
+ fifo_bug = 1;
+ }
if (!(termios->c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
@@ -2246,7 +2250,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
fcr = uart_config[port->type].fcr;
- if (baud < 2400) {
+ if (baud < 2400 || fifo_bug) {
fcr &= ~UART_FCR_TRIGGER_MASK;
fcr |= UART_FCR_TRIGGER_1;
}
@@ -2336,7 +2340,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP1
/* Workaround to enable 115200 baud on OMAP1510 internal ports */
if (cpu_is_omap1510() && is_omap_port(up)) {
if (baud == 115200) {
@@ -2426,7 +2430,7 @@ static unsigned int serial8250_port_size(struct uart_8250_port *pt)
{
if (pt->port.iotype == UPIO_AU)
return 0x1000;
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP1
if (is_omap_port(pt))
return 0x16 << pt->port.regshift;
#endif
@@ -2979,36 +2983,36 @@ void serial8250_resume_port(int line)
static int __devinit serial8250_probe(struct platform_device *dev)
{
struct plat_serial8250_port *p = dev->dev.platform_data;
- struct uart_port port;
+ struct uart_8250_port uart;
int ret, i, irqflag = 0;
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
if (share_irqs)
irqflag = IRQF_SHARED;
for (i = 0; p && p->flags != 0; p++, i++) {
- port.iobase = p->iobase;
- port.membase = p->membase;
- port.irq = p->irq;
- port.irqflags = p->irqflags;
- port.uartclk = p->uartclk;
- port.regshift = p->regshift;
- port.iotype = p->iotype;
- port.flags = p->flags;
- port.mapbase = p->mapbase;
- port.hub6 = p->hub6;
- port.private_data = p->private_data;
- port.type = p->type;
- 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;
- port.irqflags |= irqflag;
- ret = serial8250_register_port(&port);
+ uart.port.iobase = p->iobase;
+ uart.port.membase = p->membase;
+ uart.port.irq = p->irq;
+ uart.port.irqflags = p->irqflags;
+ uart.port.uartclk = p->uartclk;
+ uart.port.regshift = p->regshift;
+ uart.port.iotype = p->iotype;
+ uart.port.flags = p->flags;
+ uart.port.mapbase = p->mapbase;
+ uart.port.hub6 = p->hub6;
+ uart.port.private_data = p->private_data;
+ uart.port.type = p->type;
+ uart.port.serial_in = p->serial_in;
+ uart.port.serial_out = p->serial_out;
+ uart.port.handle_irq = p->handle_irq;
+ uart.port.handle_break = p->handle_break;
+ uart.port.set_termios = p->set_termios;
+ uart.port.pm = p->pm;
+ uart.port.dev = &dev->dev;
+ uart.port.irqflags |= irqflag;
+ ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
@@ -3081,7 +3085,7 @@ static struct platform_driver serial8250_isa_driver = {
static struct platform_device *serial8250_isa_devs;
/*
- * serial8250_register_port and serial8250_unregister_port allows for
+ * serial8250_register_8250_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
*/
@@ -3155,6 +3159,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.regshift = up->port.regshift;
uart->port.iotype = up->port.iotype;
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
uart->port.private_data = up->port.private_data;
if (up->port.dev)
@@ -3198,29 +3203,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
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);
-
-/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
*
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index f9719d167c8d..0c5e908df0b5 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -13,36 +13,6 @@
#include <linux/serial_8250.h>
-struct uart_8250_port {
- struct uart_port port;
- struct timer_list timer; /* "no irq" timer */
- struct list_head list; /* ports on this IRQ */
- unsigned short capabilities; /* port capabilities */
- unsigned short bugs; /* port bugs */
- unsigned int tx_loadsz; /* transmit fifo load size */
- unsigned char acr;
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned char mcr_mask; /* mask of user bits */
- unsigned char mcr_force; /* mask of forced bits */
- unsigned char cur_iotype; /* Running I/O type */
-
- /*
- * Some bits in registers are cleared on a read, so they must
- * be saved whenever the register is read but the bits will not
- * be immediately processed.
- */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
- 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 {
unsigned int uart;
unsigned int baud_base;
@@ -56,9 +26,6 @@ struct old_serial_port {
unsigned long irqflags;
};
-/*
- * This replaces serial_uart_config in include/linux/serial.h
- */
struct serial8250_config {
const char *name;
unsigned short fifo_size;
@@ -78,6 +45,7 @@ struct serial8250_config {
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
#define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
+#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
#define PROBE_RSA (1 << 0)
#define PROBE_ANY (~0)
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index b0ce8c56f1a4..857498312a9a 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct serial_card_info *info;
struct serial_card_type *type = id->data;
- struct uart_port port;
+ struct uart_8250_port uart;
unsigned long bus_addr;
unsigned int i;
@@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
ecard_set_drvdata(ec, info);
- memset(&port, 0, sizeof(struct uart_port));
- port.irq = ec->irq;
- port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
- port.uartclk = type->uartclk;
- port.iotype = UPIO_MEM;
- port.regshift = 2;
- port.dev = &ec->dev;
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+ uart.port.irq = ec->irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ uart.port.uartclk = type->uartclk;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.regshift = 2;
+ uart.port.dev = &ec->dev;
for (i = 0; i < info->num_ports; i ++) {
- port.membase = info->vaddr + type->offset[i];
- port.mapbase = bus_addr + type->offset[i];
+ uart.port.membase = info->vaddr + type->offset[i];
+ uart.port.mapbase = bus_addr + type->offset[i];
- info->ports[i] = serial8250_register_port(&port);
+ info->ports[i] = serial8250_register_8250_port(&uart);
}
return 0;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index f574eef3075f..c3b2ec0c8c0b 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p)
static int __devinit dw8250_probe(struct platform_device *pdev)
{
- struct uart_port port = {};
+ struct uart_8250_port uart = {};
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
struct device_node *np = pdev->dev.of_node;
@@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- port.private_data = data;
-
- spin_lock_init(&port.lock);
- port.mapbase = regs->start;
- port.irq = irq->start;
- port.handle_irq = dw8250_handle_irq;
- port.type = PORT_8250;
- port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+ uart.port.private_data = data;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.mapbase = regs->start;
+ uart.port.irq = irq->start;
+ uart.port.handle_irq = dw8250_handle_irq;
+ uart.port.type = PORT_8250;
+ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
UPF_FIXED_PORT | UPF_FIXED_TYPE;
- port.dev = &pdev->dev;
+ uart.port.dev = &pdev->dev;
- port.iotype = UPIO_MEM;
- port.serial_in = dw8250_serial_in;
- port.serial_out = dw8250_serial_out;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.serial_in = dw8250_serial_in;
+ uart.port.serial_out = dw8250_serial_out;
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
case 4:
- port.iotype = UPIO_MEM32;
- port.serial_in = dw8250_serial_in32;
- port.serial_out = dw8250_serial_out32;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.serial_in = dw8250_serial_in32;
+ uart.port.serial_out = dw8250_serial_out32;
break;
default:
dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
@@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
}
if (!of_property_read_u32(np, "reg-shift", &val))
- port.regshift = val;
+ uart.port.regshift = val;
if (of_property_read_u32(np, "clock-frequency", &val)) {
dev_err(&pdev->dev, "no clock-frequency property set\n");
return -EINVAL;
}
- port.uartclk = val;
+ uart.port.uartclk = val;
- data->line = serial8250_register_port(&port);
+ data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
return data->line;
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index d8c0ffbfa6e3..097dff9c08ad 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -26,7 +26,7 @@
static int __init serial_init_chip(struct parisc_device *dev)
{
- struct uart_port port;
+ struct uart_8250_port uart;
unsigned long address;
int err;
@@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev)
if (dev->id.sversion != 0x8d)
address += 0x800;
- memset(&port, 0, sizeof(port));
- port.iotype = UPIO_MEM;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.iotype = UPIO_MEM;
/* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
- port.uartclk = 7272727;
- port.mapbase = address;
- port.membase = ioremap_nocache(address, 16);
- port.irq = dev->irq;
- port.flags = UPF_BOOT_AUTOCONF;
- port.dev = &dev->dev;
-
- err = serial8250_register_port(&port);
+ uart.port.uartclk = 7272727;
+ uart.port.mapbase = address;
+ uart.port.membase = ioremap_nocache(address, 16);
+ uart.port.irq = dev->irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF;
+ uart.port.dev = &dev->dev;
+
+ err = serial8250_register_8250_port(&uart);
if (err < 0) {
printk(KERN_WARNING
- "serial8250_register_port returned error %d\n", err);
- iounmap(port.membase);
+ "serial8250_register_8250_port returned error %d\n", err);
+ iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index c13438c93012..8f1dd2cc00a8 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
return 0;
}
#endif
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
/* Memory mapped I/O */
port.iotype = UPIO_MEM;
@@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
port.regshift = 1;
port.dev = &d->dev;
- line = serial8250_register_port(&port);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
@@ -210,7 +210,7 @@ static int __init hp300_8250_init(void)
#ifdef CONFIG_HPAPCI
int line;
unsigned long base;
- struct uart_port uport;
+ struct uart_8250_port uart;
struct hp300_port *port;
int i;
#endif
@@ -248,26 +248,26 @@ static int __init hp300_8250_init(void)
if (!port)
return -ENOMEM;
- memset(&uport, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
/* Memory mapped I/O */
- uport.iotype = UPIO_MEM;
- uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
+ uart.port.iotype = UPIO_MEM;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
| UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
- uport.irq = 0;
- uport.uartclk = HPAPCI_BAUD_BASE * 16;
- uport.mapbase = base;
- uport.membase = (char *)(base + DIO_VIRADDRBASE);
- uport.regshift = 2;
+ uart.port.irq = 0;
+ uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
+ uart.port.mapbase = base;
+ uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
+ uart.port.regshift = 2;
- line = serial8250_register_port(&uport);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uport.irq);
+ " %d irq %d failed\n", i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 28e7c7cce893..fdab80a4e063 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -44,7 +44,7 @@ struct pci_serial_quirk {
int (*init)(struct pci_dev *dev);
int (*setup)(struct serial_private *,
const struct pciserial_board *,
- struct uart_port *, int);
+ struct uart_8250_port *, int);
void (*exit)(struct pci_dev *dev);
};
@@ -59,7 +59,7 @@ struct serial_private {
};
static int pci_default_setup(struct serial_private*,
- const struct pciserial_board*, struct uart_port*, int);
+ const struct pciserial_board*, struct uart_8250_port *, int);
static void moan_device(const char *str, struct pci_dev *dev)
{
@@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
}
static int
-setup_port(struct serial_private *priv, struct uart_port *port,
+setup_port(struct serial_private *priv, struct uart_8250_port *port,
int bar, int offset, int regshift)
{
struct pci_dev *dev = priv->dev;
@@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port,
if (!priv->remapped_bar[bar])
return -ENOMEM;
- port->iotype = UPIO_MEM;
- port->iobase = 0;
- port->mapbase = base + offset;
- port->membase = priv->remapped_bar[bar] + offset;
- port->regshift = regshift;
+ port->port.iotype = UPIO_MEM;
+ port->port.iobase = 0;
+ port->port.mapbase = base + offset;
+ port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.regshift = regshift;
} else {
- port->iotype = UPIO_PORT;
- port->iobase = base + offset;
- port->mapbase = 0;
- port->membase = NULL;
- port->regshift = 0;
+ port->port.iotype = UPIO_PORT;
+ port->port.iobase = base + offset;
+ port->port.mapbase = 0;
+ port->port.membase = NULL;
+ port->port.regshift = 0;
}
return 0;
}
@@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
*/
static int addidata_apci7800_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
bar = FL_GET_BASE(board->flags);
@@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
*/
static int
afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev)
static int
pci_hp_diva_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int offset = board->first_offset;
unsigned int bar = FL_GET_BASE(board->flags);
@@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int
sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev)
static int pci_siig_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev)
static int
pci_timedia_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv,
static int
titan_400l_800l_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
static int
pci_ni8430_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
void __iomem *p;
unsigned long base, len;
@@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv,
static int pci_netmos_9900_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
unsigned int bar;
@@ -1032,10 +1032,17 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
return number_uarts;
}
-static int
-pci_default_setup(struct serial_private *priv,
+static int pci_asix_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
+{
+ port->bugs |= UART_BUG_PARITY;
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int pci_default_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
@@ -1057,15 +1064,15 @@ pci_default_setup(struct serial_private *priv,
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
int ret;
ret = setup_port(priv, port, 0, 0, board->reg_shift);
- port->iotype = UPIO_MEM32;
- port->type = PORT_XSCALE;
- port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
- port->regshift = 2;
+ port->port.iotype = UPIO_MEM32;
+ port->port.type = PORT_XSCALE;
+ port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+ port->port.regshift = 2;
return ret;
}
@@ -1073,16 +1080,16 @@ ce4100_serial_setup(struct serial_private *priv,
static int
pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
return setup_port(priv, port, 2, idx * 8, 0);
}
static int skip_tx_en_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_NO_TXEN_TEST;
+ port->port.flags |= UPF_NO_TXEN_TEST;
printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
"[%04x:%04x] subsystem [%04x:%04x]\n",
priv->dev->vendor,
@@ -1131,11 +1138,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset)
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_BUG_THRE;
- port->serial_in = kt_serial_in;
- port->handle_break = kt_handle_break;
+ port->port.flags |= UPF_BUG_THRE;
+ port->port.serial_in = kt_serial_in;
+ port->port.handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
@@ -1151,9 +1158,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
- struct uart_port *port, int idx)
+ struct uart_8250_port *port, int idx)
+{
+ port->port.flags |= UPF_EXAR_EFR;
+ return pci_default_setup(priv, board, port, idx);
+}
+
+static int
+pci_wch_ch353_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
- port->flags |= UPF_EXAR_EFR;
+ port->port.flags |= UPF_FIXED_TYPE;
+ port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
}
@@ -1187,6 +1204,13 @@ pci_xr17c154_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
+#define PCI_VENDOR_ID_WCH 0x4348
+#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
+#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
+#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
+#define PCI_VENDOR_ID_AGESTAR 0x5372
+#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
+#define PCI_VENDOR_ID_ASIX 0x9710
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@@ -1726,7 +1750,41 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_omegapci_setup,
- },
+ },
+ /* WCH CH353 2S1P card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 4S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_4S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /* WCH CH353 2S1PF card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
+ /*
+ * ASIX devices with FIFO bug
+ */
+ {
+ .vendor = PCI_VENDOR_ID_ASIX,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_asix_setup,
+ },
/*
* Default "match everything" terminator entry
*/
@@ -1887,7 +1945,6 @@ enum pci_board_num_t {
pbn_panacom,
pbn_panacom2,
pbn_panacom4,
- pbn_exsys_4055,
pbn_plx_romulus,
pbn_oxsemi,
pbn_oxsemi_1_4000000,
@@ -2393,13 +2450,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.reg_shift = 7,
},
- [pbn_exsys_4055] = {
- .flags = FL_BASE2,
- .num_ports = 4,
- .base_baud = 115200,
- .uart_offset = 8,
- },
-
/* I think this entry is broken - the first_offset looks wrong --rmk */
[pbn_plx_romulus] = {
.flags = FL_BASE2,
@@ -2624,10 +2674,14 @@ static struct pciserial_board pci_boards[] __devinitdata = {
},
};
-static const struct pci_device_id softmodem_blacklist[] = {
+static const struct pci_device_id blacklist[] = {
+ /* softmodems */
{ PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */
{ PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */
{ PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */
+
+ /* multi-io cards handled by parport_serial */
+ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
};
/*
@@ -2638,7 +2692,7 @@ static const struct pci_device_id softmodem_blacklist[] = {
static int __devinit
serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
{
- const struct pci_device_id *blacklist;
+ const struct pci_device_id *bldev;
int num_iomem, num_port, first_port = -1, i;
/*
@@ -2655,13 +2709,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
/*
* Do not access blacklisted devices that are known not to
- * feature serial ports.
+ * feature serial ports or are handled by other modules.
*/
- for (blacklist = softmodem_blacklist;
- blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
- blacklist++) {
- if (dev->vendor == blacklist->vendor &&
- dev->device == blacklist->device)
+ for (bldev = blacklist;
+ bldev < blacklist + ARRAY_SIZE(blacklist);
+ bldev++) {
+ if (dev->vendor == bldev->vendor &&
+ dev->device == bldev->device)
return -ENODEV;
}
@@ -2728,7 +2782,7 @@ serial_pci_matches(const struct pciserial_board *board,
struct serial_private *
pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
{
- struct uart_port serial_port;
+ struct uart_8250_port uart;
struct serial_private *priv;
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
@@ -2768,22 +2822,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
priv->dev = dev;
priv->quirk = quirk;
- memset(&serial_port, 0, sizeof(struct uart_port));
- serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
- serial_port.uartclk = board->base_baud * 16;
- serial_port.irq = get_pci_irq(dev, board);
- serial_port.dev = &dev->dev;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+ uart.port.uartclk = board->base_baud * 16;
+ uart.port.irq = get_pci_irq(dev, board);
+ uart.port.dev = &dev->dev;
for (i = 0; i < nr_ports; i++) {
- if (quirk->setup(priv, board, &serial_port, i))
+ if (quirk->setup(priv, board, &uart, i))
break;
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
- serial_port.iobase, serial_port.irq, serial_port.iotype);
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
#endif
- priv->line[i] = serial8250_register_port(&serial_port);
+ priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
break;
@@ -3193,7 +3247,7 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_EXSYS,
PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
- pbn_exsys_4055 },
+ pbn_b2_4_115200 },
/*
* Megawolf Romulus PCI Serial Card, from Mike Hudson
* (Exoray@isys.ca)
@@ -4179,6 +4233,25 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_omegapci },
/*
+ * AgeStar as-prs2-009
+ */
+ { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
+ * WCH CH353 series devices: The 2S1P is handled by parport_serial
+ * so not listed here.
+ */
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_4_115200 },
+
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index a2f236510ff1..fde5aa60d51e 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
static int __devinit
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
- struct uart_port port;
+ struct uart_8250_port uart;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
@@ -433,32 +433,32 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
return ret;
}
- memset(&port, 0, sizeof(struct uart_port));
+ memset(&uart, 0, sizeof(uart));
if (pnp_irq_valid(dev, 0))
- port.irq = pnp_irq(dev, 0);
+ uart.port.irq = pnp_irq(dev, 0);
if (pnp_port_valid(dev, 0)) {
- port.iobase = pnp_port_start(dev, 0);
- port.iotype = UPIO_PORT;
+ uart.port.iobase = pnp_port_start(dev, 0);
+ uart.port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
- port.mapbase = pnp_mem_start(dev, 0);
- port.iotype = UPIO_MEM;
- port.flags = UPF_IOREMAP;
+ uart.port.mapbase = pnp_mem_start(dev, 0);
+ uart.port.iotype = UPIO_MEM;
+ uart.port.flags = UPF_IOREMAP;
} else
return -ENODEV;
#ifdef SERIAL_DEBUG_PNP
printk(KERN_DEBUG
"Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- port.iobase, port.mapbase, port.irq, port.iotype);
+ uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
#endif
- port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
- port.flags |= UPF_SHARE_IRQ;
- port.uartclk = 1843200;
- port.dev = &dev->dev;
+ uart.port.flags |= UPF_SHARE_IRQ;
+ uart.port.uartclk = 1843200;
+ uart.port.dev = &dev->dev;
- line = serial8250_register_port(&port);
+ line = serial8250_register_8250_port(&uart);
if (line < 0)
return -ENODEV;
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 29b695d041ec..b7d48b346393 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -73,7 +73,7 @@ struct serial_quirk {
unsigned int prodid;
int multi; /* 1 = multifunction, > 1 = # ports */
void (*config)(struct pcmcia_device *);
- void (*setup)(struct pcmcia_device *, struct uart_port *);
+ void (*setup)(struct pcmcia_device *, struct uart_8250_port *);
void (*wakeup)(struct pcmcia_device *);
int (*post)(struct pcmcia_device *);
};
@@ -105,9 +105,9 @@ struct serial_cfg_mem {
* Elan VPU16551 UART with 14.7456MHz oscillator
* manfid 0x015D, 0x4C45
*/
-static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart)
{
- port->uartclk = 14745600;
+ uart->port.uartclk = 14745600;
}
static int quirk_post_ibm(struct pcmcia_device *link)
@@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link)
static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
unsigned int iobase, int irq)
{
- struct uart_port port;
+ struct uart_8250_port uart;
int line;
- memset(&port, 0, sizeof (struct uart_port));
- port.iobase = iobase;
- port.irq = irq;
- port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
- port.uartclk = 1843200;
- port.dev = &handle->dev;
+ memset(&uart, 0, sizeof(uart));
+ uart.port.iobase = iobase;
+ uart.port.irq = irq;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ uart.port.uartclk = 1843200;
+ uart.port.dev = &handle->dev;
if (buggy_uart)
- port.flags |= UPF_BUGGY_UART;
+ uart.port.flags |= UPF_BUGGY_UART;
if (info->quirk && info->quirk->setup)
- info->quirk->setup(handle, &port);
+ info->quirk->setup(handle, &uart);
- line = serial8250_register_port(&port);
+ line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
- "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
+ pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
+ (unsigned long)iobase, irq);
return -EINVAL;
}
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 4720b4ba096a..26907cf25744 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -257,12 +257,19 @@ config SERIAL_MAX3100
help
MAX3100 chip support
-config SERIAL_MAX3107
- tristate "MAX3107 support"
+config SERIAL_MAX310X
+ bool "MAX310X support"
depends on SPI
select SERIAL_CORE
+ select REGMAP_SPI if SPI
+ default n
help
- MAX3107 chip support
+ This selects support for an advanced UART from Maxim (Dallas).
+ Supported ICs are MAX3107, MAX3108.
+ Each IC contains 128 words each of receive and transmit FIFO
+ that can be controlled through I2C or high-speed SPI.
+
+ Say Y here if you want to support this ICs.
config SERIAL_DZ
bool "DECstation DZ serial driver"
@@ -704,6 +711,25 @@ config SERIAL_PNX8XXX_CONSOLE
If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
and you want to use serial console, say Y. Otherwise, say N.
+config SERIAL_HS_LPC32XX
+ tristate "LPC32XX high speed serial port support"
+ depends on ARCH_LPC32XX && OF
+ select SERIAL_CORE
+ help
+ Support for the LPC32XX high speed serial ports (up to 900kbps).
+ Those are UARTs completely different from the Standard UARTs on the
+ LPC32XX SoC.
+ Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+ bool "Enable LPC32XX high speed UART serial console"
+ depends on SERIAL_HS_LPC32XX
+ select SERIAL_CORE_CONSOLE
+ help
+ If you would like to be able to use one of the high speed serial
+ ports on the LPC32XX as the console, you can do so by answering
+ Y to this option.
+
config SERIAL_CORE
tristate
@@ -1104,6 +1130,24 @@ config SERIAL_SC26XX_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
+config SERIAL_SCCNXP
+ bool "SCCNXP serial port support"
+ depends on !SERIAL_SC26XX
+ select SERIAL_CORE
+ default n
+ help
+ This selects support for an advanced UART from NXP (Philips).
+ Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,
+ SC28L202, SCC68681 and SCC68692.
+ Positioned as a replacement for the driver SC26XX.
+
+config SERIAL_SCCNXP_CONSOLE
+ bool "Console on SCCNXP serial port"
+ depends on SERIAL_SCCNXP
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for console on SCCNXP serial ports.
+
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7257c5d898ae..ce88667cfd17 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -28,12 +28,13 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
-obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_MCF) += mcf.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
@@ -47,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
+obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1f0330915d5a..15d80b9fb303 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -591,7 +591,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
- dev_set_drvdata(&pdev->dev, port);
+ platform_set_drvdata(pdev, port);
uart_add_one_port(&altera_uart_driver, port);
@@ -600,11 +600,11 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
static int __devexit altera_uart_remove(struct platform_device *pdev)
{
- struct uart_port *port = dev_get_drvdata(&pdev->dev);
+ struct uart_port *port = platform_get_drvdata(pdev);
if (port) {
uart_remove_one_port(&altera_uart_driver, port);
- dev_set_drvdata(&pdev->dev, NULL);
+ platform_set_drvdata(pdev, NULL);
port->mapbase = 0;
}
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 0d91a540bf11..22317dd16474 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -312,16 +312,12 @@ static int pl010_startup(struct uart_port *port)
struct uart_amba_port *uap = (struct uart_amba_port *)port;
int retval;
- retval = clk_prepare(uap->clk);
- if (retval)
- goto out;
-
/*
* Try to enable the clock producer.
*/
- retval = clk_enable(uap->clk);
+ retval = clk_prepare_enable(uap->clk);
if (retval)
- goto clk_unprep;
+ goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@@ -346,9 +342,7 @@ static int pl010_startup(struct uart_port *port)
return 0;
clk_dis:
- clk_disable(uap->clk);
- clk_unprep:
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
out:
return retval;
}
@@ -375,8 +369,7 @@ static void pl010_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
- clk_disable(uap->clk);
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
}
static void
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d3553b5d3fca..cede93876649 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -52,6 +52,8 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
@@ -75,7 +77,6 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
- bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
bool cts_event_workaround;
};
@@ -96,7 +97,6 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
- .interrupt_may_hang = true,
.dma_threshold = true,
.cts_event_workaround = true,
};
@@ -147,7 +147,6 @@ struct uart_amba_port {
unsigned int old_cr; /* state during shutdown */
bool autorts;
char type[12];
- bool interrupt_may_hang; /* vendor-specific */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -1215,14 +1214,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static unsigned int pl01x_tx_empty(struct uart_port *port)
+static unsigned int pl011_tx_empty(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status = readw(uap->port.membase + UART01x_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
}
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
+static unsigned int pl011_get_mctrl(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int result = 0;
@@ -1285,7 +1284,7 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
}
#ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
+static int pl011_get_poll_char(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status;
@@ -1297,7 +1296,7 @@ static int pl010_get_poll_char(struct uart_port *port)
return readw(uap->port.membase + UART01x_DR);
}
-static void pl010_put_poll_char(struct uart_port *port,
+static void pl011_put_poll_char(struct uart_port *port,
unsigned char ch)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1324,16 +1323,12 @@ static int pl011_startup(struct uart_port *port)
"could not set default pins\n");
}
- retval = clk_prepare(uap->clk);
- if (retval)
- goto out;
-
/*
* Try to enable the clock producer.
*/
- retval = clk_enable(uap->clk);
+ retval = clk_prepare_enable(uap->clk);
if (retval)
- goto clk_unprep;
+ goto out;
uap->port.uartclk = clk_get_rate(uap->clk);
@@ -1411,9 +1406,7 @@ static int pl011_startup(struct uart_port *port)
return 0;
clk_dis:
- clk_disable(uap->clk);
- clk_unprep:
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
out:
return retval;
}
@@ -1473,8 +1466,7 @@ static void pl011_shutdown(struct uart_port *port)
/*
* Shut down the clock producer
*/
- clk_disable(uap->clk);
- clk_unprepare(uap->clk);
+ clk_disable_unprepare(uap->clk);
/* Optionally let pins go into sleep states */
if (!IS_ERR(uap->pins_sleep)) {
retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep);
@@ -1637,7 +1629,7 @@ static const char *pl011_type(struct uart_port *port)
/*
* Release the memory region(s) being used by 'port'
*/
-static void pl010_release_port(struct uart_port *port)
+static void pl011_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, SZ_4K);
}
@@ -1645,7 +1637,7 @@ static void pl010_release_port(struct uart_port *port)
/*
* Request the memory region(s) being used by 'port'
*/
-static int pl010_request_port(struct uart_port *port)
+static int pl011_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
!= NULL ? 0 : -EBUSY;
@@ -1654,18 +1646,18 @@ static int pl010_request_port(struct uart_port *port)
/*
* Configure/autoconfigure the port.
*/
-static void pl010_config_port(struct uart_port *port, int flags)
+static void pl011_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_AMBA;
- pl010_request_port(port);
+ pl011_request_port(port);
}
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
@@ -1678,9 +1670,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
}
static struct uart_ops amba_pl011_pops = {
- .tx_empty = pl01x_tx_empty,
+ .tx_empty = pl011_tx_empty,
.set_mctrl = pl011_set_mctrl,
- .get_mctrl = pl01x_get_mctrl,
+ .get_mctrl = pl011_get_mctrl,
.stop_tx = pl011_stop_tx,
.start_tx = pl011_start_tx,
.stop_rx = pl011_stop_rx,
@@ -1691,13 +1683,13 @@ static struct uart_ops amba_pl011_pops = {
.flush_buffer = pl011_dma_flush_buffer,
.set_termios = pl011_set_termios,
.type = pl011_type,
- .release_port = pl010_release_port,
- .request_port = pl010_request_port,
- .config_port = pl010_config_port,
- .verify_port = pl010_verify_port,
+ .release_port = pl011_release_port,
+ .request_port = pl011_request_port,
+ .config_port = pl011_config_port,
+ .verify_port = pl011_verify_port,
#ifdef CONFIG_CONSOLE_POLL
- .poll_get_char = pl010_get_poll_char,
- .poll_put_char = pl010_put_poll_char,
+ .poll_get_char = pl011_get_poll_char,
+ .poll_put_char = pl011_put_poll_char,
#endif
};
@@ -1869,6 +1861,38 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE,
};
+static int pl011_probe_dt_alias(int index, struct device *dev)
+{
+ struct device_node *np;
+ static bool seen_dev_with_alias = false;
+ static bool seen_dev_without_alias = false;
+ int ret = index;
+
+ if (!IS_ENABLED(CONFIG_OF))
+ return ret;
+
+ np = dev->of_node;
+ if (!np)
+ return ret;
+
+ ret = of_alias_get_id(np, "serial");
+ if (IS_ERR_VALUE(ret)) {
+ seen_dev_without_alias = true;
+ ret = index;
+ } else {
+ seen_dev_with_alias = true;
+ if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
+ dev_warn(dev, "requested serial port %d not available.\n", ret);
+ ret = index;
+ }
+ }
+
+ if (seen_dev_with_alias && seen_dev_without_alias)
+ dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n");
+
+ return ret;
+}
+
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
@@ -1891,6 +1915,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
+ i = pl011_probe_dt_alias(i, &dev->dev);
+
base = ioremap(dev->res.start, resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
@@ -1923,7 +1949,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
uap->fifosize = vendor->fifosize;
- uap->interrupt_may_hang = vendor->interrupt_may_hang;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index bd97db23985b..9242d56ba267 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
* To avoid losting RX interrupt, we reset IR function
* before sending data.
*/
- if (tty->termios->c_line == N_IRDA)
+ if (tty->termios.c_line == N_IRDA)
bfin_serial_reset_irda(port);
#ifdef CONFIG_SERIAL_BFIN_DMA
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 80b6b1b1f725..35ee6a2c6877 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
- tcflag_t cflags = info->port.tty->termios->c_cflag;
+ tcflag_t cflags = info->port.tty->termios.c_cflag;
int bits;
/* calc. number of bits / data byte */
@@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
- if (tty->termios->c_iflag & IXON ) {
+ if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty)
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (tty->termios->c_iflag & IXON ) {
+ if (tty->termios.c_iflag & IXON ) {
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
}
@@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info)
descr[i].buf = 0;
}
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+ if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
/* hang up DTR and RTS if HUPCL is enabled */
e100_dtr(info, 0);
e100_rts(info, 0); /* could check CRTSCTS before doing this */
@@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info)
unsigned long flags;
/* first some safety checks */
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (!info->ioport)
return;
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* possibly, the tx/rx should be disabled first to do this safely */
@@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info)
info->ioport[REG_REC_CTRL] = info->rx_ctrl;
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
- if (info->port.tty->termios->c_iflag & IXON ) {
+ if (info->port.tty->termios.c_iflag & IXON ) {
DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
STOP_CHAR(info->port.tty)));
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
@@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
/* Turn off RTS line */
e100_rts(info, 0);
}
@@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty)
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
/* Assert RTS line */
e100_rts(info, 1);
}
@@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
rs_start(tty);
}
@@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
* separate termios for callout and dialin.
*/
if (info->flags & ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
+ info->normal_termios = tty->termios;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
@@ -3976,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)
@@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL) {
+ if (tty->termios.c_cflag & CLOCAL) {
do_clocal = 1;
}
@@ -4052,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);
@@ -4115,7 +4115,7 @@ rs_open(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
return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
}
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- *tty->termios = info->normal_termios;
+ tty->termios = info->normal_termios;
change_speed(info);
}
@@ -4443,14 +4443,12 @@ static int __init rs_init(void)
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
driver->init_termios.c_ispeed = 115200;
driver->init_termios.c_ospeed = 115200;
- driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(driver, &rs_ops);
serial_driver = driver;
- if (tty_register_driver(driver))
- panic("Couldn't register serial driver\n");
- /* do some initializing for the separate ports */
+ /* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
if (info->enabled) {
if (cris_request_io_interface(info->io_if,
@@ -4502,7 +4500,12 @@ static int __init rs_init(void)
printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
serial_driver->name, info->line, info->ioport);
}
+ tty_port_link_device(&info->port, driver, i);
}
+
+ if (tty_register_driver(driver))
+ panic("Couldn't register serial driver\n");
+
#ifdef CONFIG_ETRAX_FAST_TIMER
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
memset(fast_timers, 0, sizeof(fast_timers));
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 3ad079ffd049..5b9bc19ed134 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
tty_port_init(pport);
pport->ops = &ifx_tty_port_ops;
ifx_dev->minor = IFX_SPI_TTY_ID;
- ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
- &ifx_dev->spi_dev->dev);
+ ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv,
+ ifx_dev->minor, &ifx_dev->spi_dev->dev);
if (IS_ERR(ifx_dev->tty_dev)) {
dev_dbg(&ifx_dev->spi_dev->dev,
"%s: registering tty device failed", __func__);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index d5c689d6217e..5952b25c288e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -132,6 +132,7 @@
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
+#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
@@ -206,7 +207,7 @@ struct imx_port {
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk_ipg;
struct clk *clk_per;
- struct imx_uart_data *devdata;
+ const struct imx_uart_data *devdata;
};
struct imx_port_ucrs {
@@ -667,22 +668,11 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
{
unsigned int val;
- unsigned int ufcr_rfdiv;
-
- /* set receiver / transmitter trigger level.
- * RFDIV is set such way to satisfy requested uartclk value
- */
- val = TXTL << 10 | RXTL;
- ufcr_rfdiv = (clk_get_rate(sport->clk_per) + sport->port.uartclk / 2)
- / sport->port.uartclk;
-
- if(!ufcr_rfdiv)
- ufcr_rfdiv = 1;
-
- val |= UFCR_RFDIV_REG(ufcr_rfdiv);
+ /* set receiver / transmitter trigger level */
+ val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
+ val |= TXTL << UFCR_TXTL_SHF | RXTL;
writel(val, sport->port.membase + UFCR);
-
return 0;
}
@@ -754,6 +744,7 @@ static int imx_startup(struct uart_port *port)
}
}
+ spin_lock_irqsave(&sport->port.lock, flags);
/*
* Finally, clear and enable interrupts
*/
@@ -807,7 +798,6 @@ static int imx_startup(struct uart_port *port)
/*
* Enable modem status interrupts
*/
- spin_lock_irqsave(&sport->port.lock,flags);
imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock,flags);
@@ -837,10 +827,13 @@ static void imx_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
+ unsigned long flags;
+ spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
writel(temp, sport->port.membase + UCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
@@ -869,12 +862,14 @@ static void imx_shutdown(struct uart_port *port)
* Disable all interrupts, port and break condition.
*/
+ spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
if (USE_IRDA(sport))
temp &= ~(UCR1_IREN);
writel(temp, sport->port.membase + UCR1);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void
@@ -1217,6 +1212,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
struct imx_port *sport = imx_ports[co->index];
struct imx_port_ucrs old_ucr;
unsigned int ucr1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
/*
* First, save UCR1/2/3 and then disable interrupts
@@ -1242,6 +1240,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
imx_port_ucrs_restore(&sport->port, &old_ucr);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
@@ -1505,18 +1505,21 @@ static int serial_imx_probe(struct platform_device *pdev)
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
ret = PTR_ERR(pinctrl);
+ dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
goto unmap;
}
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
+ dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
goto unmap;
}
sport->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(sport->clk_per)) {
ret = PTR_ERR(sport->clk_per);
+ dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
goto unmap;
}
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index 758ff310f7f8..5ac52898a0bb 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -1120,13 +1120,14 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len)
struct ioc3_port *port = get_ioc3_port(the_port);
struct ring *inring;
struct ring_entry *entry;
- struct port_hooks *hooks = port->ip_hooks;
+ struct port_hooks *hooks;
int byte_num;
char *sc;
int loop_counter;
BUG_ON(!(len >= 0));
BUG_ON(!port);
+ hooks = port->ip_hooks;
/* There is a nasty timing issue in the IOC3. When the rx_timer
* expires or the rx_high condition arises, we take an interrupt.
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index e16894fb2ca3..3e7da10cebba 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -1803,7 +1803,7 @@ static inline int ic4_startup_local(struct uart_port *the_port)
ioc4_set_proto(port, the_port->mapbase);
/* set the speed of the serial port */
- ioc4_change_speed(the_port, state->port.tty->termios,
+ ioc4_change_speed(the_port, &state->port.tty->termios,
(struct ktermios *)0);
return 0;
@@ -2069,13 +2069,14 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
struct ioc4_port *port = get_ioc4_port(the_port, 0);
struct ring *inring;
struct ring_entry *entry;
- struct hooks *hooks = port->ip_hooks;
+ struct hooks *hooks;
int byte_num;
char *sc;
int loop_counter;
BUG_ON(!(len >= 0));
BUG_ON(!port);
+ hooks = port->ip_hooks;
/* There is a nasty timing issue in the IOC4. When the rx_timer
* expires or the rx_high condition arises, we take an interrupt.
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 434bd881fcae..71397961773c 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -161,7 +161,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
struct ktermios *termios;
spin_lock_irqsave(&port->lock, lock_flags);
- termios = port->state->port.tty->termios;
+ termios = &port->state->port.tty->termios;
if (ch == termios->c_cc[VSTART])
channel->ch_bd->bd_ops->send_start_character(channel);
@@ -250,7 +250,7 @@ static int jsm_tty_open(struct uart_port *port)
channel->ch_cached_lsr = 0;
channel->ch_stops_sent = 0;
- termios = port->state->port.tty->termios;
+ termios = &port->state->port.tty->termios;
channel->ch_c_cflag = termios->c_cflag;
channel->ch_c_iflag = termios->c_iflag;
channel->ch_c_oflag = termios->c_oflag;
@@ -283,7 +283,7 @@ static void jsm_tty_close(struct uart_port *port)
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
- ts = port->state->port.tty->termios;
+ ts = &port->state->port.tty->termios;
channel->ch_flags &= ~(CH_STOPI);
@@ -567,7 +567,7 @@ void jsm_input(struct jsm_channel *ch)
*input data and return immediately.
*/
if (!tp ||
- !(tp->termios->c_cflag & CREAD) ) {
+ !(tp->termios.c_cflag & CREAD) ) {
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
new file mode 100644
index 000000000000..ba3af3bf6d43
--- /dev/null
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ * Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x) ((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x) ((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x) ((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x) ((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x) ((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA (1 << 10)
+#define LPC32XX_HSU_ERROR_DATA (1 << 9)
+#define LPC32XX_HSU_RX_EMPTY (1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n) (((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n) ((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET (1 << 6)
+#define LPC32XX_HSU_RX_OE_INT (1 << 5)
+#define LPC32XX_HSU_BRK_INT (1 << 4)
+#define LPC32XX_HSU_FE_INT (1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT (1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT (1 << 1)
+#define LPC32XX_HSU_TX_INT (1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV (1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B (0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B (0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B (0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B (0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN (1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED (0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B (0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B (0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B (0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV (1 << 15)
+#define LPC32XX_HSU_HCTS_EN (1 << 14)
+#define LPC32XX_HSU_OFFSET(n) ((n) << 9)
+#define LPC32XX_HSU_BREAK (1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN (1 << 7)
+#define LPC32XX_HSU_RX_INT_EN (1 << 6)
+#define LPC32XX_HSU_TX_INT_EN (1 << 5)
+#define LPC32XX_HSU_RX_TL1B (0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B (0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B (0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B (0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B (0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B (0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY (0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B (0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B (0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B (0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B (0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+ struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+ unsigned int timeout = 10000;
+
+ do {
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+ port->membase))) == 0)
+ break;
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+ unsigned int timeout = 10000;
+
+ while (1) {
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+ port->membase))) < 32)
+ break;
+ if (--timeout == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmit_ready(port);
+ writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+ unsigned long flags;
+ int locked = 1;
+
+ touch_nmi_watchdog();
+ local_irq_save(flags);
+ if (up->port.sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&up->port.lock);
+ else
+ spin_lock(&up->port.lock);
+
+ uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+ wait_for_xmit_empty(&up->port);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+ char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= MAX_PORTS)
+ co->index = 0;
+
+ port = &lpc32xx_hs_ports[co->index].port;
+ if (!port->membase)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+ .name = LPC32XX_TTY_NAME,
+ .write = lpc32xx_hsuart_console_write,
+ .device = uart_console_device,
+ .setup = lpc32xx_hsuart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+ register_console(&lpc32xx_hsuart_console);
+ return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = MODNAME,
+ .dev_name = LPC32XX_TTY_NAME,
+ .nr = MAX_PORTS,
+ .cons = LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+ unsigned long rate)
+{
+ u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+ u32 rate_diff;
+
+ /* Find the closest divider to get the desired clock rate */
+ div = uartclk / rate;
+ goodrate = hsu_rate = (div / 14) - 1;
+ if (hsu_rate != 0)
+ hsu_rate--;
+
+ /* Tweak divider */
+ l_hsu_rate = hsu_rate + 3;
+ rate_diff = 0xFFFFFFFF;
+
+ while (hsu_rate < l_hsu_rate) {
+ comprate = uartclk / ((hsu_rate + 1) * 14);
+ if (abs(comprate - rate) < rate_diff) {
+ goodrate = hsu_rate;
+ rate_diff = abs(comprate - rate);
+ }
+
+ hsu_rate++;
+ }
+ if (hsu_rate > 0xFF)
+ hsu_rate = 0xFF;
+
+ return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+ u32 tmp;
+ int cnt = 0;
+
+ while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+ (cnt++ < FIFO_READ_LIMIT))
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+ unsigned int tmp, flag;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+ if (!tty) {
+ /* Discard data: no tty available */
+ while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+ LPC32XX_HSU_RX_EMPTY))
+ ;
+
+ return;
+ }
+
+ /* Read data from FIFO and push into terminal */
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+ while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (tmp & LPC32XX_HSU_ERROR_DATA) {
+ /* Framing error */
+ writel(LPC32XX_HSU_FE_INT,
+ LPC32XX_HSUART_IIR(port->membase));
+ port->icount.frame++;
+ flag = TTY_FRAME;
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
+ }
+
+ tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+ tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+ }
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned int tmp;
+
+ if (port->x_char) {
+ writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ goto exit_tx;
+
+ /* Transfer data */
+ while (LPC32XX_HSU_TX_LEV(readl(
+ LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+ writel((u32) xmit->buf[xmit->tail],
+ LPC32XX_HSUART_FIFO(port->membase));
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+exit_tx:
+ if (uart_circ_empty(xmit)) {
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+ }
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+ u32 status;
+
+ spin_lock(&port->lock);
+
+ /* Read UART status and clear latched interrupts */
+ status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+ if (status & LPC32XX_HSU_BRK_INT) {
+ /* Break received */
+ writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+ port->icount.brk++;
+ uart_handle_break(port);
+ }
+
+ /* Framing error */
+ if (status & LPC32XX_HSU_FE_INT)
+ writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+ if (status & LPC32XX_HSU_RX_OE_INT) {
+ /* Receive FIFO overrun */
+ writel(LPC32XX_HSU_RX_OE_INT,
+ LPC32XX_HSUART_IIR(port->membase));
+ port->icount.overrun++;
+ if (tty) {
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_schedule_flip(tty);
+ }
+ }
+
+ /* Data received? */
+ if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+ __serial_lpc32xx_rx(port);
+ if (tty)
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Transmit data request? */
+ if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+ writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+ __serial_lpc32xx_tx(port);
+ }
+
+ spin_unlock(&port->lock);
+ tty_kref_put(tty);
+
+ return IRQ_HANDLED;
+}
+
+/* port->lock is not held. */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+ unsigned int ret = 0;
+
+ if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+ ret = TIOCSER_TEMT;
+
+ return ret;
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+ unsigned int mctrl)
+{
+ /* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled. */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+ /* No signals are supported on HS UARTs */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+ u32 tmp;
+
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+ u32 tmp;
+
+ __serial_lpc32xx_tx(port);
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp |= LPC32XX_HSU_TX_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+ u32 tmp;
+
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+ LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller. */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+ /* Modem status is not supported */
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+ int break_state)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&port->lock, flags);
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ if (break_state != 0)
+ tmp |= LPC32XX_HSU_BREAK;
+ else
+ tmp &= ~LPC32XX_HSU_BREAK;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+ int bit;
+ u32 tmp;
+
+ switch (mapbase) {
+ case LPC32XX_HS_UART1_BASE:
+ bit = 0;
+ break;
+ case LPC32XX_HS_UART2_BASE:
+ bit = 1;
+ break;
+ case LPC32XX_HS_UART7_BASE:
+ bit = 6;
+ break;
+ default:
+ WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+ return;
+ }
+
+ tmp = readl(LPC32XX_UARTCTL_CLOOP);
+ if (state)
+ tmp |= (1 << bit);
+ else
+ tmp &= ~(1 << bit);
+ writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held. */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+ int retval;
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ __serial_uart_flush(port);
+
+ writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+ LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+ LPC32XX_HSUART_IIR(port->membase));
+
+ writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+ /*
+ * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+ * and default FIFO trigger levels
+ */
+ tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+ 0, MODNAME, port);
+ if (!retval)
+ writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+ LPC32XX_HSUART_CTRL(port->membase));
+
+ return retval;
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ free_irq(port->irq, port);
+}
+
+/* port->lock is not held. */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, quot;
+ u32 tmp;
+
+ /* Always 8-bit, no parity, 1 stop bit */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag |= CS8;
+
+ termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ port->uartclk / 14);
+
+ quot = __serial_get_clock_div(port->uartclk, baud);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Ignore characters? */
+ tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+ if ((termios->c_cflag & CREAD) == 0)
+ tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+ else
+ tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+ writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+ writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+ return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+ if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ release_mem_region(port->mapbase, SZ_4K);
+ }
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+ int ret = -ENODEV;
+
+ if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+ ret = 0;
+
+ if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+ ret = -EBUSY;
+ else if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, SZ_4K);
+ if (!port->membase) {
+ release_mem_region(port->mapbase, SZ_4K);
+ ret = -ENOMEM;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+ int ret;
+
+ ret = serial_lpc32xx_request_port(port);
+ if (ret < 0)
+ return;
+ port->type = PORT_UART00;
+ port->fifosize = 64;
+
+ __serial_uart_flush(port);
+
+ writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+ LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+ LPC32XX_HSUART_IIR(port->membase));
+
+ writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+ /* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+ and default FIFO trigger levels */
+ writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+ LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+ LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (ser->type != PORT_UART00)
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+ .tx_empty = serial_lpc32xx_tx_empty,
+ .set_mctrl = serial_lpc32xx_set_mctrl,
+ .get_mctrl = serial_lpc32xx_get_mctrl,
+ .stop_tx = serial_lpc32xx_stop_tx,
+ .start_tx = serial_lpc32xx_start_tx,
+ .stop_rx = serial_lpc32xx_stop_rx,
+ .enable_ms = serial_lpc32xx_enable_ms,
+ .break_ctl = serial_lpc32xx_break_ctl,
+ .startup = serial_lpc32xx_startup,
+ .shutdown = serial_lpc32xx_shutdown,
+ .set_termios = serial_lpc32xx_set_termios,
+ .type = serial_lpc32xx_type,
+ .release_port = serial_lpc32xx_release_port,
+ .request_port = serial_lpc32xx_request_port,
+ .config_port = serial_lpc32xx_config_port,
+ .verify_port = serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+ int ret = 0;
+ struct resource *res;
+
+ if (uarts_registered >= MAX_PORTS) {
+ dev_err(&pdev->dev,
+ "Error: Number of possible ports exceeded (%d)!\n",
+ uarts_registered + 1);
+ return -ENXIO;
+ }
+
+ memset(p, 0, sizeof(*p));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Error getting mem resource for HS UART port %d\n",
+ uarts_registered);
+ return -ENXIO;
+ }
+ p->port.mapbase = res->start;
+ p->port.membase = NULL;
+
+ p->port.irq = platform_get_irq(pdev, 0);
+ if (p->port.irq < 0) {
+ dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+ uarts_registered);
+ return p->port.irq;
+ }
+
+ p->port.iotype = UPIO_MEM32;
+ p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+ p->port.regshift = 2;
+ p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+ p->port.dev = &pdev->dev;
+ p->port.ops = &serial_lpc32xx_pops;
+ p->port.line = uarts_registered++;
+ spin_lock_init(&p->port.lock);
+
+ /* send port to loopback mode by default */
+ lpc32xx_loopback_set(p->port.mapbase, 1);
+
+ ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+ platform_set_drvdata(pdev, p);
+
+ return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+ uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+ return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend NULL
+#define serial_hs_lpc32xx_resume NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+ { .compatible = "nxp,lpc3220-hsuart" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+ .probe = serial_hs_lpc32xx_probe,
+ .remove = __devexit_p(serial_hs_lpc32xx_remove),
+ .suspend = serial_hs_lpc32xx_suspend,
+ .resume = serial_hs_lpc32xx_resume,
+ .driver = {
+ .name = MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = serial_hs_lpc32xx_dt_ids,
+ },
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&lpc32xx_hs_reg);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+ if (ret)
+ uart_unregister_driver(&lpc32xx_hs_reg);
+
+ return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+ platform_driver_unregister(&serial_hs_lpc32xx_driver);
+ uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index a0703624d5e5..b13949ad3408 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -44,8 +44,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#define PORT_M32R_BASE PORT_M32R_SIO
-#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1)
#define BAUD_RATE 115200
#include <linux/serial_core.h>
@@ -132,22 +130,6 @@ struct irq_info {
static struct irq_info irq_lists[NR_IRQS];
-/*
- * Here we define the default xmit fifo size used for each type of UART.
- */
-static const struct serial_uart_config uart_config[] = {
- [PORT_UNKNOWN] = {
- .name = "unknown",
- .dfl_xmit_fifo_size = 1,
- .flags = 0,
- },
- [PORT_INDEX(PORT_M32R_SIO)] = {
- .name = "M32RSIO",
- .dfl_xmit_fifo_size = 1,
- .flags = 0,
- },
-};
-
#ifdef CONFIG_SERIAL_M32R_PLDSIO
#define __sio_in(x) inw((unsigned long)(x))
@@ -907,8 +889,7 @@ static void m32r_sio_config_port(struct uart_port *port, int unused)
spin_lock_irqsave(&up->port.lock, flags);
- up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1);
- up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
+ up->port.fifosize = 1;
spin_unlock_irqrestore(&up->port.lock, flags);
}
@@ -916,23 +897,11 @@ static void m32r_sio_config_port(struct uart_port *port, int unused)
static int
m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= nr_irqs || ser->irq < 0 ||
- ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
- ser->type >= ARRAY_SIZE(uart_config))
+ if (ser->irq >= nr_irqs || ser->irq < 0 || ser->baud_base < 9600)
return -EINVAL;
return 0;
}
-static const char *
-m32r_sio_type(struct uart_port *port)
-{
- int type = port->type;
-
- if (type >= ARRAY_SIZE(uart_config))
- type = 0;
- return uart_config[type].name;
-}
-
static struct uart_ops m32r_sio_pops = {
.tx_empty = m32r_sio_tx_empty,
.set_mctrl = m32r_sio_set_mctrl,
@@ -946,7 +915,6 @@ static struct uart_ops m32r_sio_pops = {
.shutdown = m32r_sio_shutdown,
.set_termios = m32r_sio_set_termios,
.pm = m32r_sio_pm,
- .type = m32r_sio_type,
.release_port = m32r_sio_release_port,
.request_port = m32r_sio_request_port,
.config_port = m32r_sio_config_port,
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index b4902b99cfd2..46043c2521ce 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -910,17 +910,7 @@ static struct spi_driver max3100_driver = {
.resume = max3100_resume,
};
-static int __init max3100_init(void)
-{
- return spi_register_driver(&max3100_driver);
-}
-module_init(max3100_init);
-
-static void __exit max3100_exit(void)
-{
- spi_unregister_driver(&max3100_driver);
-}
-module_exit(max3100_exit);
+module_spi_driver(max3100_driver);
MODULE_DESCRIPTION("MAX3100 driver");
MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
deleted file mode 100644
index 17c7ba805d98..000000000000
--- a/drivers/tty/serial/max3107.c
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- * max3107.c - spi uart protocol driver for Maxim 3107
- * Based on max3100.c
- * by Christian Pellegrin <chripell@evolware.org>
- * and max3110.c
- * by Feng Tang <feng.tang@intel.com>
- *
- * Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 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/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/module.h>
-#include "max3107.h"
-
-static const struct baud_table brg26_ext[] = {
- { 300, MAX3107_BRG26_B300 },
- { 600, MAX3107_BRG26_B600 },
- { 1200, MAX3107_BRG26_B1200 },
- { 2400, MAX3107_BRG26_B2400 },
- { 4800, MAX3107_BRG26_B4800 },
- { 9600, MAX3107_BRG26_B9600 },
- { 19200, MAX3107_BRG26_B19200 },
- { 57600, MAX3107_BRG26_B57600 },
- { 115200, MAX3107_BRG26_B115200 },
- { 230400, MAX3107_BRG26_B230400 },
- { 460800, MAX3107_BRG26_B460800 },
- { 921600, MAX3107_BRG26_B921600 },
- { 0, 0 }
-};
-
-static const struct baud_table brg13_int[] = {
- { 300, MAX3107_BRG13_IB300 },
- { 600, MAX3107_BRG13_IB600 },
- { 1200, MAX3107_BRG13_IB1200 },
- { 2400, MAX3107_BRG13_IB2400 },
- { 4800, MAX3107_BRG13_IB4800 },
- { 9600, MAX3107_BRG13_IB9600 },
- { 19200, MAX3107_BRG13_IB19200 },
- { 57600, MAX3107_BRG13_IB57600 },
- { 115200, MAX3107_BRG13_IB115200 },
- { 230400, MAX3107_BRG13_IB230400 },
- { 460800, MAX3107_BRG13_IB460800 },
- { 921600, MAX3107_BRG13_IB921600 },
- { 0, 0 }
-};
-
-static u32 get_new_brg(int baud, struct max3107_port *s)
-{
- int i;
- const struct baud_table *baud_tbl = s->baud_tbl;
-
- for (i = 0; i < 13; i++) {
- if (baud == baud_tbl[i].baud)
- return baud_tbl[i].new_brg;
- }
-
- return 0;
-}
-
-/* Perform SPI transfer for write/read of device register(s) */
-int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
-{
- struct spi_message spi_msg;
- struct spi_transfer spi_xfer;
-
- /* Initialize SPI ,message */
- spi_message_init(&spi_msg);
-
- /* Initialize SPI transfer */
- memset(&spi_xfer, 0, sizeof spi_xfer);
- spi_xfer.len = len;
- spi_xfer.tx_buf = tx;
- spi_xfer.rx_buf = rx;
- spi_xfer.speed_hz = MAX3107_SPI_SPEED;
-
- /* Add SPI transfer to SPI message */
- spi_message_add_tail(&spi_xfer, &spi_msg);
-
-#ifdef DBG_TRACE_SPI_DATA
- {
- int i;
- pr_info("tx len %d:\n", spi_xfer.len);
- for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
- pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
- pr_info("\n");
- }
-#endif
-
- /* Perform synchronous SPI transfer */
- if (spi_sync(s->spi, &spi_msg)) {
- dev_err(&s->spi->dev, "spi_sync failure\n");
- return -EIO;
- }
-
-#ifdef DBG_TRACE_SPI_DATA
- if (spi_xfer.rx_buf) {
- int i;
- pr_info("rx len %d:\n", spi_xfer.len);
- for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
- pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
- pr_info("\n");
- }
-#endif
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_rw);
-
-/* Puts received data to circular buffer */
-static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
- int len)
-{
- struct uart_port *port = &s->port;
- struct tty_struct *tty;
-
- if (!port->state)
- return;
-
- tty = port->state->port.tty;
- if (!tty)
- return;
-
- /* Insert received data */
- tty_insert_flip_string(tty, data, len);
- /* Update RX counter */
- port->icount.rx += len;
-}
-
-/* Handle data receiving */
-static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
-{
- int i;
- int j;
- int len; /* SPI transfer buffer length */
- u16 *buf;
- u8 *valid_str;
-
- if (!s->rx_enabled)
- /* RX is disabled */
- return;
-
- if (rxlvl == 0) {
- /* RX fifo is empty */
- return;
- } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
- dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
- /* Ensure sanity of RX level */
- rxlvl = MAX3107_RX_FIFO_SIZE;
- }
- if ((s->rxbuf == 0) || (s->rxstr == 0)) {
- dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
- return;
- }
- buf = s->rxbuf;
- valid_str = s->rxstr;
- while (rxlvl) {
- pr_debug("rxlvl %d\n", rxlvl);
- /* Clear buffer */
- memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
- len = 0;
- if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
- /* First disable RX FIFO interrupt */
- pr_debug("Disabling RX INT\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
- buf[0] |= s->irqen_reg;
- len++;
- }
- /* Just increase the length by amount of words in FIFO since
- * buffer was zeroed and SPI transfer of 0x0000 means reading
- * from RX FIFO
- */
- len += rxlvl;
- /* Append RX level query */
- buf[len] = MAX3107_RXFIFOLVL_REG;
- len++;
-
- /* Perform the SPI transfer */
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
- dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
- return;
- }
-
- /* Skip RX FIFO interrupt disabling word if it was added */
- j = ((len - 1) - rxlvl);
- /* Read received words */
- for (i = 0; i < rxlvl; i++, j++)
- valid_str[i] = (u8)buf[j];
- put_data_to_circ_buf(s, valid_str, rxlvl);
- /* Get new RX level */
- rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
- }
-
- if (s->rx_enabled) {
- /* RX still enabled, re-enable RX FIFO interrupt */
- pr_debug("Enabling RX INT\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
- buf[0] |= s->irqen_reg;
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
- }
-
- /* Push the received data to receivers */
- if (s->port.state->port.tty)
- tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-
-/* Handle data sending */
-static void max3107_handletx(struct max3107_port *s)
-{
- struct circ_buf *xmit = &s->port.state->xmit;
- int i;
- unsigned long flags;
- int len; /* SPI transfer buffer length */
- u16 *buf;
-
- if (!s->tx_fifo_empty)
- /* Don't send more data before previous data is sent */
- return;
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
- /* No data to send or TX is stopped */
- return;
-
- if (!s->txbuf) {
- dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
- return;
- }
- buf = s->txbuf;
- /* Get length of data pending in circular buffer */
- len = uart_circ_chars_pending(xmit);
- if (len) {
- /* Limit to size of TX FIFO */
- if (len > MAX3107_TX_FIFO_SIZE)
- len = MAX3107_TX_FIFO_SIZE;
-
- pr_debug("txlen %d\n", len);
-
- /* Update TX counter */
- s->port.icount.tx += len;
-
- /* TX FIFO will no longer be empty */
- s->tx_fifo_empty = 0;
-
- i = 0;
- if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
- /* First disable TX empty interrupt */
- pr_debug("Disabling TE INT\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
- buf[i] |= s->irqen_reg;
- i++;
- len++;
- }
- /* Add data to send */
- spin_lock_irqsave(&s->port.lock, flags);
- for ( ; i < len ; i++) {
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
- buf[i] |= ((u16)xmit->buf[xmit->tail] &
- MAX3107_SPI_TX_DATA_MASK);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- }
- spin_unlock_irqrestore(&s->port.lock, flags);
- if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
- /* Enable TX empty interrupt */
- pr_debug("Enabling TE INT\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
- s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
- buf[i] |= s->irqen_reg;
- i++;
- len++;
- }
- if (!s->tx_enabled) {
- /* Enable TX */
- pr_debug("Enable TX\n");
- buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
- buf[i] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
- s->tx_enabled = 1;
- i++;
- len++;
- }
-
- /* Perform the SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
- dev_err(&s->spi->dev,
- "SPI transfer TX handling failed\n");
- return;
- }
- }
-
- /* Indicate wake up if circular buffer is getting low on data */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&s->port);
-
-}
-
-/* Handle interrupts
- * Also reads and returns current RX FIFO level
- */
-static u16 handle_interrupt(struct max3107_port *s)
-{
- u16 buf[4]; /* Buffer for SPI transfers */
- u8 irq_status;
- u16 rx_level;
- unsigned long flags;
-
- /* Read IRQ status register */
- buf[0] = MAX3107_IRQSTS_REG;
- /* Read status IRQ status register */
- buf[1] = MAX3107_STS_IRQSTS_REG;
- /* Read LSR IRQ status register */
- buf[2] = MAX3107_LSR_IRQSTS_REG;
- /* Query RX level */
- buf[3] = MAX3107_RXFIFOLVL_REG;
-
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
- dev_err(&s->spi->dev,
- "SPI transfer for INTR handling failed\n");
- return 0;
- }
-
- irq_status = (u8)buf[0];
- pr_debug("IRQSTS %x\n", irq_status);
- rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
-
- if (irq_status & MAX3107_IRQ_LSR_BIT) {
- /* LSR interrupt */
- if (buf[2] & MAX3107_LSR_RXTO_BIT)
- /* RX timeout interrupt,
- * handled by normal RX handling
- */
- pr_debug("RX TO INT\n");
- }
-
- if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
- /* Tx empty interrupt,
- * disable TX and set tx_fifo_empty flag
- */
- pr_debug("TE INT, disabling TX\n");
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
- buf[0] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
- s->tx_enabled = 0;
- s->tx_fifo_empty = 1;
- }
-
- if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
- /* RX FIFO interrupt,
- * handled by normal RX handling
- */
- pr_debug("RFIFO INT\n");
-
- /* Return RX level */
- return rx_level;
-}
-
-/* Trigger work thread*/
-static void max3107_dowork(struct max3107_port *s)
-{
- if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
- queue_work(s->workqueue, &s->work);
- else
- dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
-}
-
-/* Work thread */
-static void max3107_work(struct work_struct *w)
-{
- struct max3107_port *s = container_of(w, struct max3107_port, work);
- u16 rxlvl = 0;
- int len; /* SPI transfer buffer length */
- u16 buf[5]; /* Buffer for SPI transfers */
- unsigned long flags;
-
- /* Start by reading current RX FIFO level */
- buf[0] = MAX3107_RXFIFOLVL_REG;
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
- dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
- rxlvl = 0;
- } else {
- rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
- }
-
- do {
- pr_debug("rxlvl %d\n", rxlvl);
-
- /* Handle RX */
- max3107_handlerx(s, rxlvl);
- rxlvl = 0;
-
- if (s->handle_irq) {
- /* Handle pending interrupts
- * We also get new RX FIFO level since new data may
- * have been received while pushing received data to
- * receivers
- */
- s->handle_irq = 0;
- rxlvl = handle_interrupt(s);
- }
-
- /* Handle TX */
- max3107_handletx(s);
-
- /* Handle configuration changes */
- len = 0;
- spin_lock_irqsave(&s->data_lock, flags);
- if (s->mode1_commit) {
- pr_debug("mode1_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- buf[len++] |= s->mode1_reg;
- s->mode1_commit = 0;
- }
- if (s->lcr_commit) {
- pr_debug("lcr_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
- buf[len++] |= s->lcr_reg;
- s->lcr_commit = 0;
- }
- if (s->brg_commit) {
- pr_debug("brg_commit\n");
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
- buf[len++] |= ((s->brg_cfg >> 16) &
- MAX3107_SPI_TX_DATA_MASK);
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
- buf[len++] |= ((s->brg_cfg >> 8) &
- MAX3107_SPI_TX_DATA_MASK);
- buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
- buf[len++] |= ((s->brg_cfg) & 0xff);
- s->brg_commit = 0;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- if (len > 0) {
- if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
- dev_err(&s->spi->dev,
- "SPI transfer config failed\n");
- }
-
- /* Reloop if interrupt handling indicated data in RX FIFO */
- } while (rxlvl);
-
-}
-
-/* Set sleep mode */
-static void max3107_set_sleep(struct max3107_port *s, int mode)
-{
- u16 buf[1]; /* Buffer for SPI transfer */
- unsigned long flags;
- pr_debug("enter, mode %d\n", mode);
-
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
- spin_lock_irqsave(&s->data_lock, flags);
- switch (mode) {
- case MAX3107_DISABLE_FORCED_SLEEP:
- s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
- break;
- case MAX3107_ENABLE_FORCED_SLEEP:
- s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
- break;
- case MAX3107_DISABLE_AUTOSLEEP:
- s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
- break;
- case MAX3107_ENABLE_AUTOSLEEP:
- s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
- break;
- default:
- spin_unlock_irqrestore(&s->data_lock, flags);
- dev_warn(&s->spi->dev, "invalid sleep mode\n");
- return;
- }
- buf[0] |= s->mode1_reg;
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- if (max3107_rw(s, (u8 *)buf, NULL, 2))
- dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
-
- if (mode == MAX3107_DISABLE_AUTOSLEEP ||
- mode == MAX3107_DISABLE_FORCED_SLEEP)
- msleep(MAX3107_WAKEUP_DELAY);
-}
-
-/* Perform full register initialization */
-static void max3107_register_init(struct max3107_port *s)
-{
- u16 buf[11]; /* Buffer for SPI transfers */
-
- /* 1. Configure baud rate, 9600 as default */
- s->baud = 9600;
- /* the below is default*/
- if (s->ext_clk) {
- s->brg_cfg = MAX3107_BRG26_B9600;
- s->baud_tbl = (struct baud_table *)brg26_ext;
- } else {
- s->brg_cfg = MAX3107_BRG13_IB9600;
- s->baud_tbl = (struct baud_table *)brg13_int;
- }
-
- if (s->pdata->init)
- s->pdata->init(s);
-
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
- | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
- | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
- buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
- | ((s->brg_cfg) & 0xff);
-
- /* 2. Configure LCR register, 8N1 mode by default */
- s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
- buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
- | s->lcr_reg;
-
- /* 3. Configure MODE 1 register */
- s->mode1_reg = 0;
- /* Enable IRQ pin */
- s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
- /* Disable TX */
- s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
- s->tx_enabled = 0;
- /* RX is enabled */
- s->rx_enabled = 1;
- buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
- | s->mode1_reg;
-
- /* 4. Configure MODE 2 register */
- buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
- if (s->loopback) {
- /* Enable loopback */
- buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
- }
- /* Reset FIFOs */
- buf[5] |= MAX3107_MODE2_FIFORST_BIT;
- s->tx_fifo_empty = 1;
-
- /* 5. Configure FIFO trigger level register */
- buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
- /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
- buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
-
- /* 6. Configure flow control levels */
- buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
- /* Flow control halt level 96, resume level 48 */
- buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
-
- /* 7. Configure flow control */
- buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
- /* Enable auto CTS and auto RTS flow control */
- buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
-
- /* 8. Configure RX timeout register */
- buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
- /* Timeout after 48 character intervals */
- buf[9] |= 0x0030;
-
- /* 9. Configure LSR interrupt enable register */
- buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
- /* Enable RX timeout interrupt */
- buf[10] |= MAX3107_LSR_RXTO_BIT;
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, 22))
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
- /* 10. Clear IRQ status register by reading it */
- buf[0] = MAX3107_IRQSTS_REG;
-
- /* 11. Configure interrupt enable register */
- /* Enable LSR interrupt */
- s->irqen_reg = MAX3107_IRQ_LSR_BIT;
- /* Enable RX FIFO interrupt */
- s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
- | s->irqen_reg;
-
- /* 12. Clear FIFO reset that was set in step 6 */
- buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
- if (s->loopback) {
- /* Keep loopback enabled */
- buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
- }
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-}
-
-/* IRQ handler */
-static irqreturn_t max3107_irq(int irqno, void *dev_id)
-{
- struct max3107_port *s = dev_id;
-
- if (irqno != s->spi->irq) {
- /* Unexpected IRQ */
- return IRQ_NONE;
- }
-
- /* Indicate irq */
- s->handle_irq = 1;
-
- /* Trigger work thread */
- max3107_dowork(s);
-
- return IRQ_HANDLED;
-}
-
-/* HW suspension function
- *
- * Currently autosleep is used to decrease current consumption, alternative
- * approach would be to set the chip to reset mode if UART is not being
- * used but that would mess the GPIOs
- *
- */
-void max3107_hw_susp(struct max3107_port *s, int suspend)
-{
- pr_debug("enter, suspend %d\n", suspend);
-
- if (suspend) {
- /* Suspend requested,
- * enable autosleep to decrease current consumption
- */
- s->suspended = 1;
- max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
- } else {
- /* Resume requested,
- * disable autosleep
- */
- s->suspended = 0;
- max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
- }
-}
-EXPORT_SYMBOL_GPL(max3107_hw_susp);
-
-/* Modem status IRQ enabling */
-static void max3107_enable_ms(struct uart_port *port)
-{
- /* Modem status not supported */
-}
-
-/* Data send function */
-static void max3107_start_tx(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- /* Trigger work thread for sending data */
- max3107_dowork(s);
-}
-
-/* Function for checking that there is no pending transfers */
-static unsigned int max3107_tx_empty(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- pr_debug("returning %d\n",
- (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
- return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
-}
-
-/* Function for stopping RX */
-static void max3107_stop_rx(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- unsigned long flags;
-
- /* Set RX disabled in MODE 1 register */
- spin_lock_irqsave(&s->data_lock, flags);
- s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
- s->mode1_commit = 1;
- spin_unlock_irqrestore(&s->data_lock, flags);
- /* Set RX disabled */
- s->rx_enabled = 0;
- /* Trigger work thread for doing the actual configuration change */
- max3107_dowork(s);
-}
-
-/* Function for returning control pin states */
-static unsigned int max3107_get_mctrl(struct uart_port *port)
-{
- /* DCD and DSR are not wired and CTS/RTS is handled automatically
- * so just indicate DSR and CAR asserted
- */
- return TIOCM_DSR | TIOCM_CAR;
-}
-
-/* Function for setting control pin states */
-static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
- * so do nothing
- */
-}
-
-/* Function for configuring UART parameters */
-static void max3107_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- struct tty_struct *tty;
- int baud;
- u16 new_lcr = 0;
- u32 new_brg = 0;
- unsigned long flags;
-
- if (!port->state)
- return;
-
- tty = port->state->port.tty;
- if (!tty)
- return;
-
- /* Get new LCR register values */
- /* Word size */
- if ((termios->c_cflag & CSIZE) == CS7)
- new_lcr |= MAX3107_LCR_WORD_LEN_7;
- else
- new_lcr |= MAX3107_LCR_WORD_LEN_8;
-
- /* Parity */
- if (termios->c_cflag & PARENB) {
- new_lcr |= MAX3107_LCR_PARITY_BIT;
- if (!(termios->c_cflag & PARODD))
- new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
- }
-
- /* Stop bits */
- if (termios->c_cflag & CSTOPB) {
- /* 2 stop bits */
- new_lcr |= MAX3107_LCR_STOPLEN_BIT;
- }
-
- /* Mask termios capabilities we don't support */
- termios->c_cflag &= ~CMSPAR;
-
- /* Set status ignore mask */
- s->port.ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
-
- /* Set low latency to immediately handle pushed data */
- s->port.state->port.tty->low_latency = 1;
-
- /* Get new baud rate generator configuration */
- baud = tty_get_baud_rate(tty);
-
- spin_lock_irqsave(&s->data_lock, flags);
- new_brg = get_new_brg(baud, s);
- /* if can't find the corrent config, use previous */
- if (!new_brg) {
- baud = s->baud;
- new_brg = s->brg_cfg;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
- tty_termios_encode_baud_rate(termios, baud, baud);
- s->baud = baud;
-
- /* Update timeout according to new baud rate */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- spin_lock_irqsave(&s->data_lock, flags);
- if (s->lcr_reg != new_lcr) {
- s->lcr_reg = new_lcr;
- s->lcr_commit = 1;
- }
- if (s->brg_cfg != new_brg) {
- s->brg_cfg = new_brg;
- s->brg_commit = 1;
- }
- spin_unlock_irqrestore(&s->data_lock, flags);
-
- /* Trigger work thread for doing the actual configuration change */
- max3107_dowork(s);
-}
-
-/* Port shutdown function */
-static void max3107_shutdown(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- if (s->suspended && s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Free the interrupt */
- free_irq(s->spi->irq, s);
-
- if (s->workqueue) {
- /* Flush and destroy work queue */
- flush_workqueue(s->workqueue);
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- }
-
- /* Suspend HW */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 1);
-}
-
-/* Port startup function */
-static int max3107_startup(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
-
- /* Initialize work queue */
- s->workqueue = create_freezable_workqueue("max3107");
- if (!s->workqueue) {
- dev_err(&s->spi->dev, "Workqueue creation failed\n");
- return -EBUSY;
- }
- INIT_WORK(&s->work, max3107_work);
-
- /* Setup IRQ */
- if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
- "max3107", s)) {
- dev_err(&s->spi->dev, "IRQ reguest failed\n");
- destroy_workqueue(s->workqueue);
- s->workqueue = NULL;
- return -EBUSY;
- }
-
- /* Resume HW */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Init registers */
- max3107_register_init(s);
-
- return 0;
-}
-
-/* Port type function */
-static const char *max3107_type(struct uart_port *port)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- return s->spi->modalias;
-}
-
-/* Port release function */
-static void max3107_release_port(struct uart_port *port)
-{
- /* Do nothing */
-}
-
-/* Port request function */
-static int max3107_request_port(struct uart_port *port)
-{
- /* Do nothing */
- return 0;
-}
-
-/* Port config function */
-static void max3107_config_port(struct uart_port *port, int flags)
-{
- struct max3107_port *s = container_of(port, struct max3107_port, port);
- s->port.type = PORT_MAX3107;
-}
-
-/* Port verify function */
-static int max3107_verify_port(struct uart_port *port,
- struct serial_struct *ser)
-{
- if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
- return 0;
-
- return -EINVAL;
-}
-
-/* Port stop TX function */
-static void max3107_stop_tx(struct uart_port *port)
-{
- /* Do nothing */
-}
-
-/* Port break control function */
-static void max3107_break_ctl(struct uart_port *port, int break_state)
-{
- /* We don't support break control, do nothing */
-}
-
-
-/* Port functions */
-static struct uart_ops max3107_ops = {
- .tx_empty = max3107_tx_empty,
- .set_mctrl = max3107_set_mctrl,
- .get_mctrl = max3107_get_mctrl,
- .stop_tx = max3107_stop_tx,
- .start_tx = max3107_start_tx,
- .stop_rx = max3107_stop_rx,
- .enable_ms = max3107_enable_ms,
- .break_ctl = max3107_break_ctl,
- .startup = max3107_startup,
- .shutdown = max3107_shutdown,
- .set_termios = max3107_set_termios,
- .type = max3107_type,
- .release_port = max3107_release_port,
- .request_port = max3107_request_port,
- .config_port = max3107_config_port,
- .verify_port = max3107_verify_port,
-};
-
-/* UART driver data */
-static struct uart_driver max3107_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = "ttyMAX",
- .dev_name = "ttyMAX",
- .nr = 1,
-};
-
-static int driver_registered = 0;
-
-
-
-/* 'Generic' platform data */
-static struct max3107_plat generic_plat_data = {
- .loopback = 0,
- .ext_clk = 1,
- .hw_suspend = max3107_hw_susp,
- .polled_mode = 0,
- .poll_time = 0,
-};
-
-
-/*******************************************************************/
-
-/**
- * max3107_probe - SPI bus probe entry point
- * @spi: the spi device
- *
- * SPI wants us to probe this device and if appropriate claim it.
- * Perform any platform specific requirements and then initialise
- * the device.
- */
-
-int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
-{
- struct max3107_port *s;
- u16 buf[2]; /* Buffer for SPI transfers */
- int retval;
-
- pr_info("enter max3107 probe\n");
-
- /* Allocate port structure */
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- pr_err("Allocating port structure failed\n");
- return -ENOMEM;
- }
-
- s->pdata = pdata;
-
- /* SPI Rx buffer
- * +2 for RX FIFO interrupt
- * disabling and RX level query
- */
- s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
- if (!s->rxbuf) {
- pr_err("Allocating RX buffer failed\n");
- retval = -ENOMEM;
- goto err_free4;
- }
- s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
- if (!s->rxstr) {
- pr_err("Allocating RX buffer failed\n");
- retval = -ENOMEM;
- goto err_free3;
- }
- /* SPI Tx buffer
- * SPI transfer buffer
- * +3 for TX FIFO empty
- * interrupt disabling and
- * enabling and TX enabling
- */
- s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
- if (!s->txbuf) {
- pr_err("Allocating TX buffer failed\n");
- retval = -ENOMEM;
- goto err_free2;
- }
- /* Initialize shared data lock */
- spin_lock_init(&s->data_lock);
-
- /* SPI intializations */
- dev_set_drvdata(&spi->dev, s);
- spi->mode = SPI_MODE_0;
- spi->dev.platform_data = pdata;
- spi->bits_per_word = 16;
- s->ext_clk = pdata->ext_clk;
- s->loopback = pdata->loopback;
- spi_setup(spi);
- s->spi = spi;
-
- /* Check REV ID to ensure we are talking to what we expect */
- buf[0] = MAX3107_REVID_REG;
- if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
- dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
- retval = -EIO;
- goto err_free1;
- }
- if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
- (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
- dev_err(&s->spi->dev, "REVID %x does not match\n",
- (buf[0] & MAX3107_SPI_RX_DATA_MASK));
- retval = -ENODEV;
- goto err_free1;
- }
-
- /* Disable all interrupts */
- buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
- buf[0] |= 0x0000;
-
- /* Configure clock source */
- buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
- if (s->ext_clk) {
- /* External clock */
- buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
- }
-
- /* PLL bypass ON */
- buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
-
- /* Perform SPI transfer */
- if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
- dev_err(&s->spi->dev, "SPI transfer for init failed\n");
- retval = -EIO;
- goto err_free1;
- }
-
- /* Register UART driver */
- if (!driver_registered) {
- retval = uart_register_driver(&max3107_uart_driver);
- if (retval) {
- dev_err(&s->spi->dev, "Registering UART driver failed\n");
- goto err_free1;
- }
- driver_registered = 1;
- }
-
- /* Initialize UART port data */
- s->port.fifosize = 128;
- s->port.ops = &max3107_ops;
- s->port.line = 0;
- s->port.dev = &spi->dev;
- s->port.uartclk = 9600;
- s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- s->port.irq = s->spi->irq;
- s->port.type = PORT_MAX3107;
-
- /* Add UART port */
- retval = uart_add_one_port(&max3107_uart_driver, &s->port);
- if (retval < 0) {
- dev_err(&s->spi->dev, "Adding UART port failed\n");
- goto err_free1;
- }
-
- if (pdata->configure) {
- retval = pdata->configure(s);
- if (retval < 0)
- goto err_free1;
- }
-
- /* Go to suspend mode */
- if (pdata->hw_suspend)
- pdata->hw_suspend(s, 1);
-
- return 0;
-
-err_free1:
- kfree(s->txbuf);
-err_free2:
- kfree(s->rxstr);
-err_free3:
- kfree(s->rxbuf);
-err_free4:
- kfree(s);
- return retval;
-}
-EXPORT_SYMBOL_GPL(max3107_probe);
-
-/* Driver remove function */
-int max3107_remove(struct spi_device *spi)
-{
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_info("enter max3107 remove\n");
-
- /* Remove port */
- if (uart_remove_one_port(&max3107_uart_driver, &s->port))
- dev_warn(&s->spi->dev, "Removing UART port failed\n");
-
-
- /* Free TxRx buffer */
- kfree(s->rxbuf);
- kfree(s->rxstr);
- kfree(s->txbuf);
-
- /* Free port structure */
- kfree(s);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_remove);
-
-/* Driver suspend function */
-int max3107_suspend(struct spi_device *spi, pm_message_t state)
-{
-#ifdef CONFIG_PM
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_debug("enter suspend\n");
-
- /* Suspend UART port */
- uart_suspend_port(&max3107_uart_driver, &s->port);
-
- /* Go to suspend mode */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 1);
-#endif /* CONFIG_PM */
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_suspend);
-
-/* Driver resume function */
-int max3107_resume(struct spi_device *spi)
-{
-#ifdef CONFIG_PM
- struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
- pr_debug("enter resume\n");
-
- /* Resume from suspend */
- if (s->pdata->hw_suspend)
- s->pdata->hw_suspend(s, 0);
-
- /* Resume UART port */
- uart_resume_port(&max3107_uart_driver, &s->port);
-#endif /* CONFIG_PM */
- return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_resume);
-
-static int max3107_probe_generic(struct spi_device *spi)
-{
- return max3107_probe(spi, &generic_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
- .driver = {
- .name = "max3107",
- .owner = THIS_MODULE,
- },
- .probe = max3107_probe_generic,
- .remove = __devexit_p(max3107_remove),
- .suspend = max3107_suspend,
- .resume = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
- pr_info("enter max3107 init\n");
- return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
- pr_info("enter max3107 exit\n");
- /* Unregister UART driver */
- if (driver_registered)
- uart_unregister_driver(&max3107_uart_driver);
- spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("spi:max3107");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h
deleted file mode 100644
index 8415fc723b96..000000000000
--- a/drivers/tty/serial/max3107.h
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * max3107.h - spi uart protocol driver header for Maxim 3107
- *
- * Copyright (C) Aavamobile 2009
- * Based on serial_max3100.h by Christian Pellegrin
- *
- * 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 _MAX3107_H
-#define _MAX3107_H
-
-/* Serial error status definitions */
-#define MAX3107_PARITY_ERROR 1
-#define MAX3107_FRAME_ERROR 2
-#define MAX3107_OVERRUN_ERROR 4
-#define MAX3107_ALL_ERRORS (MAX3107_PARITY_ERROR | \
- MAX3107_FRAME_ERROR | \
- MAX3107_OVERRUN_ERROR)
-
-/* GPIO definitions */
-#define MAX3107_GPIO_BASE 88
-#define MAX3107_GPIO_COUNT 4
-
-
-/* GPIO connected to chip's reset pin */
-#define MAX3107_RESET_GPIO 87
-
-
-/* Chip reset delay */
-#define MAX3107_RESET_DELAY 10
-
-/* Chip wakeup delay */
-#define MAX3107_WAKEUP_DELAY 50
-
-
-/* Sleep mode definitions */
-#define MAX3107_DISABLE_FORCED_SLEEP 0
-#define MAX3107_ENABLE_FORCED_SLEEP 1
-#define MAX3107_DISABLE_AUTOSLEEP 2
-#define MAX3107_ENABLE_AUTOSLEEP 3
-
-
-/* Definitions for register access with SPI transfers
- *
- * SPI transfer format:
- *
- * Master to slave bits xzzzzzzzyyyyyyyy
- * Slave to master bits aaaaaaaabbbbbbbb
- *
- * where:
- * x = 0 for reads, 1 for writes
- * z = register address
- * y = new register value if write, 0 if read
- * a = unspecified
- * b = register value if read, unspecified if write
- */
-
-/* SPI speed */
-#define MAX3107_SPI_SPEED (3125000 * 2)
-
-/* Write bit */
-#define MAX3107_WRITE_BIT (1 << 15)
-
-/* SPI TX data mask */
-#define MAX3107_SPI_RX_DATA_MASK (0x00ff)
-
-/* SPI RX data mask */
-#define MAX3107_SPI_TX_DATA_MASK (0x00ff)
-
-/* Register access masks */
-#define MAX3107_RHR_REG (0x0000) /* RX FIFO */
-#define MAX3107_THR_REG (0x0000) /* TX FIFO */
-#define MAX3107_IRQEN_REG (0x0100) /* IRQ enable */
-#define MAX3107_IRQSTS_REG (0x0200) /* IRQ status */
-#define MAX3107_LSR_IRQEN_REG (0x0300) /* LSR IRQ enable */
-#define MAX3107_LSR_IRQSTS_REG (0x0400) /* LSR IRQ status */
-#define MAX3107_SPCHR_IRQEN_REG (0x0500) /* Special char IRQ enable */
-#define MAX3107_SPCHR_IRQSTS_REG (0x0600) /* Special char IRQ status */
-#define MAX3107_STS_IRQEN_REG (0x0700) /* Status IRQ enable */
-#define MAX3107_STS_IRQSTS_REG (0x0800) /* Status IRQ status */
-#define MAX3107_MODE1_REG (0x0900) /* MODE1 */
-#define MAX3107_MODE2_REG (0x0a00) /* MODE2 */
-#define MAX3107_LCR_REG (0x0b00) /* LCR */
-#define MAX3107_RXTO_REG (0x0c00) /* RX timeout */
-#define MAX3107_HDPIXDELAY_REG (0x0d00) /* Auto transceiver delays */
-#define MAX3107_IRDA_REG (0x0e00) /* IRDA settings */
-#define MAX3107_FLOWLVL_REG (0x0f00) /* Flow control levels */
-#define MAX3107_FIFOTRIGLVL_REG (0x1000) /* FIFO IRQ trigger levels */
-#define MAX3107_TXFIFOLVL_REG (0x1100) /* TX FIFO level */
-#define MAX3107_RXFIFOLVL_REG (0x1200) /* RX FIFO level */
-#define MAX3107_FLOWCTRL_REG (0x1300) /* Flow control */
-#define MAX3107_XON1_REG (0x1400) /* XON1 character */
-#define MAX3107_XON2_REG (0x1500) /* XON2 character */
-#define MAX3107_XOFF1_REG (0x1600) /* XOFF1 character */
-#define MAX3107_XOFF2_REG (0x1700) /* XOFF2 character */
-#define MAX3107_GPIOCFG_REG (0x1800) /* GPIO config */
-#define MAX3107_GPIODATA_REG (0x1900) /* GPIO data */
-#define MAX3107_PLLCFG_REG (0x1a00) /* PLL config */
-#define MAX3107_BRGCFG_REG (0x1b00) /* Baud rate generator conf */
-#define MAX3107_BRGDIVLSB_REG (0x1c00) /* Baud rate divisor LSB */
-#define MAX3107_BRGDIVMSB_REG (0x1d00) /* Baud rate divisor MSB */
-#define MAX3107_CLKSRC_REG (0x1e00) /* Clock source */
-#define MAX3107_REVID_REG (0x1f00) /* Revision identification */
-
-/* IRQ register bits */
-#define MAX3107_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
-#define MAX3107_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
-#define MAX3107_IRQ_STS_BIT (1 << 2) /* Status interrupt */
-#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
-#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
-#define MAX3107_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */
-#define MAX3107_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */
-#define MAX3107_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */
-
-/* LSR register bits */
-#define MAX3107_LSR_RXTO_BIT (1 << 0) /* RX timeout */
-#define MAX3107_LSR_RXOVR_BIT (1 << 1) /* RX overrun */
-#define MAX3107_LSR_RXPAR_BIT (1 << 2) /* RX parity error */
-#define MAX3107_LSR_FRERR_BIT (1 << 3) /* Frame error */
-#define MAX3107_LSR_RXBRK_BIT (1 << 4) /* RX break */
-#define MAX3107_LSR_RXNOISE_BIT (1 << 5) /* RX noise */
-#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_LSR_CTS_BIT (1 << 7) /* CTS pin state */
-
-/* Special character register bits */
-#define MAX3107_SPCHR_XON1_BIT (1 << 0) /* XON1 character */
-#define MAX3107_SPCHR_XON2_BIT (1 << 1) /* XON2 character */
-#define MAX3107_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */
-#define MAX3107_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */
-#define MAX3107_SPCHR_BREAK_BIT (1 << 4) /* RX break */
-#define MAX3107_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */
-#define MAX3107_SPCHR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_SPCHR_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Status register bits */
-#define MAX3107_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */
-#define MAX3107_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */
-#define MAX3107_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */
-#define MAX3107_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */
-#define MAX3107_STS_UNDEF4_BIT (1 << 4) /* Undefined/not used */
-#define MAX3107_STS_CLKREADY_BIT (1 << 5) /* Clock ready */
-#define MAX3107_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */
-#define MAX3107_STS_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* MODE1 register bits */
-#define MAX3107_MODE1_RXDIS_BIT (1 << 0) /* RX disable */
-#define MAX3107_MODE1_TXDIS_BIT (1 << 1) /* TX disable */
-#define MAX3107_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */
-#define MAX3107_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */
-#define MAX3107_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */
-#define MAX3107_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */
-#define MAX3107_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */
-#define MAX3107_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */
-
-/* MODE2 register bits */
-#define MAX3107_MODE2_RST_BIT (1 << 0) /* Chip reset */
-#define MAX3107_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */
-#define MAX3107_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */
-#define MAX3107_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */
-#define MAX3107_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */
-#define MAX3107_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */
-#define MAX3107_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */
-#define MAX3107_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */
-
-/* LCR register bits */
-#define MAX3107_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
-#define MAX3107_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
- *
- * Word length bits table:
- * 00 -> 5 bit words
- * 01 -> 6 bit words
- * 10 -> 7 bit words
- * 11 -> 8 bit words
- */
-#define MAX3107_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
- *
- * STOP length bit table:
- * 0 -> 1 stop bit
- * 1 -> 1-1.5 stop bits if
- * word length is 5,
- * 2 stop bits otherwise
- */
-#define MAX3107_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
-#define MAX3107_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
-#define MAX3107_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
-#define MAX3107_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
-#define MAX3107_LCR_RTS_BIT (1 << 7) /* RTS pin control */
-#define MAX3107_LCR_WORD_LEN_5 (0x0000)
-#define MAX3107_LCR_WORD_LEN_6 (0x0001)
-#define MAX3107_LCR_WORD_LEN_7 (0x0002)
-#define MAX3107_LCR_WORD_LEN_8 (0x0003)
-
-
-/* IRDA register bits */
-#define MAX3107_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
-#define MAX3107_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
-#define MAX3107_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
-#define MAX3107_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
-#define MAX3107_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
-#define MAX3107_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
-#define MAX3107_IRDA_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_IRDA_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Flow control trigger level register masks */
-#define MAX3107_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
-#define MAX3107_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
-#define MAX3107_FLOWLVL_HALT(words) ((words/8) & 0x000f)
-#define MAX3107_FLOWLVL_RES(words) (((words/8) & 0x000f) << 4)
-
-/* FIFO interrupt trigger level register masks */
-#define MAX3107_FIFOTRIGLVL_TX_MASK (0x000f) /* TX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_RX_MASK (0x00f0) /* RX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_TX(words) ((words/8) & 0x000f)
-#define MAX3107_FIFOTRIGLVL_RX(words) (((words/8) & 0x000f) << 4)
-
-/* Flow control register bits */
-#define MAX3107_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
- * are used in conjunction with
- * XOFF2 for definition of
- * special character */
-#define MAX3107_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
-#define MAX3107_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
-#define MAX3107_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
- *
- * SWFLOW bits 1 & 0 table:
- * 00 -> no transmitter flow
- * control
- * 01 -> receiver compares
- * XON2 and XOFF2
- * and controls
- * transmitter
- * 10 -> receiver compares
- * XON1 and XOFF1
- * and controls
- * transmitter
- * 11 -> receiver compares
- * XON1, XON2, XOFF1 and
- * XOFF2 and controls
- * transmitter
- */
-#define MAX3107_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */
-#define MAX3107_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3
- *
- * SWFLOW bits 3 & 2 table:
- * 00 -> no received flow
- * control
- * 01 -> transmitter generates
- * XON2 and XOFF2
- * 10 -> transmitter generates
- * XON1 and XOFF1
- * 11 -> transmitter generates
- * XON1, XON2, XOFF1 and
- * XOFF2
- */
-
-/* GPIO configuration register bits */
-#define MAX3107_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
-#define MAX3107_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
-#define MAX3107_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
-#define MAX3107_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
-#define MAX3107_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX3107_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX3107_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX3107_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX3107_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
-#define MAX3107_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
-#define MAX3107_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
-#define MAX3107_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
-#define MAX3107_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
-#define MAX3107_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
-#define MAX3107_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
-#define MAX3107_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
-
-/* PLL configuration register masks */
-#define MAX3107_PLLCFG_PREDIV_MASK (0x003f) /* PLL predivision value */
-#define MAX3107_PLLCFG_PLLFACTOR_MASK (0x00c0) /* PLL multiplication factor */
-
-/* Baud rate generator configuration register masks and bits */
-#define MAX3107_BRGCFG_FRACT_MASK (0x000f) /* Fractional portion of
- * Baud rate generator divisor
- */
-#define MAX3107_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
-#define MAX3107_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */
-#define MAX3107_BRGCFG_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_BRGCFG_UNDEF7_BIT (1 << 7) /* Undefined/not used */
-
-/* Clock source register bits */
-#define MAX3107_CLKSRC_INTOSC_BIT (1 << 0) /* Internal osc enable */
-#define MAX3107_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */
-#define MAX3107_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */
-#define MAX3107_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */
-#define MAX3107_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
-#define MAX3107_CLKSRC_UNDEF5_BIT (1 << 5) /* Undefined/not used */
-#define MAX3107_CLKSRC_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
-
-
-/* HW definitions */
-#define MAX3107_RX_FIFO_SIZE 128
-#define MAX3107_TX_FIFO_SIZE 128
-#define MAX3107_REVID1 0x00a0
-#define MAX3107_REVID2 0x00a1
-
-
-/* Baud rate generator configuration values for external clock 13MHz */
-#define MAX3107_BRG13_B300 (0x0A9400 | 0x05)
-#define MAX3107_BRG13_B600 (0x054A00 | 0x03)
-#define MAX3107_BRG13_B1200 (0x02A500 | 0x01)
-#define MAX3107_BRG13_B2400 (0x015200 | 0x09)
-#define MAX3107_BRG13_B4800 (0x00A900 | 0x04)
-#define MAX3107_BRG13_B9600 (0x005400 | 0x0A)
-#define MAX3107_BRG13_B19200 (0x002A00 | 0x05)
-#define MAX3107_BRG13_B38400 (0x001500 | 0x03)
-#define MAX3107_BRG13_B57600 (0x000E00 | 0x02)
-#define MAX3107_BRG13_B115200 (0x000700 | 0x01)
-#define MAX3107_BRG13_B230400 (0x000300 | 0x08)
-#define MAX3107_BRG13_B460800 (0x000100 | 0x0c)
-#define MAX3107_BRG13_B921600 (0x000100 | 0x1c)
-
-/* Baud rate generator configuration values for external clock 26MHz */
-#define MAX3107_BRG26_B300 (0x152800 | 0x0A)
-#define MAX3107_BRG26_B600 (0x0A9400 | 0x05)
-#define MAX3107_BRG26_B1200 (0x054A00 | 0x03)
-#define MAX3107_BRG26_B2400 (0x02A500 | 0x01)
-#define MAX3107_BRG26_B4800 (0x015200 | 0x09)
-#define MAX3107_BRG26_B9600 (0x00A900 | 0x04)
-#define MAX3107_BRG26_B19200 (0x005400 | 0x0A)
-#define MAX3107_BRG26_B38400 (0x002A00 | 0x05)
-#define MAX3107_BRG26_B57600 (0x001C00 | 0x03)
-#define MAX3107_BRG26_B115200 (0x000E00 | 0x02)
-#define MAX3107_BRG26_B230400 (0x000700 | 0x01)
-#define MAX3107_BRG26_B460800 (0x000300 | 0x08)
-#define MAX3107_BRG26_B921600 (0x000100 | 0x0C)
-
-/* Baud rate generator configuration values for internal clock */
-#define MAX3107_BRG13_IB300 (0x008000 | 0x00)
-#define MAX3107_BRG13_IB600 (0x004000 | 0x00)
-#define MAX3107_BRG13_IB1200 (0x002000 | 0x00)
-#define MAX3107_BRG13_IB2400 (0x001000 | 0x00)
-#define MAX3107_BRG13_IB4800 (0x000800 | 0x00)
-#define MAX3107_BRG13_IB9600 (0x000400 | 0x00)
-#define MAX3107_BRG13_IB19200 (0x000200 | 0x00)
-#define MAX3107_BRG13_IB38400 (0x000100 | 0x00)
-#define MAX3107_BRG13_IB57600 (0x000000 | 0x0B)
-#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
-#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
-#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
-#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
-
-
-struct baud_table {
- int baud;
- u32 new_brg;
-};
-
-struct max3107_port {
- /* UART port structure */
- struct uart_port port;
-
- /* SPI device structure */
- struct spi_device *spi;
-
-#if defined(CONFIG_GPIOLIB)
- /* GPIO chip structure */
- struct gpio_chip chip;
-#endif
-
- /* Workqueue that does all the magic */
- struct workqueue_struct *workqueue;
- struct work_struct work;
-
- /* Lock for shared data */
- spinlock_t data_lock;
-
- /* Device configuration */
- int ext_clk; /* 1 if external clock used */
- int loopback; /* Current loopback mode state */
- int baud; /* Current baud rate */
-
- /* State flags */
- int suspended; /* Indicates suspend mode */
- int tx_fifo_empty; /* Flag for TX FIFO state */
- int rx_enabled; /* Flag for receiver state */
- int tx_enabled; /* Flag for transmitter state */
-
- u16 irqen_reg; /* Current IRQ enable register value */
- /* Shared data */
- u16 mode1_reg; /* Current mode1 register value*/
- int mode1_commit; /* Flag for setting new mode1 register value */
- u16 lcr_reg; /* Current LCR register value */
- int lcr_commit; /* Flag for setting new LCR register value */
- u32 brg_cfg; /* Current Baud rate generator config */
- int brg_commit; /* Flag for setting new baud rate generator
- * config
- */
- struct baud_table *baud_tbl;
- int handle_irq; /* Indicates that IRQ should be handled */
-
- /* Rx buffer and str*/
- u16 *rxbuf;
- u8 *rxstr;
- /* Tx buffer*/
- u16 *txbuf;
-
- struct max3107_plat *pdata; /* Platform data */
-};
-
-/* Platform data structure */
-struct max3107_plat {
- /* Loopback mode enable */
- int loopback;
- /* External clock enable */
- int ext_clk;
- /* Called during the register initialisation */
- void (*init)(struct max3107_port *s);
- /* Called when the port is found and configured */
- int (*configure)(struct max3107_port *s);
- /* HW suspend function */
- void (*hw_suspend) (struct max3107_port *s, int suspend);
- /* Polling mode enable */
- int polled_mode;
- /* Polling period if polling mode enabled */
- int poll_time;
-};
-
-extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
-extern void max3107_hw_susp(struct max3107_port *s, int suspend);
-extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
-extern int max3107_remove(struct spi_device *spi);
-extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
-extern int max3107_resume(struct spi_device *spi);
-
-#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
new file mode 100644
index 000000000000..2bc28a59d385
--- /dev/null
+++ b/drivers/tty/serial/max310x.c
@@ -0,0 +1,1260 @@
+/*
+ * Maxim (Dallas) MAX3107/8 serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
+ * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
+ * Based on max3107.c, by Aavamobile
+ *
+ * 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.
+ */
+
+/* TODO: MAX3109 support (Dual) */
+/* TODO: MAX14830 support (Quad) */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/max310x.h>
+
+#define MAX310X_MAJOR 204
+#define MAX310X_MINOR 209
+
+/* MAX310X register definitions */
+#define MAX310X_RHR_REG (0x00) /* RX FIFO */
+#define MAX310X_THR_REG (0x00) /* TX FIFO */
+#define MAX310X_IRQEN_REG (0x01) /* IRQ enable */
+#define MAX310X_IRQSTS_REG (0x02) /* IRQ status */
+#define MAX310X_LSR_IRQEN_REG (0x03) /* LSR IRQ enable */
+#define MAX310X_LSR_IRQSTS_REG (0x04) /* LSR IRQ status */
+#define MAX310X_SPCHR_IRQEN_REG (0x05) /* Special char IRQ enable */
+#define MAX310X_SPCHR_IRQSTS_REG (0x06) /* Special char IRQ status */
+#define MAX310X_STS_IRQEN_REG (0x07) /* Status IRQ enable */
+#define MAX310X_STS_IRQSTS_REG (0x08) /* Status IRQ status */
+#define MAX310X_MODE1_REG (0x09) /* MODE1 */
+#define MAX310X_MODE2_REG (0x0a) /* MODE2 */
+#define MAX310X_LCR_REG (0x0b) /* LCR */
+#define MAX310X_RXTO_REG (0x0c) /* RX timeout */
+#define MAX310X_HDPIXDELAY_REG (0x0d) /* Auto transceiver delays */
+#define MAX310X_IRDA_REG (0x0e) /* IRDA settings */
+#define MAX310X_FLOWLVL_REG (0x0f) /* Flow control levels */
+#define MAX310X_FIFOTRIGLVL_REG (0x10) /* FIFO IRQ trigger levels */
+#define MAX310X_TXFIFOLVL_REG (0x11) /* TX FIFO level */
+#define MAX310X_RXFIFOLVL_REG (0x12) /* RX FIFO level */
+#define MAX310X_FLOWCTRL_REG (0x13) /* Flow control */
+#define MAX310X_XON1_REG (0x14) /* XON1 character */
+#define MAX310X_XON2_REG (0x15) /* XON2 character */
+#define MAX310X_XOFF1_REG (0x16) /* XOFF1 character */
+#define MAX310X_XOFF2_REG (0x17) /* XOFF2 character */
+#define MAX310X_GPIOCFG_REG (0x18) /* GPIO config */
+#define MAX310X_GPIODATA_REG (0x19) /* GPIO data */
+#define MAX310X_PLLCFG_REG (0x1a) /* PLL config */
+#define MAX310X_BRGCFG_REG (0x1b) /* Baud rate generator conf */
+#define MAX310X_BRGDIVLSB_REG (0x1c) /* Baud rate divisor LSB */
+#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */
+#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */
+/* Only present in MAX3107 */
+#define MAX3107_REVID_REG (0x1f) /* Revision identification */
+
+/* IRQ register bits */
+#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
+#define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */
+#define MAX310X_IRQ_STS_BIT (1 << 2) /* Status interrupt */
+#define MAX310X_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
+#define MAX310X_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
+#define MAX310X_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */
+#define MAX310X_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */
+#define MAX310X_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */
+
+/* LSR register bits */
+#define MAX310X_LSR_RXTO_BIT (1 << 0) /* RX timeout */
+#define MAX310X_LSR_RXOVR_BIT (1 << 1) /* RX overrun */
+#define MAX310X_LSR_RXPAR_BIT (1 << 2) /* RX parity error */
+#define MAX310X_LSR_FRERR_BIT (1 << 3) /* Frame error */
+#define MAX310X_LSR_RXBRK_BIT (1 << 4) /* RX break */
+#define MAX310X_LSR_RXNOISE_BIT (1 << 5) /* RX noise */
+#define MAX310X_LSR_CTS_BIT (1 << 7) /* CTS pin state */
+
+/* Special character register bits */
+#define MAX310X_SPCHR_XON1_BIT (1 << 0) /* XON1 character */
+#define MAX310X_SPCHR_XON2_BIT (1 << 1) /* XON2 character */
+#define MAX310X_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */
+#define MAX310X_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */
+#define MAX310X_SPCHR_BREAK_BIT (1 << 4) /* RX break */
+#define MAX310X_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */
+
+/* Status register bits */
+#define MAX310X_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */
+#define MAX310X_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */
+#define MAX310X_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */
+#define MAX310X_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */
+#define MAX310X_STS_CLKREADY_BIT (1 << 5) /* Clock ready */
+#define MAX310X_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */
+
+/* MODE1 register bits */
+#define MAX310X_MODE1_RXDIS_BIT (1 << 0) /* RX disable */
+#define MAX310X_MODE1_TXDIS_BIT (1 << 1) /* TX disable */
+#define MAX310X_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */
+#define MAX310X_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */
+#define MAX310X_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */
+#define MAX310X_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */
+#define MAX310X_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */
+#define MAX310X_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */
+
+/* MODE2 register bits */
+#define MAX310X_MODE2_RST_BIT (1 << 0) /* Chip reset */
+#define MAX310X_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */
+#define MAX310X_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */
+#define MAX310X_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */
+#define MAX310X_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */
+#define MAX310X_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */
+#define MAX310X_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */
+#define MAX310X_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */
+
+/* LCR register bits */
+#define MAX310X_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
+#define MAX310X_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
+ *
+ * Word length bits table:
+ * 00 -> 5 bit words
+ * 01 -> 6 bit words
+ * 10 -> 7 bit words
+ * 11 -> 8 bit words
+ */
+#define MAX310X_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
+ *
+ * STOP length bit table:
+ * 0 -> 1 stop bit
+ * 1 -> 1-1.5 stop bits if
+ * word length is 5,
+ * 2 stop bits otherwise
+ */
+#define MAX310X_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
+#define MAX310X_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
+#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
+#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
+#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
+#define MAX310X_LCR_WORD_LEN_5 (0x00)
+#define MAX310X_LCR_WORD_LEN_6 (0x01)
+#define MAX310X_LCR_WORD_LEN_7 (0x02)
+#define MAX310X_LCR_WORD_LEN_8 (0x03)
+
+/* IRDA register bits */
+#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
+#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
+#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
+#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
+#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
+#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
+
+/* Flow control trigger level register masks */
+#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
+#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */
+#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f)
+#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4)
+
+/* FIFO interrupt trigger level register masks */
+#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f)
+#define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4)
+
+/* Flow control register bits */
+#define MAX310X_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs
+ * are used in conjunction with
+ * XOFF2 for definition of
+ * special character */
+#define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */
+#define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */
+#define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1
+ *
+ * SWFLOW bits 1 & 0 table:
+ * 00 -> no transmitter flow
+ * control
+ * 01 -> receiver compares
+ * XON2 and XOFF2
+ * and controls
+ * transmitter
+ * 10 -> receiver compares
+ * XON1 and XOFF1
+ * and controls
+ * transmitter
+ * 11 -> receiver compares
+ * XON1, XON2, XOFF1 and
+ * XOFF2 and controls
+ * transmitter
+ */
+#define MAX310X_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */
+#define MAX310X_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3
+ *
+ * SWFLOW bits 3 & 2 table:
+ * 00 -> no received flow
+ * control
+ * 01 -> transmitter generates
+ * XON2 and XOFF2
+ * 10 -> transmitter generates
+ * XON1 and XOFF1
+ * 11 -> transmitter generates
+ * XON1, XON2, XOFF1 and
+ * XOFF2
+ */
+
+/* GPIO configuration register bits */
+#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
+#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
+#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
+#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
+#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
+#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
+#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
+#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
+
+/* GPIO DATA register bits */
+#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
+#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
+#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
+#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
+#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
+#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
+#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
+#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
+
+/* PLL configuration register masks */
+#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */
+#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */
+
+/* Baud rate generator configuration register bits */
+#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */
+#define MAX310X_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */
+
+/* Clock source register bits */
+#define MAX310X_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */
+#define MAX310X_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */
+#define MAX310X_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */
+#define MAX310X_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */
+#define MAX310X_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */
+
+/* Misc definitions */
+#define MAX310X_FIFO_SIZE (128)
+
+/* MAX3107 specific */
+#define MAX3107_REV_ID (0xa0)
+#define MAX3107_REV_MASK (0xfe)
+
+/* IRQ status bits definitions */
+#define MAX310X_IRQ_TX (MAX310X_IRQ_TXFIFO_BIT | \
+ MAX310X_IRQ_TXEMPTY_BIT)
+#define MAX310X_IRQ_RX (MAX310X_IRQ_RXFIFO_BIT | \
+ MAX310X_IRQ_RXEMPTY_BIT)
+
+/* Supported chip types */
+enum {
+ MAX310X_TYPE_MAX3107 = 3107,
+ MAX310X_TYPE_MAX3108 = 3108,
+};
+
+struct max310x_port {
+ struct uart_driver uart;
+ struct uart_port port;
+
+ const char *name;
+ int uartclk;
+
+ unsigned int nr_gpio;
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio;
+#endif
+
+ struct regmap *regmap;
+ struct regmap_config regcfg;
+
+ struct workqueue_struct *wq;
+ struct work_struct tx_work;
+
+ struct mutex max310x_mutex;
+
+ struct max310x_pdata *pdata;
+};
+
+static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_LSR_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ case MAX310X_TXFIFOLVL_REG:
+ case MAX310X_RXFIFOLVL_REG:
+ case MAX3107_REVID_REG: /* Only available on MAX3107 */
+ return false;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_RHR_REG:
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_LSR_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ case MAX310X_TXFIFOLVL_REG:
+ case MAX310X_RXFIFOLVL_REG:
+ case MAX310X_GPIODATA_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool max310x_reg_precious(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX310X_RHR_REG:
+ case MAX310X_IRQSTS_REG:
+ case MAX310X_SPCHR_IRQSTS_REG:
+ case MAX310X_STS_IRQSTS_REG:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static void max310x_set_baud(struct max310x_port *s, int baud)
+{
+ unsigned int mode = 0, div = s->uartclk / baud;
+
+ if (!(div / 16)) {
+ /* Mode x2 */
+ mode = MAX310X_BRGCFG_2XMODE_BIT;
+ div = (s->uartclk * 2) / baud;
+ }
+
+ if (!(div / 16)) {
+ /* Mode x4 */
+ mode = MAX310X_BRGCFG_4XMODE_BIT;
+ div = (s->uartclk * 4) / baud;
+ }
+
+ regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG,
+ ((div / 16) >> 8) & 0xff);
+ regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff);
+ regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode);
+}
+
+static void max310x_wait_pll(struct max310x_port *s)
+{
+ int tryes = 1000;
+
+ /* Wait for PLL only if crystal is used */
+ if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) {
+ unsigned int sts = 0;
+
+ while (tryes--) {
+ regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts);
+ if (sts & MAX310X_STS_CLKREADY_BIT)
+ break;
+ }
+ }
+}
+
+static int __devinit max310x_update_best_err(unsigned long f, long *besterr)
+{
+ /* Use baudrate 115200 for calculate error */
+ long err = f % (115200 * 16);
+
+ if ((*besterr < 0) || (*besterr > err)) {
+ *besterr = err;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int __devinit max310x_set_ref_clk(struct max310x_port *s)
+{
+ unsigned int div, clksrc, pllcfg = 0;
+ long besterr = -1;
+ unsigned long fdiv, fmul, bestfreq = s->pdata->frequency;
+
+ /* First, update error without PLL */
+ max310x_update_best_err(s->pdata->frequency, &besterr);
+
+ /* Try all possible PLL dividers */
+ for (div = 1; (div <= 63) && besterr; div++) {
+ fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div);
+
+ /* Try multiplier 6 */
+ fmul = fdiv * 6;
+ if ((fdiv >= 500000) && (fdiv <= 800000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (0 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 48 */
+ fmul = fdiv * 48;
+ if ((fdiv >= 850000) && (fdiv <= 1200000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (1 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 96 */
+ fmul = fdiv * 96;
+ if ((fdiv >= 425000) && (fdiv <= 1000000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (2 << 6) | div;
+ bestfreq = fmul;
+ }
+ /* Try multiplier 144 */
+ fmul = fdiv * 144;
+ if ((fdiv >= 390000) && (fdiv <= 667000))
+ if (!max310x_update_best_err(fmul, &besterr)) {
+ pllcfg = (3 << 6) | div;
+ bestfreq = fmul;
+ }
+ }
+
+ /* Configure clock source */
+ if (s->pdata->driver_flags & MAX310X_EXT_CLK)
+ clksrc = MAX310X_CLKSRC_EXTCLK_BIT;
+ else
+ clksrc = MAX310X_CLKSRC_CRYST_BIT;
+
+ /* Configure PLL */
+ if (pllcfg) {
+ clksrc |= MAX310X_CLKSRC_PLL_BIT;
+ regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg);
+ } else
+ clksrc |= MAX310X_CLKSRC_PLLBYP_BIT;
+
+ regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
+
+ if (pllcfg)
+ max310x_wait_pll(s);
+
+ dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq);
+
+ return (int)bestfreq;
+}
+
+static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
+{
+ unsigned int sts = 0, ch = 0, flag;
+ struct tty_struct *tty = tty_port_tty_get(&s->port.state->port);
+
+ if (!tty)
+ return;
+
+ if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
+ dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
+ /* Ensure sanity of RX level */
+ rxlen = MAX310X_FIFO_SIZE;
+ }
+
+ dev_dbg(s->port.dev, "RX Len = %u\n", rxlen);
+
+ while (rxlen--) {
+ regmap_read(s->regmap, MAX310X_RHR_REG, &ch);
+ regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts);
+
+ sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT |
+ MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT;
+
+ s->port.icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (unlikely(sts)) {
+ if (sts & MAX310X_LSR_RXBRK_BIT) {
+ s->port.icount.brk++;
+ if (uart_handle_break(&s->port))
+ continue;
+ } else if (sts & MAX310X_LSR_RXPAR_BIT)
+ s->port.icount.parity++;
+ else if (sts & MAX310X_LSR_FRERR_BIT)
+ s->port.icount.frame++;
+ else if (sts & MAX310X_LSR_RXOVR_BIT)
+ s->port.icount.overrun++;
+
+ sts &= s->port.read_status_mask;
+ if (sts & MAX310X_LSR_RXBRK_BIT)
+ flag = TTY_BREAK;
+ else if (sts & MAX310X_LSR_RXPAR_BIT)
+ flag = TTY_PARITY;
+ else if (sts & MAX310X_LSR_FRERR_BIT)
+ flag = TTY_FRAME;
+ else if (sts & MAX310X_LSR_RXOVR_BIT)
+ flag = TTY_OVERRUN;
+ }
+
+ if (uart_handle_sysrq_char(s->port, ch))
+ continue;
+
+ if (sts & s->port.ignore_status_mask)
+ continue;
+
+ uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT,
+ ch, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+}
+
+static void max310x_handle_tx(struct max310x_port *s)
+{
+ struct circ_buf *xmit = &s->port.state->xmit;
+ unsigned int txlen = 0, to_send;
+
+ if (unlikely(s->port.x_char)) {
+ regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char);
+ s->port.icount.tx++;
+ s->port.x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+ return;
+
+ /* Get length of data pending in circular buffer */
+ to_send = uart_circ_chars_pending(xmit);
+ if (likely(to_send)) {
+ /* Limit to size of TX FIFO */
+ regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen);
+ txlen = MAX310X_FIFO_SIZE - txlen;
+ to_send = (to_send > txlen) ? txlen : to_send;
+
+ dev_dbg(s->port.dev, "TX Len = %u\n", to_send);
+
+ /* Add data to send */
+ s->port.icount.tx += to_send;
+ while (to_send--) {
+ regmap_write(s->regmap, MAX310X_THR_REG,
+ xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ };
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+}
+
+static irqreturn_t max310x_ist(int irq, void *dev_id)
+{
+ struct max310x_port *s = (struct max310x_port *)dev_id;
+ unsigned int ists = 0, lsr = 0, rxlen = 0;
+
+ mutex_lock(&s->max310x_mutex);
+
+ for (;;) {
+ /* Read IRQ status & RX FIFO level */
+ regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists);
+ regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr);
+ regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen);
+ if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen)
+ break;
+
+ dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists);
+
+ if (rxlen)
+ max310x_handle_rx(s, rxlen);
+ if (ists & MAX310X_IRQ_TX)
+ max310x_handle_tx(s);
+ if (ists & MAX310X_IRQ_CTS_BIT)
+ uart_handle_cts_change(&s->port,
+ !!(lsr & MAX310X_LSR_CTS_BIT));
+ }
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static void max310x_wq_proc(struct work_struct *ws)
+{
+ struct max310x_port *s = container_of(ws, struct max310x_port, tx_work);
+
+ mutex_lock(&s->max310x_mutex);
+ max310x_handle_tx(s);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_start_tx(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ queue_work(s->wq, &s->tx_work);
+}
+
+static void max310x_stop_tx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void max310x_stop_rx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static unsigned int max310x_tx_empty(struct uart_port *port)
+{
+ unsigned int val = 0;
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val);
+ mutex_unlock(&s->max310x_mutex);
+
+ return val ? 0 : TIOCSER_TEMT;
+}
+
+static void max310x_enable_ms(struct uart_port *port)
+{
+ /* Modem status not supported */
+}
+
+static unsigned int max310x_get_mctrl(struct uart_port *port)
+{
+ /* DCD and DSR are not wired and CTS/RTS is handled automatically
+ * so just indicate DSR and CAR asserted
+ */
+ return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
+ * so do nothing
+ */
+}
+
+static void max310x_break_ctl(struct uart_port *port, int break_state)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_update_bits(s->regmap, MAX310X_LCR_REG,
+ MAX310X_LCR_TXBREAK_BIT,
+ break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+ unsigned int lcr, flow = 0;
+ int baud;
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~IXANY;
+
+ /* Word size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr = MAX310X_LCR_WORD_LEN_5;
+ break;
+ case CS6:
+ lcr = MAX310X_LCR_WORD_LEN_6;
+ break;
+ case CS7:
+ lcr = MAX310X_LCR_WORD_LEN_7;
+ break;
+ case CS8:
+ default:
+ lcr = MAX310X_LCR_WORD_LEN_8;
+ break;
+ }
+
+ /* Parity */
+ if (termios->c_cflag & PARENB) {
+ lcr |= MAX310X_LCR_PARITY_BIT;
+ if (!(termios->c_cflag & PARODD))
+ lcr |= MAX310X_LCR_EVENPARITY_BIT;
+ }
+
+ /* Stop bits */
+ if (termios->c_cflag & CSTOPB)
+ lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
+
+ /* Update LCR register */
+ regmap_write(s->regmap, MAX310X_LCR_REG, lcr);
+
+ /* Set read status mask */
+ port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |
+ MAX310X_LSR_FRERR_BIT;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK)
+ port->ignore_status_mask |= MAX310X_LSR_RXBRK_BIT;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= MAX310X_LSR_RXPAR_BIT |
+ MAX310X_LSR_RXOVR_BIT |
+ MAX310X_LSR_FRERR_BIT |
+ MAX310X_LSR_RXBRK_BIT;
+
+ /* Configure flow control */
+ regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]);
+ regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
+ if (termios->c_cflag & CRTSCTS)
+ flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT |
+ MAX310X_FLOWCTRL_AUTORTS_BIT;
+ if (termios->c_iflag & IXON)
+ flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT |
+ MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+ if (termios->c_iflag & IXOFF)
+ flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT |
+ MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+ regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow);
+
+ /* Get baud rate generator configuration */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 4);
+
+ /* Setup baudrate generator */
+ max310x_set_baud(s, baud);
+
+ /* Update timeout according to new baud rate */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_startup(struct uart_port *port)
+{
+ unsigned int val, line = port->line;
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(0);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Configure baud rate, 9600 as default */
+ max310x_set_baud(s, 9600);
+
+ /* Configure LCR register, 8N1 mode by default */
+ val = MAX310X_LCR_WORD_LEN_8;
+ regmap_write(s->regmap, MAX310X_LCR_REG, val);
+
+ /* Configure MODE1 register */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_TRNSCVCTRL_BIT,
+ (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
+ ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
+
+ /* Configure MODE2 register */
+ val = MAX310X_MODE2_RXEMPTINV_BIT;
+ if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK)
+ val |= MAX310X_MODE2_LOOPBACK_BIT;
+ if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS)
+ val |= MAX310X_MODE2_ECHOSUPR_BIT;
+
+ /* Reset FIFOs */
+ val |= MAX310X_MODE2_FIFORST_BIT;
+ regmap_write(s->regmap, MAX310X_MODE2_REG, val);
+
+ /* Configure FIFO trigger level register */
+ /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */
+ val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64);
+ regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val);
+
+ /* Configure flow control levels */
+ /* Flow control halt level 96, resume level 48 */
+ val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96);
+ regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val);
+
+ /* Clear timeout register */
+ regmap_write(s->regmap, MAX310X_RXTO_REG, 0);
+
+ /* Configure LSR interrupt enable register */
+ /* Enable RX timeout interrupt */
+ val = MAX310X_LSR_RXTO_BIT;
+ regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val);
+
+ /* Clear FIFO reset */
+ regmap_update_bits(s->regmap, MAX310X_MODE2_REG,
+ MAX310X_MODE2_FIFORST_BIT, 0);
+
+ /* Clear IRQ status register by reading it */
+ regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val);
+
+ /* Configure interrupt enable register */
+ /* Enable CTS change interrupt */
+ val = MAX310X_IRQ_CTS_BIT;
+ /* Enable RX, TX interrupts */
+ val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX;
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, val);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+
+static void max310x_shutdown(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ /* Disable all interrupts */
+ mutex_lock(&s->max310x_mutex);
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+ mutex_unlock(&s->max310x_mutex);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+}
+
+static const char *max310x_type(struct uart_port *port)
+{
+ struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+ return (port->type == PORT_MAX310X) ? s->name : NULL;
+}
+
+static int max310x_request_port(struct uart_port *port)
+{
+ /* Do nothing */
+ return 0;
+}
+
+static void max310x_release_port(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void max310x_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_MAX310X;
+}
+
+static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X))
+ return 0;
+ if (ser->irq == port->irq)
+ return 0;
+
+ return -EINVAL;
+}
+
+static struct uart_ops max310x_ops = {
+ .tx_empty = max310x_tx_empty,
+ .set_mctrl = max310x_set_mctrl,
+ .get_mctrl = max310x_get_mctrl,
+ .stop_tx = max310x_stop_tx,
+ .start_tx = max310x_start_tx,
+ .stop_rx = max310x_stop_rx,
+ .enable_ms = max310x_enable_ms,
+ .break_ctl = max310x_break_ctl,
+ .startup = max310x_startup,
+ .shutdown = max310x_shutdown,
+ .set_termios = max310x_set_termios,
+ .type = max310x_type,
+ .request_port = max310x_request_port,
+ .release_port = max310x_release_port,
+ .config_port = max310x_config_port,
+ .verify_port = max310x_verify_port,
+};
+
+static int max310x_suspend(struct spi_device *spi, pm_message_t state)
+{
+ int ret;
+ struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "Suspend\n");
+
+ ret = uart_suspend_port(&s->uart, &s->port);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Enable sleep mode */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_FORCESLEEP_BIT,
+ MAX310X_MODE1_FORCESLEEP_BIT);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+
+ return ret;
+}
+
+static int max310x_resume(struct spi_device *spi)
+{
+ struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "Resume\n");
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(0);
+
+ mutex_lock(&s->max310x_mutex);
+
+ /* Disable sleep mode */
+ regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+ MAX310X_MODE1_FORCESLEEP_BIT,
+ 0);
+
+ max310x_wait_pll(s);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return uart_resume_port(&s->uart, &s->port);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned int val = 0;
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val);
+ mutex_unlock(&s->max310x_mutex);
+
+ return !!((val >> 4) & (1 << offset));
+}
+
+static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+ regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+ 1 << offset : 0);
+ mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+
+ regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+
+static int max310x_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+ mutex_lock(&s->max310x_mutex);
+
+ regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset,
+ 1 << offset);
+ regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+ 1 << offset : 0);
+
+ mutex_unlock(&s->max310x_mutex);
+
+ return 0;
+}
+#endif
+
+/* Generic platform data */
+static struct max310x_pdata generic_plat_data = {
+ .driver_flags = MAX310X_EXT_CLK,
+ .uart_flags[0] = MAX310X_ECHO_SUPRESS,
+ .frequency = 26000000,
+};
+
+static int __devinit max310x_probe(struct spi_device *spi)
+{
+ struct max310x_port *s;
+ struct device *dev = &spi->dev;
+ int chiptype = spi_get_device_id(spi)->driver_data;
+ struct max310x_pdata *pdata = dev->platform_data;
+ unsigned int val = 0;
+ int ret;
+
+ /* Check for IRQ */
+ if (spi->irq <= 0) {
+ dev_err(dev, "No IRQ specified\n");
+ return -ENOTSUPP;
+ }
+
+ /* Alloc port structure */
+ s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(dev, s);
+
+ if (!pdata) {
+ dev_warn(dev, "No platform data supplied, using defaults\n");
+ pdata = &generic_plat_data;
+ }
+ s->pdata = pdata;
+
+ /* Individual chip settings */
+ switch (chiptype) {
+ case MAX310X_TYPE_MAX3107:
+ s->name = "MAX3107";
+ s->nr_gpio = 4;
+ s->uart.nr = 1;
+ s->regcfg.max_register = 0x1f;
+ break;
+ case MAX310X_TYPE_MAX3108:
+ s->name = "MAX3108";
+ s->nr_gpio = 4;
+ s->uart.nr = 1;
+ s->regcfg.max_register = 0x1e;
+ break;
+ default:
+ dev_err(dev, "Unsupported chip type %i\n", chiptype);
+ return -ENOTSUPP;
+ }
+
+ /* Check input frequency */
+ if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
+ ((pdata->frequency < 500000) || (pdata->frequency > 35000000)))
+ goto err_freq;
+ /* Check frequency for quartz */
+ if (!(pdata->driver_flags & MAX310X_EXT_CLK) &&
+ ((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
+ goto err_freq;
+
+ mutex_init(&s->max310x_mutex);
+
+ /* Setup SPI bus */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ spi->max_speed_hz = 26000000;
+ spi_setup(spi);
+
+ /* Setup regmap */
+ s->regcfg.reg_bits = 8;
+ s->regcfg.val_bits = 8;
+ s->regcfg.read_flag_mask = 0x00;
+ s->regcfg.write_flag_mask = 0x80;
+ s->regcfg.cache_type = REGCACHE_RBTREE;
+ s->regcfg.writeable_reg = max3107_8_reg_writeable;
+ s->regcfg.volatile_reg = max310x_reg_volatile;
+ s->regcfg.precious_reg = max310x_reg_precious;
+ s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+ if (IS_ERR(s->regmap)) {
+ ret = PTR_ERR(s->regmap);
+ dev_err(dev, "Failed to initialize register map\n");
+ goto err_out;
+ }
+
+ /* Reset chip & check SPI function */
+ ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT);
+ if (ret) {
+ dev_err(dev, "SPI transfer failed\n");
+ goto err_out;
+ }
+ /* Clear chip reset */
+ regmap_write(s->regmap, MAX310X_MODE2_REG, 0);
+
+ switch (chiptype) {
+ case MAX310X_TYPE_MAX3107:
+ /* Check REV ID to ensure we are talking to what we expect */
+ regmap_read(s->regmap, MAX3107_REVID_REG, &val);
+ if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) {
+ dev_err(dev, "%s ID 0x%02x does not match\n",
+ s->name, val);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ break;
+ case MAX310X_TYPE_MAX3108:
+ /* MAX3108 have not REV ID register, we just check default value
+ * from clocksource register to make sure everything works.
+ */
+ regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+ if (val != (MAX310X_CLKSRC_EXTCLK_BIT |
+ MAX310X_CLKSRC_PLLBYP_BIT)) {
+ dev_err(dev, "%s not present\n", s->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ break;
+ }
+
+ /* Board specific configure */
+ if (pdata->init)
+ pdata->init();
+ if (pdata->suspend)
+ pdata->suspend(0);
+
+ /* Calculate referecne clock */
+ s->uartclk = max310x_set_ref_clk(s);
+
+ /* Disable all interrupts */
+ regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+
+ /* Setup MODE1 register */
+ val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */
+ if (pdata->driver_flags & MAX310X_AUTOSLEEP)
+ val = MAX310X_MODE1_AUTOSLEEP_BIT;
+ regmap_write(s->regmap, MAX310X_MODE1_REG, val);
+
+ /* Setup interrupt */
+ ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), s);
+ if (ret) {
+ dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq);
+ goto err_out;
+ }
+
+ /* Register UART driver */
+ s->uart.owner = THIS_MODULE;
+ s->uart.driver_name = dev_name(dev);
+ s->uart.dev_name = "ttyMAX";
+ s->uart.major = MAX310X_MAJOR;
+ s->uart.minor = MAX310X_MINOR;
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(dev, "Registering UART driver failed\n");
+ goto err_out;
+ }
+
+ /* Initialize workqueue for start TX */
+ s->wq = create_freezable_workqueue(dev_name(dev));
+ INIT_WORK(&s->tx_work, max310x_wq_proc);
+
+ /* Initialize UART port data */
+ s->port.line = 0;
+ s->port.dev = dev;
+ s->port.irq = spi->irq;
+ s->port.type = PORT_MAX310X;
+ s->port.fifosize = MAX310X_FIFO_SIZE;
+ s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port.iotype = UPIO_PORT;
+ s->port.membase = (void __iomem *)0xffffffff; /* Bogus value */
+ s->port.uartclk = s->uartclk;
+ s->port.ops = &max310x_ops;
+ uart_add_one_port(&s->uart, &s->port);
+
+#ifdef CONFIG_GPIOLIB
+ /* Setup GPIO cotroller */
+ if (pdata->gpio_base) {
+ s->gpio.owner = THIS_MODULE;
+ s->gpio.dev = dev;
+ s->gpio.label = dev_name(dev);
+ s->gpio.direction_input = max310x_gpio_direction_input;
+ s->gpio.get = max310x_gpio_get;
+ s->gpio.direction_output= max310x_gpio_direction_output;
+ s->gpio.set = max310x_gpio_set;
+ s->gpio.base = pdata->gpio_base;
+ s->gpio.ngpio = s->nr_gpio;
+ if (gpiochip_add(&s->gpio)) {
+ /* Indicate that we should not call gpiochip_remove */
+ s->gpio.base = 0;
+ }
+ } else
+ dev_info(dev, "GPIO support not enabled\n");
+#endif
+
+ /* Go to suspend mode */
+ if (pdata->suspend)
+ pdata->suspend(1);
+
+ return 0;
+
+err_freq:
+ dev_err(dev, "Frequency parameter incorrect\n");
+ ret = -EINVAL;
+
+err_out:
+ dev_set_drvdata(dev, NULL);
+
+ return ret;
+}
+
+static int __devexit max310x_remove(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct max310x_port *s = dev_get_drvdata(dev);
+ int ret = 0;
+
+ dev_dbg(dev, "Removing port\n");
+
+ devm_free_irq(dev, s->port.irq, s);
+
+ destroy_workqueue(s->wq);
+
+ uart_remove_one_port(&s->uart, &s->port);
+
+ uart_unregister_driver(&s->uart);
+
+#ifdef CONFIG_GPIOLIB
+ if (s->pdata->gpio_base) {
+ ret = gpiochip_remove(&s->gpio);
+ if (ret)
+ dev_err(dev, "Failed to remove gpio chip: %d\n", ret);
+ }
+#endif
+
+ dev_set_drvdata(dev, NULL);
+
+ if (s->pdata->suspend)
+ s->pdata->suspend(1);
+ if (s->pdata->exit)
+ s->pdata->exit();
+
+ return ret;
+}
+
+static const struct spi_device_id max310x_id_table[] = {
+ { "max3107", MAX310X_TYPE_MAX3107 },
+ { "max3108", MAX310X_TYPE_MAX3108 },
+};
+MODULE_DEVICE_TABLE(spi, max310x_id_table);
+
+static struct spi_driver max310x_driver = {
+ .driver = {
+ .name = "max310x",
+ .owner = THIS_MODULE,
+ },
+ .probe = max310x_probe,
+ .remove = __devexit_p(max310x_remove),
+ .suspend = max310x_suspend,
+ .resume = max310x_resume,
+ .id_table = max310x_id_table,
+};
+module_spi_driver(max310x_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("MAX310X serial driver");
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index bedac0d4c9ce..f19d04ed8586 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -775,11 +775,15 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
}
if (new->c_cflag & PARENB) {
+ if (new->c_cflag & CMSPAR)
+ mr1 |= MPC52xx_PSC_MODE_PARFORCE;
+
+ /* With CMSPAR, PARODD also means high parity (same as termios) */
mr1 |= (new->c_cflag & PARODD) ?
MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
- } else
+ } else {
mr1 |= MPC52xx_PSC_MODE_PARNONE;
-
+ }
mr2 = 0;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8131e2c28015..033e0bc9ebab 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -896,7 +896,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
return PTR_ERR(msm_port->clk);
if (msm_port->is_uartdm)
- clk_set_rate(msm_port->clk, 7372800);
+ clk_set_rate(msm_port->clk, 1843200);
port->uartclk = clk_get_rate(msm_port->clk);
printk(KERN_INFO "uartclk = %d\n", port->uartclk);
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index b25e6ee71443..925d1fa153db 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -223,9 +223,11 @@ static int __init smd_tty_init(void)
return ret;
for (i = 0; i < smd_tty_channels_len; i++) {
- tty_port_init(&smd_tty[smd_tty_channels[i].id].port);
- smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops;
- tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
+ struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
+ tty_port_init(port);
+ port->ops = &smd_tty_port_ops;
+ tty_port_register_device(port, smd_tty_driver,
+ smd_tty_channels[i].id, NULL);
}
return 0;
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 3a667eed63d6..68984136bfb1 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -262,7 +262,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
ctrl &= ~AUART_CTRL2_RTSEN;
if (mctrl & TIOCM_RTS) {
- if (u->state->port.flags & ASYNC_CTS_FLOW)
+ if (tty_port_cts_enabled(&u->state->port))
ctrl |= AUART_CTRL2_RTSEN;
}
@@ -457,11 +457,11 @@ static void mxs_auart_shutdown(struct uart_port *u)
writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
- writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
-
writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
u->membase + AUART_INTR_CLR);
+ writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
+
clk_disable_unprepare(s->clk);
}
@@ -796,6 +796,7 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
+ put_device(s->dev);
clk_put(s->clk);
free_irq(s->irq, s);
kfree(s);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 34e71874a892..df443b908ca3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
+
+ if (of_find_property(np, "no-loopback-test", NULL))
+ port->flags |= UPF_SKIP_TEST;
+
port->dev = &ofdev->dev;
if (type == PORT_TEGRA)
@@ -144,8 +148,15 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
switch (port_type) {
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
- ret = serial8250_register_port(&port);
+ {
+ /* For now the of bindings don't support the extra
+ 8250 specific bits */
+ struct uart_8250_port port8250;
+ memset(&port8250, 0, sizeof(port8250));
+ port8250.port = port;
+ ret = serial8250_register_8250_port(&port8250);
break;
+ }
#endif
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
case PORT_NWPSERIAL:
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d3cda0cb2df0..f175385bb304 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -32,16 +32,16 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
-#include <plat/dma.h>
-#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
@@ -57,8 +57,8 @@
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
/* FCR register bitmasks */
-#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
+#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4)
/* MVR register bitmasks */
#define OMAP_UART_MVR_SCHEME_SHIFT 30
@@ -71,12 +71,52 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+struct uart_omap_port {
+ struct uart_port port;
+ struct uart_omap_dma uart_dma;
+ struct device *dev;
+
+ unsigned char ier;
+ unsigned char lcr;
+ unsigned char mcr;
+ unsigned char fcr;
+ unsigned char efr;
+ unsigned char dll;
+ unsigned char dlh;
+ unsigned char mdr1;
+ unsigned char scr;
+
+ int use_dma;
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+ unsigned int lsr_break_flag;
+ unsigned char msr_saved_flags;
+ char name[20];
+ unsigned long port_activity;
+ u32 context_loss_cnt;
+ u32 errata;
+ u8 wakeups_enabled;
+ unsigned int irq_pending:1;
+
+ int DTR_gpio;
+ int DTR_inverted;
+ int DTR_active;
+
+ struct pm_qos_request pm_qos_request;
+ u32 latency;
+ u32 calc_latency;
+ struct work_struct qos_work;
+ struct pinctrl *pins;
+};
+
+#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port)))
+
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_rxdma_poll(unsigned long uart_no);
-static int serial_omap_start_rxdma(struct uart_omap_port *up);
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
static struct workqueue_struct *serial_omap_uart_wq;
@@ -101,6 +141,46 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
serial_out(up, UART_FCR, 0);
}
+static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->get_context_loss_count)
+ return 0;
+
+ return pdata->get_context_loss_count(up->dev);
+}
+
+static void serial_omap_set_forceidle(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->set_forceidle)
+ return;
+
+ pdata->set_forceidle(up->dev);
+}
+
+static void serial_omap_set_noidle(struct uart_omap_port *up)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->set_noidle)
+ return;
+
+ pdata->set_noidle(up->dev);
+}
+
+static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
+{
+ struct omap_uart_port_info *pdata = up->dev->platform_data;
+
+ if (!pdata || !pdata->enable_wakeup)
+ return;
+
+ pdata->enable_wakeup(up->dev, enable);
+}
+
/*
* serial_omap_get_divisor - calculate divisor value
* @port: uart port info
@@ -126,151 +206,55 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
return port->uartclk/(baud * divisor);
}
-static void serial_omap_stop_rxdma(struct uart_omap_port *up)
-{
- if (up->uart_dma.rx_dma_used) {
- del_timer(&up->uart_dma.rx_timer);
- omap_stop_dma(up->uart_dma.rx_dma_channel);
- omap_free_dma(up->uart_dma.rx_dma_channel);
- up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
- up->uart_dma.rx_dma_used = false;
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- }
-}
-
static void serial_omap_enable_ms(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
up->ier |= UART_IER_MSI;
serial_out(up, UART_IER, up->ier);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
- struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
+ struct uart_omap_port *up = to_uart_omap_port(port);
- if (up->use_dma &&
- up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
- /*
- * Check if dma is still active. If yes do nothing,
- * return. Else stop dma
- */
- if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
- return;
- omap_stop_dma(up->uart_dma.tx_dma_channel);
- omap_free_dma(up->uart_dma.tx_dma_channel);
- up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- }
-
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
if (up->ier & UART_IER_THRI) {
up->ier &= ~UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
}
- if (!up->use_dma && pdata && pdata->set_forceidle)
- pdata->set_forceidle(up->pdev);
+ serial_omap_set_forceidle(up);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_stop_rx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(&up->pdev->dev);
- if (up->use_dma)
- serial_omap_stop_rxdma(up);
+ pm_runtime_get_sync(up->dev);
up->ier &= ~UART_IER_RLSI;
up->port.read_status_mask &= ~UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
-}
-
-static inline void receive_chars(struct uart_omap_port *up,
- unsigned int *status)
-{
- struct tty_struct *tty = up->port.state->port.tty;
- unsigned int flag, lsr = *status;
- unsigned char ch = 0;
- int max_count = 256;
-
- do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- flag = TTY_NORMAL;
- up->port.icount.rx++;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- /*
- * For statistics only
- */
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- up->port.icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(&up->port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE) {
- up->port.icount.parity++;
- } else if (lsr & UART_LSR_FE) {
- up->port.icount.frame++;
- }
-
- if (lsr & UART_LSR_OE)
- up->port.icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= up->port.read_status_mask;
-
-#ifdef CONFIG_SERIAL_OMAP_CONSOLE
- if (up->port.line == up->port.cons->index) {
- /* Recover the break flag from console xmit */
- lsr |= up->lsr_break_flag;
- }
-#endif
- if (lsr & UART_LSR_BI)
- flag = TTY_BREAK;
- else if (lsr & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (lsr & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(&up->port, ch))
- goto ignore_char;
- uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
-ignore_char:
- lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
- spin_unlock(&up->port.lock);
- tty_flip_buffer_push(tty);
- spin_lock(&up->port.lock);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
-static void transmit_chars(struct uart_omap_port *up)
+static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
{
struct circ_buf *xmit = &up->port.state->xmit;
int count;
+ if (!(lsr & UART_LSR_THRE))
+ return;
+
if (up->port.x_char) {
serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
@@ -290,8 +274,11 @@ static void transmit_chars(struct uart_omap_port *up)
break;
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ spin_unlock(&up->port.lock);
uart_write_wakeup(&up->port);
+ spin_lock(&up->port.lock);
+ }
if (uart_circ_empty(xmit))
serial_omap_stop_tx(&up->port);
@@ -307,70 +294,13 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
static void serial_omap_start_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
- struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
- struct circ_buf *xmit;
- unsigned int start;
- int ret = 0;
-
- if (!up->use_dma) {
- pm_runtime_get_sync(&up->pdev->dev);
- serial_omap_enable_ier_thri(up);
- if (pdata && pdata->set_noidle)
- pdata->set_noidle(up->pdev);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- return;
- }
-
- if (up->uart_dma.tx_dma_used)
- return;
-
- xmit = &up->port.state->xmit;
-
- if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
- pm_runtime_get_sync(&up->pdev->dev);
- ret = omap_request_dma(up->uart_dma.uart_dma_tx,
- "UART Tx DMA",
- (void *)uart_tx_dma_callback, up,
- &(up->uart_dma.tx_dma_channel));
+ struct uart_omap_port *up = to_uart_omap_port(port);
- if (ret < 0) {
- serial_omap_enable_ier_thri(up);
- return;
- }
- }
- spin_lock(&(up->uart_dma.tx_lock));
- up->uart_dma.tx_dma_used = true;
- spin_unlock(&(up->uart_dma.tx_lock));
-
- start = up->uart_dma.tx_buf_dma_phys +
- (xmit->tail & (UART_XMIT_SIZE - 1));
-
- up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
- /*
- * It is a circular buffer. See if the buffer has wounded back.
- * If yes it will have to be transferred in two separate dma
- * transfers
- */
- if (start + up->uart_dma.tx_buf_size >=
- up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
- up->uart_dma.tx_buf_size =
- (up->uart_dma.tx_buf_dma_phys +
- UART_XMIT_SIZE) - start;
-
- omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.tx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_tx, 0);
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.tx_dma_channel);
+ pm_runtime_get_sync(up->dev);
+ serial_omap_enable_ier_thri(up);
+ serial_omap_set_noidle(up);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static unsigned int check_modem_status(struct uart_omap_port *up)
@@ -401,76 +331,158 @@ static unsigned int check_modem_status(struct uart_omap_port *up)
return status;
}
+static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr)
+{
+ unsigned int flag;
+
+ up->port.icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (lsr & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ up->port.icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(&up->port))
+ return;
+
+ }
+
+ if (lsr & UART_LSR_PE) {
+ flag = TTY_PARITY;
+ up->port.icount.parity++;
+ }
+
+ if (lsr & UART_LSR_FE) {
+ flag = TTY_FRAME;
+ up->port.icount.frame++;
+ }
+
+ if (lsr & UART_LSR_OE)
+ up->port.icount.overrun++;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+ if (up->port.line == up->port.cons->index) {
+ /* Recover the break flag from console xmit */
+ lsr |= up->lsr_break_flag;
+ }
+#endif
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag);
+}
+
+static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)
+{
+ unsigned char ch = 0;
+ unsigned int flag;
+
+ if (!(lsr & UART_LSR_DR))
+ return;
+
+ ch = serial_in(up, UART_RX);
+ flag = TTY_NORMAL;
+ up->port.icount.rx++;
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ return;
+
+ uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+}
+
/**
* serial_omap_irq() - This handles the interrupt from one port
* @irq: uart port irq number
* @dev_id: uart port info
*/
-static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+static irqreturn_t serial_omap_irq(int irq, void *dev_id)
{
struct uart_omap_port *up = dev_id;
+ struct tty_struct *tty = up->port.state->port.tty;
unsigned int iir, lsr;
- unsigned long flags;
+ unsigned int type;
+ irqreturn_t ret = IRQ_NONE;
+ int max_count = 256;
- pm_runtime_get_sync(&up->pdev->dev);
- iir = serial_in(up, UART_IIR);
- if (iir & UART_IIR_NO_INT) {
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
- return IRQ_NONE;
- }
+ spin_lock(&up->port.lock);
+ pm_runtime_get_sync(up->dev);
- spin_lock_irqsave(&up->port.lock, flags);
- lsr = serial_in(up, UART_LSR);
- if (iir & UART_IIR_RLSI) {
- if (!up->use_dma) {
- if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
- } else {
- up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- if ((serial_omap_start_rxdma(up) != 0) &&
- (lsr & UART_LSR_DR))
- receive_chars(up, &lsr);
+ do {
+ iir = serial_in(up, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ break;
+
+ ret = IRQ_HANDLED;
+ lsr = serial_in(up, UART_LSR);
+
+ /* extract IRQ type from IIR register */
+ type = iir & 0x3e;
+
+ switch (type) {
+ case UART_IIR_MSI:
+ check_modem_status(up);
+ break;
+ case UART_IIR_THRI:
+ transmit_chars(up, lsr);
+ break;
+ case UART_IIR_RX_TIMEOUT:
+ /* FALLTHROUGH */
+ case UART_IIR_RDI:
+ serial_omap_rdi(up, lsr);
+ break;
+ case UART_IIR_RLSI:
+ serial_omap_rlsi(up, lsr);
+ break;
+ case UART_IIR_CTS_RTS_DSR:
+ /* simply try again */
+ break;
+ case UART_IIR_XOFF:
+ /* FALLTHROUGH */
+ default:
+ break;
}
- }
+ } while (!(iir & UART_IIR_NO_INT) && max_count--);
- check_modem_status(up);
- if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
- transmit_chars(up);
+ spin_unlock(&up->port.lock);
- spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ tty_flip_buffer_push(tty);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
- return IRQ_HANDLED;
+
+ return ret;
}
static unsigned int serial_omap_tx_empty(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
unsigned int ret = 0;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line);
spin_lock_irqsave(&up->port.lock, flags);
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
return ret;
}
static unsigned int serial_omap_get_mctrl(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int status;
unsigned int ret = 0;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
status = check_modem_status(up);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line);
@@ -487,7 +499,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char mcr = 0;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
@@ -502,20 +514,31 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (mctrl & TIOCM_LOOP)
mcr |= UART_MCR_LOOP;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
up->mcr = serial_in(up, UART_MCR);
up->mcr |= mcr;
serial_out(up, UART_MCR, up->mcr);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+
+ if (gpio_is_valid(up->DTR_gpio) &&
+ !!(mctrl & TIOCM_DTR) != up->DTR_active) {
+ up->DTR_active = !up->DTR_active;
+ if (gpio_cansleep(up->DTR_gpio))
+ schedule_work(&up->qos_work);
+ else
+ gpio_set_value(up->DTR_gpio,
+ up->DTR_active != up->DTR_inverted);
+ }
}
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
@@ -523,12 +546,13 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_startup(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
int retval;
@@ -542,7 +566,7 @@ static int serial_omap_startup(struct uart_port *port)
dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
@@ -573,20 +597,6 @@ static int serial_omap_startup(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags);
up->msr_saved_flags = 0;
- if (up->use_dma) {
- free_page((unsigned long)up->port.state->xmit.buf);
- up->port.state->xmit.buf = dma_alloc_coherent(NULL,
- UART_XMIT_SIZE,
- (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
- 0);
- init_timer(&(up->uart_dma.rx_timer));
- up->uart_dma.rx_timer.function = serial_omap_rxdma_poll;
- up->uart_dma.rx_timer.data = up->port.line;
- /* Currently the buffer size is 4KB. Can increase it */
- up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
- up->uart_dma.rx_buf_size,
- (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
- }
/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
@@ -598,20 +608,20 @@ static int serial_omap_startup(struct uart_port *port)
/* Enable module level wake up */
serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
up->port_activity = jiffies;
return 0;
}
static void serial_omap_shutdown(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
/*
* Disable interrupts from this port
*/
@@ -634,19 +644,9 @@ static void serial_omap_shutdown(struct uart_port *port)
*/
if (serial_in(up, UART_LSR) & UART_LSR_DR)
(void) serial_in(up, UART_RX);
- if (up->use_dma) {
- dma_free_coherent(up->port.dev,
- UART_XMIT_SIZE, up->port.state->xmit.buf,
- up->uart_dma.tx_buf_dma_phys);
- up->port.state->xmit.buf = NULL;
- serial_omap_stop_rx(port);
- dma_free_coherent(up->port.dev,
- up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
- up->uart_dma.rx_buf_dma_phys);
- up->uart_dma.rx_buf = NULL;
- }
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
free_irq(up->port.irq, up);
}
@@ -667,19 +667,19 @@ serial_omap_configure_xonxoff
/*
* IXON Flag:
- * Enable XON/XOFF flow control on output.
- * Transmit XON1, XOFF1
+ * Flow control for OMAP.TX
+ * OMAP.RX should listen for XON/XOFF
*/
if (termios->c_iflag & IXON)
- up->efr |= OMAP_UART_SW_TX;
+ up->efr |= OMAP_UART_SW_RX;
/*
* IXOFF Flag:
- * Enable XON/XOFF flow control on input.
- * Receiver compares XON1, XOFF1.
+ * Flow control for OMAP.RX
+ * OMAP.TX should send XON/XOFF
*/
if (termios->c_iflag & IXOFF)
- up->efr |= OMAP_UART_SW_RX;
+ up->efr |= OMAP_UART_SW_TX;
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
@@ -715,13 +715,16 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
qos_work);
pm_qos_update_request(&up->pm_qos_request, up->latency);
+ if (gpio_is_valid(up->DTR_gpio))
+ gpio_set_value_cansleep(up->DTR_gpio,
+ up->DTR_active != up->DTR_inverted);
}
static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char cval = 0;
unsigned char efr = 0;
unsigned long flags = 0;
@@ -768,14 +771,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
UART_FCR_ENABLE_FIFO;
- if (up->use_dma)
- up->fcr |= UART_FCR_DMA_SELECT;
/*
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
spin_lock_irqsave(&up->port.lock, flags);
/*
@@ -845,14 +846,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
- if (up->use_dma) {
- serial_out(up, UART_TI752_TLR, 0);
- up->scr |= UART_FCR_TRIGGER_4;
- } else {
- /* Set receive FIFO threshold to 1 byte */
- up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
- up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
- }
+ /* Set receive FIFO threshold to 16 characters and
+ * transmit FIFO threshold to 16 spaces
+ */
+ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
+ up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK;
+ up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 |
+ UART_FCR_ENABLE_FIFO;
serial_out(up, UART_FCR, up->fcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -924,20 +924,30 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);
}
+static int serial_omap_set_wake(struct uart_port *port, unsigned int state)
+{
+ struct uart_omap_port *up = to_uart_omap_port(port);
+
+ serial_omap_enable_wakeup(up, state);
+
+ return 0;
+}
+
static void
serial_omap_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char efr;
dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
efr = serial_in(up, UART_EFR);
serial_out(up, UART_EFR, efr | UART_EFR_ECB);
@@ -948,14 +958,15 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
- if (!device_may_wakeup(&up->pdev->dev)) {
+ if (!device_may_wakeup(up->dev)) {
if (!state)
- pm_runtime_forbid(&up->pdev->dev);
+ pm_runtime_forbid(up->dev);
else
- pm_runtime_allow(&up->pdev->dev);
+ pm_runtime_allow(up->dev);
}
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static void serial_omap_release_port(struct uart_port *port)
@@ -971,7 +982,7 @@ static int serial_omap_request_port(struct uart_port *port)
static void serial_omap_config_port(struct uart_port *port, int flags)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
up->port.line);
@@ -989,7 +1000,7 @@ serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
static const char *
serial_omap_type(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line);
return up->name;
@@ -1032,26 +1043,33 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
- pm_runtime_put(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
}
static int serial_omap_poll_get_char(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int status;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
status = serial_in(up, UART_LSR);
- if (!(status & UART_LSR_DR))
- return NO_POLL_CHAR;
+ if (!(status & UART_LSR_DR)) {
+ status = NO_POLL_CHAR;
+ goto out;
+ }
status = serial_in(up, UART_RX);
- pm_runtime_put(&up->pdev->dev);
+
+out:
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
+
return status;
}
@@ -1065,7 +1083,7 @@ static struct uart_driver serial_omap_reg;
static void serial_omap_console_putchar(struct uart_port *port, int ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = to_uart_omap_port(port);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
@@ -1080,7 +1098,7 @@ serial_omap_console_write(struct console *co, const char *s,
unsigned int ier;
int locked = 1;
- pm_runtime_get_sync(&up->pdev->dev);
+ pm_runtime_get_sync(up->dev);
local_irq_save(flags);
if (up->port.sysrq)
@@ -1114,8 +1132,8 @@ serial_omap_console_write(struct console *co, const char *s,
if (up->msr_saved_flags)
check_modem_status(up);
- pm_runtime_mark_last_busy(&up->pdev->dev);
- pm_runtime_put_autosuspend(&up->pdev->dev);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
if (locked)
spin_unlock(&up->port.lock);
local_irq_restore(flags);
@@ -1179,6 +1197,7 @@ static struct uart_ops serial_omap_pops = {
.shutdown = serial_omap_shutdown,
.set_termios = serial_omap_set_termios,
.pm = serial_omap_pm,
+ .set_wake = serial_omap_set_wake,
.type = serial_omap_type,
.release_port = serial_omap_release_port,
.request_port = serial_omap_request_port,
@@ -1221,150 +1240,7 @@ static int serial_omap_resume(struct device *dev)
}
#endif
-static void serial_omap_rxdma_poll(unsigned long uart_no)
-{
- struct uart_omap_port *up = ui[uart_no];
- unsigned int curr_dma_pos, curr_transmitted_size;
- int ret = 0;
-
- curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
- if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
- (curr_dma_pos == 0)) {
- if (jiffies_to_msecs(jiffies - up->port_activity) <
- up->uart_dma.rx_timeout) {
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- } else {
- serial_omap_stop_rxdma(up);
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- }
- return;
- }
-
- curr_transmitted_size = curr_dma_pos -
- up->uart_dma.prev_rx_dma_pos;
- up->port.icount.rx += curr_transmitted_size;
- tty_insert_flip_string(up->port.state->port.tty,
- up->uart_dma.rx_buf +
- (up->uart_dma.prev_rx_dma_pos -
- up->uart_dma.rx_buf_dma_phys),
- curr_transmitted_size);
- tty_flip_buffer_push(up->port.state->port.tty);
- up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
- if (up->uart_dma.rx_buf_size +
- up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
- ret = serial_omap_start_rxdma(up);
- if (ret < 0) {
- serial_omap_stop_rxdma(up);
- up->ier |= (UART_IER_RDI | UART_IER_RLSI);
- serial_out(up, UART_IER, up->ier);
- }
- } else {
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- }
- up->port_activity = jiffies;
-}
-
-static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
-{
- return;
-}
-
-static int serial_omap_start_rxdma(struct uart_omap_port *up)
-{
- int ret = 0;
-
- if (up->uart_dma.rx_dma_channel == -1) {
- pm_runtime_get_sync(&up->pdev->dev);
- ret = omap_request_dma(up->uart_dma.uart_dma_rx,
- "UART Rx DMA",
- (void *)uart_rx_dma_callback, up,
- &(up->uart_dma.rx_dma_channel));
- if (ret < 0)
- return ret;
-
- omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC,
- up->uart_dma.rx_buf_dma_phys, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.rx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_rx, 0);
- }
- up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.rx_dma_channel);
- mod_timer(&up->uart_dma.rx_timer, jiffies +
- usecs_to_jiffies(up->uart_dma.rx_poll_rate));
- up->uart_dma.rx_dma_used = true;
- return ret;
-}
-
-static void serial_omap_continue_tx(struct uart_omap_port *up)
-{
- struct circ_buf *xmit = &up->port.state->xmit;
- unsigned int start = up->uart_dma.tx_buf_dma_phys
- + (xmit->tail & (UART_XMIT_SIZE - 1));
-
- if (uart_circ_empty(xmit))
- return;
-
- up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
- /*
- * It is a circular buffer. See if the buffer has wounded back.
- * If yes it will have to be transferred in two separate dma
- * transfers
- */
- if (start + up->uart_dma.tx_buf_size >=
- up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
- up->uart_dma.tx_buf_size =
- (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
- omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_CONSTANT,
- up->uart_dma.uart_base, 0, 0);
- omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
- OMAP_DMA_AMODE_POST_INC, start, 0, 0);
- omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
- OMAP_DMA_DATA_TYPE_S8,
- up->uart_dma.tx_buf_size, 1,
- OMAP_DMA_SYNC_ELEMENT,
- up->uart_dma.uart_dma_tx, 0);
- /* FIXME: Cache maintenance needed here? */
- omap_start_dma(up->uart_dma.tx_dma_channel);
-}
-
-static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
-{
- struct uart_omap_port *up = (struct uart_omap_port *)data;
- struct circ_buf *xmit = &up->port.state->xmit;
-
- xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
- (UART_XMIT_SIZE - 1);
- up->port.icount.tx += up->uart_dma.tx_buf_size;
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&up->port);
-
- if (uart_circ_empty(xmit)) {
- spin_lock(&(up->uart_dma.tx_lock));
- serial_omap_stop_tx(&up->port);
- up->uart_dma.tx_dma_used = false;
- spin_unlock(&(up->uart_dma.tx_lock));
- } else {
- omap_stop_dma(up->uart_dma.tx_dma_channel);
- serial_omap_continue_tx(up);
- }
- up->port_activity = jiffies;
- return;
-}
-
-static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up)
{
u32 mvr, scheme;
u16 revision, major, minor;
@@ -1389,7 +1265,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
minor = (mvr & OMAP_UART_MVR_MIN_MASK);
break;
default:
- dev_warn(&up->pdev->dev,
+ dev_warn(up->dev,
"Unknown %s revision, defaulting to highest\n",
up->name);
/* highest possible revision */
@@ -1417,7 +1293,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
}
}
-static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
+static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
@@ -1430,12 +1306,12 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
return omap_up_info;
}
-static int serial_omap_probe(struct platform_device *pdev)
+static int __devinit serial_omap_probe(struct platform_device *pdev)
{
struct uart_omap_port *up;
- struct resource *mem, *irq, *dma_tx, *dma_rx;
+ struct resource *mem, *irq;
struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
- int ret = -ENOSPC;
+ int ret;
if (pdev->dev.of_node)
omap_up_info = of_get_uart_port_info(&pdev->dev);
@@ -1458,19 +1334,30 @@ static int serial_omap_probe(struct platform_device *pdev)
return -EBUSY;
}
- dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!dma_rx)
- return -ENXIO;
-
- dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!dma_tx)
- return -ENXIO;
+ if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+ omap_up_info->DTR_present) {
+ ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+ if (ret < 0)
+ return ret;
+ ret = gpio_direction_output(omap_up_info->DTR_gpio,
+ omap_up_info->DTR_inverted);
+ if (ret < 0)
+ return ret;
+ }
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
if (!up)
return -ENOMEM;
- up->pdev = pdev;
+ if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+ omap_up_info->DTR_present) {
+ up->DTR_gpio = omap_up_info->DTR_gpio;
+ up->DTR_inverted = omap_up_info->DTR_inverted;
+ } else
+ up->DTR_gpio = -EINVAL;
+ up->DTR_active = 0;
+
+ up->dev = &pdev->dev;
up->port.dev = &pdev->dev;
up->port.type = PORT_OMAP;
up->port.iotype = UPIO_MEM;
@@ -1492,6 +1379,13 @@ static int serial_omap_probe(struct platform_device *pdev)
goto err_port_line;
}
+ up->pins = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(up->pins)) {
+ dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",
+ up->port.line, PTR_ERR(up->pins));
+ up->pins = NULL;
+ }
+
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
up->port.membase = devm_ioremap(&pdev->dev, mem->start,
@@ -1509,20 +1403,6 @@ static int serial_omap_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "No clock speed specified: using default:"
"%d\n", DEFAULT_CLK_SPEED);
}
- up->uart_dma.uart_base = mem->start;
-
- if (omap_up_info->dma_enabled) {
- up->uart_dma.uart_dma_tx = dma_tx->start;
- up->uart_dma.uart_dma_rx = dma_rx->start;
- up->use_dma = 1;
- up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size;
- up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;
- up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;
- spin_lock_init(&(up->uart_dma.tx_lock));
- spin_lock_init(&(up->uart_dma.rx_lock));
- up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
- up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
- }
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
@@ -1531,12 +1411,13 @@ static int serial_omap_probe(struct platform_device *pdev)
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
+ platform_set_drvdata(pdev, up);
+ pm_runtime_enable(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev,
omap_up_info->autosuspend_timeout);
pm_runtime_irq_safe(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
omap_serial_fill_features_erratas(up);
@@ -1548,8 +1429,8 @@ static int serial_omap_probe(struct platform_device *pdev)
if (ret != 0)
goto err_add_port;
- pm_runtime_put(&pdev->dev);
- platform_set_drvdata(pdev, up);
+ pm_runtime_mark_last_busy(up->dev);
+ pm_runtime_put_autosuspend(up->dev);
return 0;
err_add_port:
@@ -1562,17 +1443,15 @@ err_port_line:
return ret;
}
-static int serial_omap_remove(struct platform_device *dev)
+static int __devexit serial_omap_remove(struct platform_device *dev)
{
struct uart_omap_port *up = platform_get_drvdata(dev);
- if (up) {
- pm_runtime_disable(&up->pdev->dev);
- uart_remove_one_port(&serial_omap_reg, &up->port);
- pm_qos_remove_request(&up->pm_qos_request);
- }
+ pm_runtime_put_sync(up->dev);
+ pm_runtime_disable(up->dev);
+ uart_remove_one_port(&serial_omap_reg, &up->port);
+ pm_qos_remove_request(&up->pm_qos_request);
- platform_set_drvdata(dev, NULL);
return 0;
}
@@ -1602,7 +1481,7 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)
timeout--;
if (!timeout) {
/* Should *never* happen. we warn and carry on */
- dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n",
+ dev_crit(up->dev, "Errata i202: timedout %x\n",
serial_in(up, UART_LSR));
break;
}
@@ -1648,29 +1527,23 @@ static int serial_omap_runtime_suspend(struct device *dev)
if (!up)
return -EINVAL;
- if (!pdata || !pdata->enable_wakeup)
+ if (!pdata)
return 0;
- if (pdata->get_context_loss_count)
- up->context_loss_cnt = pdata->get_context_loss_count(dev);
+ up->context_loss_cnt = serial_omap_get_context_loss_count(up);
if (device_may_wakeup(dev)) {
if (!up->wakeups_enabled) {
- pdata->enable_wakeup(up->pdev, true);
+ serial_omap_enable_wakeup(up, true);
up->wakeups_enabled = true;
}
} else {
if (up->wakeups_enabled) {
- pdata->enable_wakeup(up->pdev, false);
+ serial_omap_enable_wakeup(up, false);
up->wakeups_enabled = false;
}
}
- /* Errata i291 */
- if (up->use_dma && pdata->set_forceidle &&
- (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
- pdata->set_forceidle(up->pdev);
-
up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
schedule_work(&up->qos_work);
@@ -1683,17 +1556,10 @@ static int serial_omap_runtime_resume(struct device *dev)
struct omap_uart_port_info *pdata = dev->platform_data;
if (up && pdata) {
- if (pdata->get_context_loss_count) {
- u32 loss_cnt = pdata->get_context_loss_count(dev);
+ u32 loss_cnt = serial_omap_get_context_loss_count(up);
if (up->context_loss_cnt != loss_cnt)
serial_omap_restore_context(up);
- }
-
- /* Errata i291 */
- if (up->use_dma && pdata->set_noidle &&
- (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
- pdata->set_noidle(up->pdev);
up->latency = up->calc_latency;
schedule_work(&up->qos_work);
@@ -1721,7 +1587,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match);
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
- .remove = serial_omap_remove,
+ .remove = __devexit_p(serial_omap_remove),
.driver = {
.name = DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 558ce8509a9a..4cd6c2381528 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -979,6 +979,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
priv->tx_dma_use = 1;
priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+ if (!priv->sg_tx_p) {
+ dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__);
+ return 0;
+ }
sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
sg = priv->sg_tx_p;
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 5847a4b855f7..9033fc6e0e4e 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_pxa_port *up = serial_pxa_ports[co->index];
unsigned int ier;
+ unsigned long flags;
+ int locked = 1;
clk_prepare_enable(up->clk);
+ local_irq_save(flags);
+ if (up->port.sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock(&up->port.lock);
+ else
+ spin_lock(&up->port.lock);
+
/*
* First save the IER then disable the interrupts
*/
@@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
+
clk_disable_unprepare(up->clk);
}
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 02d07bfcfa8a..bdaa06f3ab69 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -82,7 +82,7 @@ static inline const char *s3c24xx_serial_portname(struct uart_port *port)
static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
{
- return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+ return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
}
/*
@@ -268,7 +268,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
dbg("break!\n");
port->icount.brk++;
if (uart_handle_break(port))
- goto ignore_char;
+ goto ignore_char;
}
if (uerstat & S3C2410_UERSTAT_FRAME)
@@ -459,7 +459,7 @@ static int s3c24xx_serial_startup(struct uart_port *port)
s3c24xx_serial_portname(port), ourport);
if (ret != 0) {
- printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
+ dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq);
return ret;
}
@@ -473,7 +473,7 @@ static int s3c24xx_serial_startup(struct uart_port *port)
s3c24xx_serial_portname(port), ourport);
if (ret) {
- printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
+ dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq);
goto err;
}
@@ -502,7 +502,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
if (ret) {
- printk(KERN_ERR "cannot get irq %d\n", port->irq);
+ dev_err(port->dev, "cannot get irq %d\n", port->irq);
return ret;
}
@@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
switch (level) {
case 3:
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_disable(ourport->baudclk);
clk_disable(ourport->clk);
@@ -538,12 +538,12 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
case 0:
clk_enable(ourport->clk);
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_enable(ourport->baudclk);
break;
default:
- printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+ dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
}
}
@@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1;
- *best_clk = NULL;
clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
ourport->info->def_clk_sel;
for (cnt = 0; cnt < info->num_clks; cnt++) {
@@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
sprintf(clkname, "clk_uart_baud%d", cnt);
clk = clk_get(ourport->port.dev, clkname);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
continue;
rate = clk_get_rate(clk);
@@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
{
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct clk *clk = NULL;
+ struct clk *clk = ERR_PTR(-EINVAL);
unsigned long flags;
unsigned int baud, quot, clk_sel = 0;
unsigned int ulcon;
@@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
- if (!clk)
+ if (IS_ERR(clk))
return;
/* check to see if we need to change clock source */
@@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
if (ourport->baudclk != clk) {
s3c24xx_serial_setsource(port, clk_sel);
- if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+ if (!IS_ERR(ourport->baudclk)) {
clk_disable(ourport->baudclk);
- ourport->baudclk = NULL;
+ ourport->baudclk = ERR_PTR(-EINVAL);
}
clk_enable(clk);
@@ -1036,10 +1035,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
if (tty == NULL)
goto exit;
- termios = tty->termios;
+ termios = &tty->termios;
if (termios == NULL) {
- printk(KERN_WARNING "%s: no termios?\n", __func__);
+ dev_warn(uport->dev, "%s: no termios?\n", __func__);
goto exit;
}
@@ -1114,7 +1113,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
if (res == NULL) {
- printk(KERN_ERR "failed to find memory resource for uart\n");
+ dev_err(port->dev, "failed to find memory resource for uart\n");
return -EINVAL;
}
@@ -1130,7 +1129,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->rx_irq = ret;
ourport->tx_irq = ret + 1;
}
-
+
ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;
@@ -1160,7 +1159,11 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
struct uart_port *port = s3c24xx_dev_to_port(dev);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
+ if (IS_ERR(ourport->baudclk))
+ return -EINVAL;
+
+ return snprintf(buf, PAGE_SIZE, "* %s\n",
+ ourport->baudclk->name ?: "(null)");
}
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
@@ -1200,6 +1203,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
return -ENODEV;
}
+ ourport->baudclk = ERR_PTR(-EINVAL);
ourport->info = ourport->drv_data->info;
ourport->cfg = (pdev->dev.platform_data) ?
(struct s3c2410_uartcfg *)pdev->dev.platform_data :
@@ -1387,7 +1391,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
sprintf(clk_name, "clk_uart_baud%d", clk_sel);
clk = clk_get(port->dev, clk_name);
- if (!IS_ERR(clk) && clk != NULL)
+ if (!IS_ERR(clk))
rate = clk_get_rate(clk);
else
rate = 1;
@@ -1679,7 +1683,7 @@ static int __init s3c24xx_serial_modinit(void)
ret = uart_register_driver(&s3c24xx_uart_drv);
if (ret < 0) {
- printk(KERN_ERR "failed to register UART driver\n");
+ pr_err("Failed to register Samsung UART driver\n");
return -1;
}
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index e0b4b0a30a5a..9d664242b312 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -20,6 +20,10 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/io.h>
+
+#warning "Please try migrate to use new driver SCCNXP and report the status" \
+ "in the linux-serial mailing list."
#if defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
new file mode 100644
index 000000000000..05d767cf82a7
--- /dev/null
+++ b/drivers/tty/serial/sccnxp.c
@@ -0,0 +1,985 @@
+/*
+ * NXP (Philips) SCC+++(SCN+++) serial driver
+ *
+ * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.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.
+ */
+
+#if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/sccnxp.h>
+
+#define SCCNXP_NAME "uart-sccnxp"
+#define SCCNXP_MAJOR 204
+#define SCCNXP_MINOR 205
+
+#define SCCNXP_MR_REG (0x00)
+# define MR0_BAUD_NORMAL (0 << 0)
+# define MR0_BAUD_EXT1 (1 << 0)
+# define MR0_BAUD_EXT2 (5 << 0)
+# define MR0_FIFO (1 << 3)
+# define MR0_TXLVL (1 << 4)
+# define MR1_BITS_5 (0 << 0)
+# define MR1_BITS_6 (1 << 0)
+# define MR1_BITS_7 (2 << 0)
+# define MR1_BITS_8 (3 << 0)
+# define MR1_PAR_EVN (0 << 2)
+# define MR1_PAR_ODD (1 << 2)
+# define MR1_PAR_NO (4 << 2)
+# define MR2_STOP1 (7 << 0)
+# define MR2_STOP2 (0xf << 0)
+#define SCCNXP_SR_REG (0x01)
+#define SCCNXP_CSR_REG SCCNXP_SR_REG
+# define SR_RXRDY (1 << 0)
+# define SR_FULL (1 << 1)
+# define SR_TXRDY (1 << 2)
+# define SR_TXEMT (1 << 3)
+# define SR_OVR (1 << 4)
+# define SR_PE (1 << 5)
+# define SR_FE (1 << 6)
+# define SR_BRK (1 << 7)
+#define SCCNXP_CR_REG (0x02)
+# define CR_RX_ENABLE (1 << 0)
+# define CR_RX_DISABLE (1 << 1)
+# define CR_TX_ENABLE (1 << 2)
+# define CR_TX_DISABLE (1 << 3)
+# define CR_CMD_MRPTR1 (0x01 << 4)
+# define CR_CMD_RX_RESET (0x02 << 4)
+# define CR_CMD_TX_RESET (0x03 << 4)
+# define CR_CMD_STATUS_RESET (0x04 << 4)
+# define CR_CMD_BREAK_RESET (0x05 << 4)
+# define CR_CMD_START_BREAK (0x06 << 4)
+# define CR_CMD_STOP_BREAK (0x07 << 4)
+# define CR_CMD_MRPTR0 (0x0b << 4)
+#define SCCNXP_RHR_REG (0x03)
+#define SCCNXP_THR_REG SCCNXP_RHR_REG
+#define SCCNXP_IPCR_REG (0x04)
+#define SCCNXP_ACR_REG SCCNXP_IPCR_REG
+# define ACR_BAUD0 (0 << 7)
+# define ACR_BAUD1 (1 << 7)
+# define ACR_TIMER_MODE (6 << 4)
+#define SCCNXP_ISR_REG (0x05)
+#define SCCNXP_IMR_REG SCCNXP_ISR_REG
+# define IMR_TXRDY (1 << 0)
+# define IMR_RXRDY (1 << 1)
+# define ISR_TXRDY(x) (1 << ((x * 4) + 0))
+# define ISR_RXRDY(x) (1 << ((x * 4) + 1))
+#define SCCNXP_IPR_REG (0x0d)
+#define SCCNXP_OPCR_REG SCCNXP_IPR_REG
+#define SCCNXP_SOP_REG (0x0e)
+#define SCCNXP_ROP_REG (0x0f)
+
+/* Route helpers */
+#define MCTRL_MASK(sig) (0xf << (sig))
+#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0)
+#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0)
+
+/* Supported chip types */
+enum {
+ SCCNXP_TYPE_SC2681 = 2681,
+ SCCNXP_TYPE_SC2691 = 2691,
+ SCCNXP_TYPE_SC2692 = 2692,
+ SCCNXP_TYPE_SC2891 = 2891,
+ SCCNXP_TYPE_SC2892 = 2892,
+ SCCNXP_TYPE_SC28202 = 28202,
+ SCCNXP_TYPE_SC68681 = 68681,
+ SCCNXP_TYPE_SC68692 = 68692,
+};
+
+struct sccnxp_port {
+ struct uart_driver uart;
+ struct uart_port port[SCCNXP_MAX_UARTS];
+
+ const char *name;
+ int irq;
+
+ u8 imr;
+ u8 addr_mask;
+ int freq_std;
+
+ int flags;
+#define SCCNXP_HAVE_IO 0x00000001
+#define SCCNXP_HAVE_MR0 0x00000002
+
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+ struct console console;
+#endif
+
+ struct mutex sccnxp_mutex;
+
+ struct sccnxp_pdata pdata;
+};
+
+static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
+{
+ return readb(base + (reg << shift));
+}
+
+static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v)
+{
+ writeb(v, base + (reg << shift));
+}
+
+static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ return sccnxp_raw_read(port->membase, reg & s->addr_mask,
+ port->regshift);
+}
+
+static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v);
+}
+
+static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
+{
+ return sccnxp_read(port, (port->line << 3) + reg);
+}
+
+static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v)
+{
+ sccnxp_write(port, (port->line << 3) + reg, v);
+}
+
+static int sccnxp_update_best_err(int a, int b, int *besterr)
+{
+ int err = abs(a - b);
+
+ if ((*besterr < 0) || (*besterr > err)) {
+ *besterr = err;
+ return 0;
+ }
+
+ return 1;
+}
+
+struct baud_table {
+ u8 csr;
+ u8 acr;
+ u8 mr0;
+ int baud;
+};
+
+const struct baud_table baud_std[] = {
+ { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, },
+ { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, },
+ { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, },
+ { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, },
+ { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, },
+ { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, },
+ { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, },
+ { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, },
+ { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, },
+ { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, },
+ { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, },
+ { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, },
+ { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, },
+ { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, },
+ { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, },
+ { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, },
+ { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, },
+ { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, },
+ { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, },
+ { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, },
+ { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, },
+ { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, },
+ { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, },
+ { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, },
+ { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, },
+ { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, },
+ { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, },
+ { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, },
+ { 0, 0, 0, 0 }
+};
+
+static void sccnxp_set_baud(struct uart_port *port, int baud)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ int div_std, tmp_baud, bestbaud = baud, besterr = -1;
+ u8 i, acr = 0, csr = 0, mr0 = 0;
+
+ /* Find best baud from table */
+ for (i = 0; baud_std[i].baud && besterr; i++) {
+ if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0))
+ continue;
+ div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud);
+ tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std);
+ if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) {
+ acr = baud_std[i].acr;
+ csr = baud_std[i].csr;
+ mr0 = baud_std[i].mr0;
+ bestbaud = tmp_baud;
+ }
+ }
+
+ if (s->flags & SCCNXP_HAVE_MR0) {
+ /* Enable FIFO, set half level for TX */
+ mr0 |= MR0_FIFO | MR0_TXLVL;
+ /* Update MR0 */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr0);
+ }
+
+ sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE);
+ sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr);
+
+ dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n",
+ baud, bestbaud);
+}
+
+static void sccnxp_enable_irq(struct uart_port *port, int mask)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ s->imr |= mask << (port->line * 4);
+ sccnxp_write(port, SCCNXP_IMR_REG, s->imr);
+}
+
+static void sccnxp_disable_irq(struct uart_port *port, int mask)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ s->imr &= ~(mask << (port->line * 4));
+ sccnxp_write(port, SCCNXP_IMR_REG, s->imr);
+}
+
+static void sccnxp_set_bit(struct uart_port *port, int sig, int state)
+{
+ u8 bitmask;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) {
+ bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig);
+ if (state)
+ sccnxp_write(port, SCCNXP_SOP_REG, bitmask);
+ else
+ sccnxp_write(port, SCCNXP_ROP_REG, bitmask);
+ }
+}
+
+static void sccnxp_handle_rx(struct uart_port *port)
+{
+ u8 sr;
+ unsigned int ch, flag;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+ if (!tty)
+ return;
+
+ for (;;) {
+ sr = sccnxp_port_read(port, SCCNXP_SR_REG);
+ if (!(sr & SR_RXRDY))
+ break;
+ sr &= SR_PE | SR_FE | SR_OVR | SR_BRK;
+
+ ch = sccnxp_port_read(port, SCCNXP_RHR_REG);
+
+ port->icount.rx++;
+ flag = TTY_NORMAL;
+
+ if (unlikely(sr)) {
+ if (sr & SR_BRK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & SR_PE)
+ port->icount.parity++;
+ else if (sr & SR_FE)
+ port->icount.frame++;
+ else if (sr & SR_OVR)
+ port->icount.overrun++;
+
+ sr &= port->read_status_mask;
+ if (sr & SR_BRK)
+ flag = TTY_BREAK;
+ else if (sr & SR_PE)
+ flag = TTY_PARITY;
+ else if (sr & SR_FE)
+ flag = TTY_FRAME;
+ else if (sr & SR_OVR)
+ flag = TTY_OVERRUN;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ if (sr & port->ignore_status_mask)
+ continue;
+
+ uart_insert_char(port, sr, SR_OVR, ch, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+}
+
+static void sccnxp_handle_tx(struct uart_port *port)
+{
+ u8 sr;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (unlikely(port->x_char)) {
+ sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ /* Disable TX if FIFO is empty */
+ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) {
+ sccnxp_disable_irq(port, IMR_TXRDY);
+
+ /* Set direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 0);
+ }
+ return;
+ }
+
+ while (!uart_circ_empty(xmit)) {
+ sr = sccnxp_port_read(port, SCCNXP_SR_REG);
+ if (!(sr & SR_TXRDY))
+ break;
+
+ sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t sccnxp_ist(int irq, void *dev_id)
+{
+ int i;
+ u8 isr;
+ struct sccnxp_port *s = (struct sccnxp_port *)dev_id;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ for (;;) {
+ isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG);
+ isr &= s->imr;
+ if (!isr)
+ break;
+
+ dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr);
+
+ for (i = 0; i < s->uart.nr; i++) {
+ if (isr & ISR_RXRDY(i))
+ sccnxp_handle_rx(&s->port[i]);
+ if (isr & ISR_TXRDY(i))
+ sccnxp_handle_tx(&s->port[i]);
+ }
+ }
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return IRQ_HANDLED;
+}
+
+static void sccnxp_start_tx(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Set direction to output */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 1);
+
+ sccnxp_enable_irq(port, IMR_TXRDY);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static void sccnxp_stop_tx(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void sccnxp_stop_rx(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static unsigned int sccnxp_tx_empty(struct uart_port *port)
+{
+ u8 val;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ val = sccnxp_port_read(port, SCCNXP_SR_REG);
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return (val & SR_TXEMT) ? TIOCSER_TEMT : 0;
+}
+
+static void sccnxp_enable_ms(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ if (!(s->flags & SCCNXP_HAVE_IO))
+ return;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR);
+ sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static unsigned int sccnxp_get_mctrl(struct uart_port *port)
+{
+ u8 bitmask, ipr;
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
+
+ if (!(s->flags & SCCNXP_HAVE_IO))
+ return mctrl;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG);
+
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ DSR_IP);
+ mctrl &= ~TIOCM_DSR;
+ mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ CTS_IP);
+ mctrl &= ~TIOCM_CTS;
+ mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ DCD_IP);
+ mctrl &= ~TIOCM_CAR;
+ mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0;
+ }
+ if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) {
+ bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line],
+ RNG_IP);
+ mctrl &= ~TIOCM_RNG;
+ mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0;
+ }
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return mctrl;
+}
+
+static void sccnxp_break_ctl(struct uart_port *port, int break_state)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+ sccnxp_port_write(port, SCCNXP_CR_REG, break_state ?
+ CR_CMD_START_BREAK : CR_CMD_STOP_BREAK);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static void sccnxp_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+ u8 mr1, mr2;
+ int baud;
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~(IXON | IXOFF | IXANY);
+
+ /* Disable RX & TX, reset break condition, status and FIFOs */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET |
+ CR_RX_DISABLE | CR_TX_DISABLE);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET);
+
+ /* Word size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ mr1 = MR1_BITS_5;
+ break;
+ case CS6:
+ mr1 = MR1_BITS_6;
+ break;
+ case CS7:
+ mr1 = MR1_BITS_7;
+ break;
+ default:
+ case CS8:
+ mr1 = MR1_BITS_8;
+ break;
+ }
+
+ /* Parity */
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ mr1 |= MR1_PAR_ODD;
+ } else
+ mr1 |= MR1_PAR_NO;
+
+ /* Stop bits */
+ mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1;
+
+ /* Update desired format */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr1);
+ sccnxp_port_write(port, SCCNXP_MR_REG, mr2);
+
+ /* Set read status mask */
+ port->read_status_mask = SR_OVR;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= SR_PE | SR_FE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= SR_BRK;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNBRK)
+ port->ignore_status_mask |= SR_BRK;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;
+
+ /* Setup baudrate */
+ baud = uart_get_baud_rate(port, termios, old, 50,
+ (s->flags & SCCNXP_HAVE_MR0) ?
+ 230400 : 38400);
+ sccnxp_set_baud(port, baud);
+
+ /* Update timeout according to new baud rate */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /* Enable RX & TX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static int sccnxp_startup(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ if (s->flags & SCCNXP_HAVE_IO) {
+ /* Outputs are controlled manually */
+ sccnxp_write(port, SCCNXP_OPCR_REG, 0);
+ }
+
+ /* Reset break condition, status and FIFOs */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET);
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET);
+
+ /* Enable RX & TX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
+
+ /* Enable RX interrupt */
+ sccnxp_enable_irq(port, IMR_RXRDY);
+
+ mutex_unlock(&s->sccnxp_mutex);
+
+ return 0;
+}
+
+static void sccnxp_shutdown(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ mutex_lock(&s->sccnxp_mutex);
+
+ /* Disable interrupts */
+ sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
+
+ /* Disable TX & RX */
+ sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE);
+
+ /* Leave direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(port, DIR_OP, 0);
+
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static const char *sccnxp_type(struct uart_port *port)
+{
+ struct sccnxp_port *s = dev_get_drvdata(port->dev);
+
+ return (port->type == PORT_SC26XX) ? s->name : NULL;
+}
+
+static void sccnxp_release_port(struct uart_port *port)
+{
+ /* Do nothing */
+}
+
+static int sccnxp_request_port(struct uart_port *port)
+{
+ /* Do nothing */
+ return 0;
+}
+
+static void sccnxp_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_SC26XX;
+}
+
+static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s)
+{
+ if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX))
+ return 0;
+ if (s->irq == port->irq)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct uart_ops sccnxp_ops = {
+ .tx_empty = sccnxp_tx_empty,
+ .set_mctrl = sccnxp_set_mctrl,
+ .get_mctrl = sccnxp_get_mctrl,
+ .stop_tx = sccnxp_stop_tx,
+ .start_tx = sccnxp_start_tx,
+ .stop_rx = sccnxp_stop_rx,
+ .enable_ms = sccnxp_enable_ms,
+ .break_ctl = sccnxp_break_ctl,
+ .startup = sccnxp_startup,
+ .shutdown = sccnxp_shutdown,
+ .set_termios = sccnxp_set_termios,
+ .type = sccnxp_type,
+ .release_port = sccnxp_release_port,
+ .request_port = sccnxp_request_port,
+ .config_port = sccnxp_config_port,
+ .verify_port = sccnxp_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+static void sccnxp_console_putchar(struct uart_port *port, int c)
+{
+ int tryes = 100000;
+
+ while (tryes--) {
+ if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) {
+ sccnxp_port_write(port, SCCNXP_THR_REG, c);
+ break;
+ }
+ barrier();
+ }
+}
+
+static void sccnxp_console_write(struct console *co, const char *c, unsigned n)
+{
+ struct sccnxp_port *s = (struct sccnxp_port *)co->data;
+ struct uart_port *port = &s->port[co->index];
+
+ mutex_lock(&s->sccnxp_mutex);
+ uart_console_write(port, c, n, sccnxp_console_putchar);
+ mutex_unlock(&s->sccnxp_mutex);
+}
+
+static int sccnxp_console_setup(struct console *co, char *options)
+{
+ struct sccnxp_port *s = (struct sccnxp_port *)co->data;
+ struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
+ int baud = 9600, bits = 8, parity = 'n', flow = 'n';
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+#endif
+
+static int __devinit sccnxp_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int chiptype = pdev->id_entry->driver_data;
+ struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev);
+ int i, ret, fifosize, freq_min, freq_max;
+ struct sccnxp_port *s;
+ void __iomem *membase;
+
+ if (!res) {
+ dev_err(&pdev->dev, "Missing memory resource data\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ dev_set_name(&pdev->dev, SCCNXP_NAME);
+
+ s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(&pdev->dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, s);
+
+ mutex_init(&s->sccnxp_mutex);
+
+ /* Individual chip settings */
+ switch (chiptype) {
+ case SCCNXP_TYPE_SC2681:
+ s->name = "SC2681";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2691:
+ s->name = "SC2691";
+ s->uart.nr = 1;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x07;
+ s->flags = 0;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2692:
+ s->name = "SC2692";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC2891:
+ s->name = "SC2891";
+ s->uart.nr = 1;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 16;
+ freq_min = 100000;
+ freq_max = 8000000;
+ break;
+ case SCCNXP_TYPE_SC2892:
+ s->name = "SC2892";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 16;
+ freq_min = 100000;
+ freq_max = 8000000;
+ break;
+ case SCCNXP_TYPE_SC28202:
+ s->name = "SC28202";
+ s->uart.nr = 2;
+ s->freq_std = 14745600;
+ s->addr_mask = 0x7f;
+ s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
+ fifosize = 256;
+ freq_min = 1000000;
+ freq_max = 50000000;
+ break;
+ case SCCNXP_TYPE_SC68681:
+ s->name = "SC68681";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ case SCCNXP_TYPE_SC68692:
+ s->name = "SC68692";
+ s->uart.nr = 2;
+ s->freq_std = 3686400;
+ s->addr_mask = 0x0f;
+ s->flags = SCCNXP_HAVE_IO;
+ fifosize = 3;
+ freq_min = 1000000;
+ freq_max = 4000000;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype);
+ ret = -ENOTSUPP;
+ goto err_out;
+ }
+
+ if (!pdata) {
+ dev_warn(&pdev->dev,
+ "No platform data supplied, using defaults\n");
+ s->pdata.frequency = s->freq_std;
+ } else
+ memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));
+
+ s->irq = platform_get_irq(pdev, 0);
+ if (s->irq <= 0) {
+ dev_err(&pdev->dev, "Missing irq resource data\n");
+ ret = -ENXIO;
+ goto err_out;
+ }
+
+ /* Check input frequency */
+ if ((s->pdata.frequency < freq_min) ||
+ (s->pdata.frequency > freq_max)) {
+ dev_err(&pdev->dev, "Frequency out of bounds\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!membase) {
+ dev_err(&pdev->dev, "Failed to ioremap\n");
+ ret = -EIO;
+ goto err_out;
+ }
+
+ s->uart.owner = THIS_MODULE;
+ s->uart.dev_name = "ttySC";
+ s->uart.major = SCCNXP_MAJOR;
+ s->uart.minor = SCCNXP_MINOR;
+#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
+ s->uart.cons = &s->console;
+ s->uart.cons->device = uart_console_device;
+ s->uart.cons->write = sccnxp_console_write;
+ s->uart.cons->setup = sccnxp_console_setup;
+ s->uart.cons->flags = CON_PRINTBUFFER;
+ s->uart.cons->index = -1;
+ s->uart.cons->data = s;
+ strcpy(s->uart.cons->name, "ttySC");
+#endif
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering UART driver failed\n");
+ goto err_out;
+ }
+
+ for (i = 0; i < s->uart.nr; i++) {
+ s->port[i].line = i;
+ s->port[i].dev = &pdev->dev;
+ s->port[i].irq = s->irq;
+ s->port[i].type = PORT_SC26XX;
+ s->port[i].fifosize = fifosize;
+ s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port[i].iotype = UPIO_MEM;
+ s->port[i].mapbase = res->start;
+ s->port[i].membase = membase;
+ s->port[i].regshift = s->pdata.reg_shift;
+ s->port[i].uartclk = s->pdata.frequency;
+ s->port[i].ops = &sccnxp_ops;
+ uart_add_one_port(&s->uart, &s->port[i]);
+ /* Set direction to input */
+ if (s->flags & SCCNXP_HAVE_IO)
+ sccnxp_set_bit(&s->port[i], DIR_OP, 0);
+ }
+
+ /* Disable interrupts */
+ s->imr = 0;
+ sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
+
+ /* Board specific configure */
+ if (s->pdata.init)
+ s->pdata.init();
+
+ ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&pdev->dev), s);
+ if (!ret)
+ return 0;
+
+ dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq);
+
+err_out:
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit sccnxp_remove(struct platform_device *pdev)
+{
+ int i;
+ struct sccnxp_port *s = platform_get_drvdata(pdev);
+
+ devm_free_irq(&pdev->dev, s->irq, s);
+
+ for (i = 0; i < s->uart.nr; i++)
+ uart_remove_one_port(&s->uart, &s->port[i]);
+
+ uart_unregister_driver(&s->uart);
+ platform_set_drvdata(pdev, NULL);
+
+ if (s->pdata.exit)
+ s->pdata.exit();
+
+ return 0;
+}
+
+static const struct platform_device_id sccnxp_id_table[] = {
+ { "sc2681", SCCNXP_TYPE_SC2681 },
+ { "sc2691", SCCNXP_TYPE_SC2691 },
+ { "sc2692", SCCNXP_TYPE_SC2692 },
+ { "sc2891", SCCNXP_TYPE_SC2891 },
+ { "sc2892", SCCNXP_TYPE_SC2892 },
+ { "sc28202", SCCNXP_TYPE_SC28202 },
+ { "sc68681", SCCNXP_TYPE_SC68681 },
+ { "sc68692", SCCNXP_TYPE_SC68692 },
+};
+MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
+
+static struct platform_driver sccnxp_uart_driver = {
+ .driver = {
+ .name = SCCNXP_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = sccnxp_probe,
+ .remove = __devexit_p(sccnxp_remove),
+ .id_table = sccnxp_id_table,
+};
+module_platform_driver(sccnxp_uart_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("SCCNXP serial driver");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index a21dc8e3b7c0..046279ce3e8d 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -159,7 +159,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
retval = uport->ops->startup(uport);
if (retval == 0) {
if (uart_console(uport) && uport->cons->cflag) {
- tty->termios->c_cflag = uport->cons->cflag;
+ tty->termios.c_cflag = uport->cons->cflag;
uport->cons->cflag = 0;
}
/*
@@ -172,11 +172,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* Setup the RTS and DTR signals once the
* port is open and ready to respond.
*/
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
spin_lock_irq(&uport->lock);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
tty->hw_stopped = 1;
@@ -240,7 +240,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
- if (!tty || (tty->termios->c_cflag & HUPCL))
+ if (!tty || (tty->termios.c_cflag & HUPCL))
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
uart_port_shutdown(port);
@@ -440,10 +440,10 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
* If we have no tty, termios, or the port does not exist,
* then we can't set the parameters for this port.
*/
- if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
+ if (!tty || uport->type == PORT_UNKNOWN)
return;
- termios = tty->termios;
+ termios = &tty->termios;
/*
* Set flags based on termios cflag
@@ -614,7 +614,7 @@ static void uart_throttle(struct tty_struct *tty)
if (I_IXOFF(tty))
uart_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
uart_clear_mctrl(state->uart_port, TIOCM_RTS);
}
@@ -630,42 +630,48 @@ static void uart_unthrottle(struct tty_struct *tty)
uart_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (tty->termios.c_cflag & CRTSCTS)
uart_set_mctrl(port, TIOCM_RTS);
}
-static int uart_get_info(struct uart_state *state,
- struct serial_struct __user *retinfo)
+static void uart_get_info(struct tty_port *port,
+ struct uart_state *state,
+ struct serial_struct *retinfo)
{
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- /* Ensure the state we copy is consistent and no hardware changes
- occur as we go */
- mutex_lock(&port->mutex);
+ memset(retinfo, 0, sizeof(*retinfo));
- tmp.type = uport->type;
- tmp.line = uport->line;
- tmp.port = uport->iobase;
+ retinfo->type = uport->type;
+ retinfo->line = uport->line;
+ retinfo->port = uport->iobase;
if (HIGH_BITS_OFFSET)
- tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
- tmp.irq = uport->irq;
- tmp.flags = uport->flags;
- tmp.xmit_fifo_size = uport->fifosize;
- tmp.baud_base = uport->uartclk / 16;
- tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10;
- tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET;
+ retinfo->irq = uport->irq;
+ retinfo->flags = uport->flags;
+ retinfo->xmit_fifo_size = uport->fifosize;
+ retinfo->baud_base = uport->uartclk / 16;
+ retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10;
+ retinfo->closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
jiffies_to_msecs(port->closing_wait) / 10;
- tmp.custom_divisor = uport->custom_divisor;
- tmp.hub6 = uport->hub6;
- tmp.io_type = uport->iotype;
- tmp.iomem_reg_shift = uport->regshift;
- tmp.iomem_base = (void *)(unsigned long)uport->mapbase;
+ retinfo->custom_divisor = uport->custom_divisor;
+ retinfo->hub6 = uport->hub6;
+ retinfo->io_type = uport->iotype;
+ retinfo->iomem_reg_shift = uport->regshift;
+ retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
+}
+static int uart_get_info_user(struct uart_state *state,
+ struct serial_struct __user *retinfo)
+{
+ struct tty_port *port = &state->port;
+ struct serial_struct tmp;
+
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&port->mutex);
+ uart_get_info(port, state, &tmp);
mutex_unlock(&port->mutex);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
@@ -673,42 +679,30 @@ static int uart_get_info(struct uart_state *state,
return 0;
}
-static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
- struct serial_struct __user *newinfo)
+static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
+ struct uart_state *state,
+ struct serial_struct *new_info)
{
- struct serial_struct new_serial;
struct uart_port *uport = state->uart_port;
- struct tty_port *port = &state->port;
unsigned long new_port;
unsigned int change_irq, change_port, closing_wait;
unsigned int old_custom_divisor, close_delay;
upf_t old_flags, new_flags;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- new_port = new_serial.port;
+ new_port = new_info->port;
if (HIGH_BITS_OFFSET)
- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+ new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET;
- new_serial.irq = irq_canonicalize(new_serial.irq);
- close_delay = msecs_to_jiffies(new_serial.close_delay * 10);
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ new_info->irq = irq_canonicalize(new_info->irq);
+ close_delay = msecs_to_jiffies(new_info->close_delay * 10);
+ closing_wait = new_info->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
ASYNC_CLOSING_WAIT_NONE :
- msecs_to_jiffies(new_serial.closing_wait * 10);
+ msecs_to_jiffies(new_info->closing_wait * 10);
- /*
- * This semaphore protects port->count. It is also
- * very useful to prevent opens. Also, take the
- * port configuration semaphore to make sure that a
- * module insertion/removal doesn't change anything
- * under us.
- */
- mutex_lock(&port->mutex);
change_irq = !(uport->flags & UPF_FIXED_PORT)
- && new_serial.irq != uport->irq;
+ && new_info->irq != uport->irq;
/*
* Since changing the 'type' of the port changes its resource
@@ -717,29 +711,29 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
*/
change_port = !(uport->flags & UPF_FIXED_PORT)
&& (new_port != uport->iobase ||
- (unsigned long)new_serial.iomem_base != uport->mapbase ||
- new_serial.hub6 != uport->hub6 ||
- new_serial.io_type != uport->iotype ||
- new_serial.iomem_reg_shift != uport->regshift ||
- new_serial.type != uport->type);
+ (unsigned long)new_info->iomem_base != uport->mapbase ||
+ new_info->hub6 != uport->hub6 ||
+ new_info->io_type != uport->iotype ||
+ new_info->iomem_reg_shift != uport->regshift ||
+ new_info->type != uport->type);
old_flags = uport->flags;
- new_flags = new_serial.flags;
+ new_flags = new_info->flags;
old_custom_divisor = uport->custom_divisor;
if (!capable(CAP_SYS_ADMIN)) {
retval = -EPERM;
if (change_irq || change_port ||
- (new_serial.baud_base != uport->uartclk / 16) ||
+ (new_info->baud_base != uport->uartclk / 16) ||
(close_delay != port->close_delay) ||
(closing_wait != port->closing_wait) ||
- (new_serial.xmit_fifo_size &&
- new_serial.xmit_fifo_size != uport->fifosize) ||
+ (new_info->xmit_fifo_size &&
+ new_info->xmit_fifo_size != uport->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
goto exit;
uport->flags = ((uport->flags & ~UPF_USR_MASK) |
(new_flags & UPF_USR_MASK));
- uport->custom_divisor = new_serial.custom_divisor;
+ uport->custom_divisor = new_info->custom_divisor;
goto check_and_exit;
}
@@ -747,10 +741,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
* Ask the low level driver to verify the settings.
*/
if (uport->ops->verify_port)
- retval = uport->ops->verify_port(uport, &new_serial);
+ retval = uport->ops->verify_port(uport, new_info);
- if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) ||
- (new_serial.baud_base < 9600))
+ if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) ||
+ (new_info->baud_base < 9600))
retval = -EINVAL;
if (retval)
@@ -790,11 +784,11 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
uport->ops->release_port(uport);
uport->iobase = new_port;
- uport->type = new_serial.type;
- uport->hub6 = new_serial.hub6;
- uport->iotype = new_serial.io_type;
- uport->regshift = new_serial.iomem_reg_shift;
- uport->mapbase = (unsigned long)new_serial.iomem_base;
+ uport->type = new_info->type;
+ uport->hub6 = new_info->hub6;
+ uport->iotype = new_info->io_type;
+ uport->regshift = new_info->iomem_reg_shift;
+ uport->mapbase = (unsigned long)new_info->iomem_base;
/*
* Claim and map the new regions
@@ -835,16 +829,16 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
}
if (change_irq)
- uport->irq = new_serial.irq;
+ uport->irq = new_info->irq;
if (!(uport->flags & UPF_FIXED_PORT))
- uport->uartclk = new_serial.baud_base * 16;
+ uport->uartclk = new_info->baud_base * 16;
uport->flags = (uport->flags & ~UPF_CHANGE_MASK) |
(new_flags & UPF_CHANGE_MASK);
- uport->custom_divisor = new_serial.custom_divisor;
+ uport->custom_divisor = new_info->custom_divisor;
port->close_delay = close_delay;
port->closing_wait = closing_wait;
- if (new_serial.xmit_fifo_size)
- uport->fifosize = new_serial.xmit_fifo_size;
+ if (new_info->xmit_fifo_size)
+ uport->fifosize = new_info->xmit_fifo_size;
if (port->tty)
port->tty->low_latency =
(uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
@@ -873,6 +867,28 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state,
} else
retval = uart_startup(tty, state, 1);
exit:
+ return retval;
+}
+
+static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
+ struct serial_struct __user *newinfo)
+{
+ struct serial_struct new_serial;
+ struct tty_port *port = &state->port;
+ int retval;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ /*
+ * This semaphore protects port->count. It is also
+ * very useful to prevent opens. Also, take the
+ * port configuration semaphore to make sure that a
+ * module insertion/removal doesn't change anything
+ * under us.
+ */
+ mutex_lock(&port->mutex);
+ retval = uart_set_info(tty, port, state, &new_serial);
mutex_unlock(&port->mutex);
return retval;
}
@@ -1115,11 +1131,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
*/
switch (cmd) {
case TIOCGSERIAL:
- ret = uart_get_info(state, uarg);
+ ret = uart_get_info_user(state, uarg);
break;
case TIOCSSERIAL:
- ret = uart_set_info(tty, state, uarg);
+ ret = uart_set_info_user(tty, state, uarg);
break;
case TIOCSERCONFIG:
@@ -1187,7 +1203,7 @@ static void uart_set_ldisc(struct tty_struct *tty)
struct uart_port *uport = state->uart_port;
if (uport->ops->set_ldisc)
- uport->ops->set_ldisc(uport, tty->termios->c_line);
+ uport->ops->set_ldisc(uport, tty->termios.c_line);
}
static void uart_set_termios(struct tty_struct *tty,
@@ -1195,7 +1211,7 @@ static void uart_set_termios(struct tty_struct *tty,
{
struct uart_state *state = tty->driver_data;
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
/*
@@ -1206,9 +1222,9 @@ static void uart_set_termios(struct tty_struct *tty,
*/
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
- tty->termios->c_ospeed == old_termios->c_ospeed &&
- tty->termios->c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
+ tty->termios.c_ospeed == old_termios->c_ospeed &&
+ tty->termios.c_ispeed == old_termios->c_ispeed &&
+ RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) {
return;
}
@@ -1960,8 +1976,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
/*
* If that's unset, use the tty termios setting.
*/
- if (port->tty && port->tty->termios && termios.c_cflag == 0)
- termios = *(port->tty->termios);
+ if (port->tty && termios.c_cflag == 0)
+ termios = port->tty->termios;
if (console_suspend_enabled)
uart_change_pm(state, 0);
@@ -2293,6 +2309,36 @@ struct tty_driver *uart_console_device(struct console *co, int *index)
return p->tty_driver;
}
+static ssize_t uart_get_attr_uartclk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct tty_port *port = dev_get_drvdata(dev);
+ struct uart_state *state = container_of(port, struct uart_state, port);
+
+ mutex_lock(&state->port.mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk);
+ mutex_unlock(&state->port.mutex);
+
+ return ret;
+}
+
+static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
+
+static struct attribute *tty_dev_attrs[] = {
+ &dev_attr_uartclk.attr,
+ NULL,
+ };
+
+static const struct attribute_group tty_dev_attr_group = {
+ .attrs = tty_dev_attrs,
+ };
+
+static const struct attribute_group *tty_dev_attr_groups[] = {
+ &tty_dev_attr_group,
+ NULL
+ };
+
/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
@@ -2346,7 +2392,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
- tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+ tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
+ uport->line, uport->dev, port, tty_dev_attr_groups);
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, 1);
} else {
@@ -2492,7 +2539,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
- if (port->flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(port)) {
if (tty->hw_stopped) {
if (status) {
tty->hw_stopped = 0;
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 5b3eda2024fe..a9e2bd1ab534 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -668,7 +668,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "Insufficient resources.\n");
ret = -EFAULT;
- goto irq_err;
+ goto err;
}
port->irq = res->start;
@@ -676,7 +676,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
sirfport->p = pinctrl_get_select_default(&pdev->dev);
ret = IS_ERR(sirfport->p);
if (ret)
- goto pin_err;
+ goto err;
}
port->ops = &sirfsoc_uart_ops;
@@ -695,9 +695,6 @@ port_err:
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl)
pinctrl_put(sirfport->p);
-pin_err:
-irq_err:
- devm_iounmap(&pdev->dev, port->membase);
err:
return ret;
}
@@ -709,7 +706,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
if (sirfport->hw_flow_ctrl)
pinctrl_put(sirfport->p);
- devm_iounmap(&pdev->dev, port->membase);
uart_remove_one_port(&sirfsoc_uart_drv, port);
return 0;
}
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 675303b8ed84..b97913dcdbff 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -58,10 +58,16 @@
enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };
static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" };
+struct serial_uart_config {
+ char *name;
+ int dfl_xmit_fifo_size;
+ int flags;
+};
+
/*
* Here we define the default xmit fifo size used for each type of UART.
*/
-static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
+static const struct serial_uart_config uart_config[] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 593d40ad0a6b..70e3a525bc82 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -1359,7 +1359,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
}
}
- if ( (info->port.flags & ASYNC_CTS_FLOW) &&
+ if (tty_port_cts_enabled(&info->port) &&
(status & MISCSTATUS_CTS_LATCHED) ) {
if (info->port.tty->hw_stopped) {
if (status & MISCSTATUS_CTS) {
@@ -1840,22 +1840,22 @@ static void shutdown(struct mgsl_struct * info)
usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
-
+
/* Disable DMAEN (Port 7, Bit 14) */
/* This disconnects the DMA request signal from the ISA bus */
/* on the ISA adapter. This has no effect for the PCI adapter */
usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14));
-
+
/* Disable INTEN (Port 6, Bit12) */
/* This disconnects the IRQ request signal to the ISA bus */
/* on the ISA adapter. This has no effect for the PCI adapter */
usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12));
-
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
usc_set_serial_signals(info);
}
-
+
spin_unlock_irqrestore(&info->irq_spinlock,flags);
mgsl_release_resources(info);
@@ -1895,7 +1895,7 @@ static void mgsl_program_hw(struct mgsl_struct *info)
usc_EnableInterrupts(info, IO_PIN);
usc_get_serial_signals(info);
- if (info->netcount || info->port.tty->termios->c_cflag & CREAD)
+ if (info->netcount || info->port.tty->termios.c_cflag & CREAD)
usc_start_receiver(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -1908,14 +1908,14 @@ static void mgsl_change_params(struct mgsl_struct *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -2367,8 +2367,8 @@ static void mgsl_throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
mgsl_send_xchar(tty, STOP_CHAR(tty));
-
- if (tty->termios->c_cflag & CRTSCTS) {
+
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals &= ~SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -2401,8 +2401,8 @@ static void mgsl_unthrottle(struct tty_struct * tty)
else
mgsl_send_xchar(tty, START_CHAR(tty));
}
-
- if (tty->termios->c_cflag & CRTSCTS) {
+
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS;
usc_set_serial_signals(info);
@@ -3045,7 +3045,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_set_serial_signals(info);
@@ -3054,9 +3054,9 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -3067,7 +3067,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mgsl_start(tty);
}
@@ -3287,7 +3287,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3313,7 +3313,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -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);
@@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
} /* end of block_til_ready() */
+static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct mgsl_struct *info;
+ int line = tty->index;
+
+ /* verify range of specified line number */
+ if (line >= mgsl_device_count) {
+ printk("%s(%d):mgsl_open with invalid line #%d.\n",
+ __FILE__, __LINE__, line);
+ return -ENODEV;
+ }
+
+ /* find the info structure for the specified line */
+ info = mgsl_device_list;
+ while (info && info->line != line)
+ info = info->next_device;
+ if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
+ return -ENODEV;
+ tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
/* mgsl_open()
*
* Called when a port is opened. Init and enable port.
@@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
static int mgsl_open(struct tty_struct *tty, struct file * filp)
{
- struct mgsl_struct *info;
- int retval, line;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
+ int retval;
- /* verify range of specified line number */
- line = tty->index;
- if (line >= mgsl_device_count) {
- printk("%s(%d):mgsl_open with invalid line #%d.\n",
- __FILE__,__LINE__,line);
- return -ENODEV;
- }
-
- /* find the info structure for the specified line */
- info = mgsl_device_list;
- while(info && info->line != line)
- info = info->next_device;
- if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
- return -ENODEV;
-
- tty->driver_data = info;
info->port.tty = tty;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
} /* end of mgsl_allocate_device()*/
static const struct tty_operations mgsl_ops = {
+ .install = mgsl_install,
.open = mgsl_open,
.close = mgsl_close,
.write = mgsl_write,
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa1debf97cc7..b38e954eedd3 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -785,7 +785,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -794,9 +794,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->signals |= SerialSignal_RTS;
}
@@ -807,7 +807,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1372,7 +1372,7 @@ static void throttle(struct tty_struct * tty)
DBGINFO(("%s throttle\n", info->device_name));
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1397,7 +1397,7 @@ static void unthrottle(struct tty_struct * tty)
else
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS;
set_signals(info);
@@ -2053,7 +2053,7 @@ static void cts_change(struct slgt_info *info, unsigned short status)
wake_up_interruptible(&info->event_wait_q);
info->pending_bh |= BH_STATUS;
- if (info->port.flags & ASYNC_CTS_FLOW) {
+ if (tty_port_cts_enabled(&info->port)) {
if (info->port.tty) {
if (info->port.tty->hw_stopped) {
if (info->signals & SerialSignal_CTS) {
@@ -2493,7 +2493,7 @@ static void shutdown(struct slgt_info *info)
slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -2534,7 +2534,7 @@ static void program_hw(struct slgt_info *info)
get_signals(info);
if (info->netcount ||
- (info->port.tty && info->port.tty->termios->c_cflag & CREAD))
+ (info->port.tty && info->port.tty->termios.c_cflag & CREAD))
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -2548,11 +2548,11 @@ static void change_params(struct slgt_info *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
DBGINFO(("%s change_params\n", info->device_name));
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -3292,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3314,7 +3314,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if ((tty->termios->c_cflag & CBAUD))
+ if ((tty->termios.c_cflag & CBAUD))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -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);
@@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}
- for (i=0; i < port_count; ++i)
- tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
+ for (i = 0; i < port_count; ++i) {
+ struct slgt_info *info = port_array[i];
+ tty_port_register_device(&info->port, serial_driver, info->line,
+ &info->pdev->dev);
+ }
}
static int __devinit init_one(struct pci_dev *dev,
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a3dddc12d2fe..f17d9f3d84a2 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,
/* tty callbacks */
-/* Called when a port is opened. Init and enable port.
- */
-static int open(struct tty_struct *tty, struct file *filp)
+static int install(struct tty_driver *driver, struct tty_struct *tty)
{
SLMP_INFO *info;
- int retval, line;
- unsigned long flags;
+ int line = tty->index;
- line = tty->index;
if (line >= synclinkmp_device_count) {
printk("%s(%d): open with invalid line #%d.\n",
__FILE__,__LINE__,line);
@@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp)
}
info = synclinkmp_device_list;
- while(info && info->line != line)
+ while (info && info->line != line)
info = info->next_device;
if (sanity_check(info, tty->name, "open"))
return -ENODEV;
- if ( info->init_error ) {
+ if (info->init_error) {
printk("%s(%d):%s device is not allocated, init error=%d\n",
- __FILE__,__LINE__,info->device_name,info->init_error);
+ __FILE__, __LINE__, info->device_name,
+ info->init_error);
return -ENODEV;
}
tty->driver_data = info;
+
+ return tty_port_install(&info->port, driver, tty);
+}
+
+/* Called when a port is opened. Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+ SLMP_INFO *info = tty->driver_data;
+ unsigned long flags;
+ int retval;
+
info->port.tty = tty;
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -873,7 +882,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD &&
- !(tty->termios->c_cflag & CBAUD)) {
+ !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags);
set_signals(info);
@@ -882,9 +891,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
- tty->termios->c_cflag & CBAUD) {
+ tty->termios.c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -895,7 +904,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios.c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
tx_release(tty);
}
@@ -1473,7 +1482,7 @@ static void throttle(struct tty_struct * tty)
if (I_IXOFF(tty))
send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
set_signals(info);
@@ -1502,7 +1511,7 @@ static void unthrottle(struct tty_struct * tty)
send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
set_signals(info);
@@ -2491,7 +2500,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status )
}
}
- if ( (info->port.flags & ASYNC_CTS_FLOW) &&
+ if (tty_port_cts_enabled(&info->port) &&
(status & MISCSTATUS_CTS_LATCHED) ) {
if ( info->port.tty ) {
if (info->port.tty->hw_stopped) {
@@ -2708,7 +2717,7 @@ static void shutdown(SLMP_INFO * info)
reset_port(info);
- if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+ if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
@@ -2749,7 +2758,7 @@ static void program_hw(SLMP_INFO *info)
get_signals(info);
- if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) )
+ if (info->netcount || (info->port.tty && info->port.tty->termios.c_cflag & CREAD) )
rx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
@@ -2762,14 +2771,14 @@ static void change_params(SLMP_INFO *info)
unsigned cflag;
int bits_per_char;
- if (!info->port.tty || !info->port.tty->termios)
+ if (!info->port.tty)
return;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s change_params()\n",
__FILE__,__LINE__, info->device_name );
- cflag = info->port.tty->termios->c_cflag;
+ cflag = info->port.tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
/* otherwise assert DTR and RTS */
@@ -3306,7 +3315,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
- if (tty->termios->c_cflag & CLOCAL)
+ if (tty->termios.c_cflag & CLOCAL)
do_clocal = true;
/* Wait for carrier detect and the line to become
@@ -3332,7 +3341,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
@@ -3357,9 +3366,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);
@@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
static const struct tty_operations ops = {
+ .install = install,
.open = open,
.close = close,
.write = write,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index b425c79675ad..8a5a8b064616 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -181,10 +181,13 @@ struct tty_struct *alloc_tty_struct(void)
void free_tty_struct(struct tty_struct *tty)
{
+ if (!tty)
+ return;
if (tty->dev)
put_device(tty->dev);
kfree(tty->write_buf);
tty_buffer_free_all(tty);
+ tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -573,7 +576,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 +669,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);
@@ -1103,12 +1106,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;
@@ -1213,7 +1216,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
*/
static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
+ if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
+ strcpy(p, driver->name);
+ else
+ sprintf(p, "%s%d", driver->name, index + driver->name_base);
}
/**
@@ -1249,21 +1255,19 @@ int tty_init_termios(struct tty_struct *tty)
struct ktermios *tp;
int idx = tty->index;
- tp = tty->driver->termios[idx];
- if (tp == NULL) {
- tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
- if (tp == NULL)
- return -ENOMEM;
- memcpy(tp, &tty->driver->init_termios,
- sizeof(struct ktermios));
- tty->driver->termios[idx] = tp;
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ tty->termios = tty->driver->init_termios;
+ else {
+ /* Check for lazy saved data */
+ tp = tty->driver->termios[idx];
+ if (tp != NULL)
+ tty->termios = *tp;
+ else
+ tty->termios = tty->driver->init_termios;
}
- tty->termios = tp;
- tty->termios_locked = tp + 1;
-
/* Compatibility until drivers always set this */
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+ tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
return 0;
}
EXPORT_SYMBOL_GPL(tty_init_termios);
@@ -1403,10 +1407,18 @@ 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;
+ if (!tty->port)
+ tty->port = driver->ports[idx];
+
+ WARN_RATELIMIT(!tty->port,
+ "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n",
+ __func__, tty->driver->name);
+
/*
* Structures all installed ... call the ldisc open routines.
* If we fail here just call release_tty to clean up. No need
@@ -1415,9 +1427,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:
@@ -1426,6 +1440,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);
@@ -1436,22 +1451,25 @@ void tty_free_termios(struct tty_struct *tty)
{
struct ktermios *tp;
int idx = tty->index;
- /* Kill this flag and push into drivers for locking etc */
- if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* FIXME: Locking on ->termios array */
- tp = tty->termios;
- tty->driver->termios[idx] = NULL;
- kfree(tp);
+
+ /* If the port is going to reset then it has no termios to save */
+ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+ return;
+
+ /* Stash the termios data */
+ tp = tty->driver->termios[idx];
+ if (tp == NULL) {
+ tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+ if (tp == NULL) {
+ pr_warn("tty: no memory to save termios state.\n");
+ return;
+ }
+ tty->driver->termios[idx] = tp;
}
+ *tp = tty->termios;
}
EXPORT_SYMBOL(tty_free_termios);
-void tty_shutdown(struct tty_struct *tty)
-{
- tty_driver_remove_tty(tty->driver, tty);
- tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
/**
* release_one_tty - release tty structure memory
@@ -1462,7 +1480,6 @@ EXPORT_SYMBOL(tty_shutdown);
* in use. It also gets called when setup of a device fails.
*
* Locking:
- * tty_mutex - sometimes only
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
*
@@ -1495,11 +1512,6 @@ static void queue_release_one_tty(struct kref *kref)
{
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
- if (tty->ops->shutdown)
- tty->ops->shutdown(tty);
- else
- tty_shutdown(tty);
-
/* The hangup queue is now free so we can reuse it rather than
waste a chunk of memory for each port */
INIT_WORK(&tty->hangup_work, release_one_tty);
@@ -1528,16 +1540,20 @@ EXPORT_SYMBOL(tty_kref_put);
* and decrement the refcount of the backing module.
*
* Locking:
- * tty_mutex - sometimes only
+ * tty_mutex
* takes the file list lock internally when working on the list
* of ttys that the driver keeps.
- * FIXME: should we require tty_mutex is held here ??
*
*/
static void release_tty(struct tty_struct *tty, int idx)
{
/* This should always be true but check for the moment */
WARN_ON(tty->index != idx);
+ WARN_ON(!mutex_is_locked(&tty_mutex));
+ if (tty->ops->shutdown)
+ tty->ops->shutdown(tty);
+ tty_free_termios(tty);
+ tty_driver_remove_tty(tty->driver, tty);
if (tty->link)
tty_kref_put(tty->link);
@@ -1572,22 +1588,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
__func__, idx, tty->name);
return -1;
}
- if (tty->termios != tty->driver->termios[idx]) {
- printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n",
- __func__, idx, tty->name);
- return -1;
- }
if (tty->driver->other) {
if (o_tty != tty->driver->other->ttys[idx]) {
printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
__func__, idx, tty->name);
return -1;
}
- if (o_tty->termios != tty->driver->other->termios[idx]) {
- printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n",
- __func__, idx, tty->name);
- return -1;
- }
if (o_tty->link != tty) {
printk(KERN_DEBUG "%s: bad pty pointers\n", __func__);
return -1;
@@ -1628,7 +1634,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);
@@ -1637,10 +1643,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;
}
@@ -1652,7 +1659,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
@@ -1675,7 +1682,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));
@@ -1706,7 +1713,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();
}
@@ -1715,6 +1722,9 @@ int tty_release(struct inode *inode, struct file *filp)
* The closing flags are now consistent with the open counts on
* both sides, and we've completed the last operation that could
* block, so it's safe to proceed with closing.
+ *
+ * We must *not* drop the tty_mutex until we ensure that a further
+ * entry into tty_open can not pick up this tty.
*/
if (pty_master) {
if (--o_tty->count < 0) {
@@ -1766,12 +1776,13 @@ int tty_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&tty_mutex);
+ tty_unlock_pair(tty, o_tty);
+ /* At this point the TTY_CLOSING flag should ensure a dead tty
+ cannot be re-opened by a racing opener */
/* check whether both sides are closing ... */
- if (!tty_closing || (o_tty && !o_tty_closing)) {
- tty_unlock();
+ if (!tty_closing || (o_tty && !o_tty_closing))
return 0;
- }
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
@@ -1782,14 +1793,17 @@ 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).
*/
+ mutex_lock(&tty_mutex);
release_tty(tty, idx);
+ mutex_unlock(&tty_mutex);
/* Make this pty number available for reallocation */
if (devpts)
devpts_kill_index(inode, idx);
- tty_unlock();
return 0;
}
@@ -1893,6 +1907,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)
@@ -1916,8 +1933,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);
@@ -1938,17 +1954,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;
}
@@ -1977,7 +1995,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;
@@ -1989,17 +2007,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 &&
@@ -2007,11 +2023,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))
@@ -2094,10 +2109,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;
}
@@ -2756,7 +2774,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (ld->ops->ioctl) {
retval = ld->ops->ioctl(tty, file, cmd, arg);
if (retval == -ENOIOCTLCMD)
- retval = -EINVAL;
+ retval = -ENOTTY;
}
tty_ldisc_deref(ld);
return retval;
@@ -2934,6 +2952,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);
@@ -2991,6 +3010,15 @@ EXPORT_SYMBOL_GPL(tty_put_char);
struct class *tty_class;
+static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
+ unsigned int index, unsigned int count)
+{
+ /* init here, since reused cdevs cause crashes */
+ cdev_init(&driver->cdevs[index], &tty_fops);
+ driver->cdevs[index].owner = driver->owner;
+ return cdev_add(&driver->cdevs[index], dev, count);
+}
+
/**
* tty_register_device - register a tty device
* @driver: the tty driver that describes the tty device
@@ -3013,8 +3041,46 @@ struct class *tty_class;
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
+ return tty_register_device_attr(driver, index, device, NULL, NULL);
+}
+EXPORT_SYMBOL(tty_register_device);
+
+static void tty_device_create_release(struct device *dev)
+{
+ pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
+ kfree(dev);
+}
+
+/**
+ * tty_register_device_attr - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ * This field is optional, if there is no known struct device
+ * for this tty device it can be set to NULL safely.
+ * @drvdata: Driver data to be set to device.
+ * @attr_grp: Attribute group to be set on device.
+ *
+ * Returns a pointer to the struct device for this tty device
+ * (or ERR_PTR(-EFOO) on error).
+ *
+ * This call is required to be made to register an individual tty device
+ * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If
+ * that bit is not set, this function should not be called by a tty
+ * driver.
+ *
+ * Locking: ??
+ */
+struct device *tty_register_device_attr(struct tty_driver *driver,
+ unsigned index, struct device *device,
+ void *drvdata,
+ const struct attribute_group **attr_grp)
+{
char name[64];
- dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+ dev_t devt = MKDEV(driver->major, driver->minor_start) + index;
+ struct device *dev = NULL;
+ int retval = -ENODEV;
+ bool cdev = false;
if (index >= driver->num) {
printk(KERN_ERR "Attempt to register invalid tty line number "
@@ -3027,9 +3093,40 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
else
tty_line_name(driver, index, name);
- return device_create(tty_class, device, dev, NULL, name);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ retval = tty_cdev_add(driver, devt, index, 1);
+ if (retval)
+ goto error;
+ cdev = true;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev->devt = devt;
+ dev->class = tty_class;
+ dev->parent = device;
+ dev->release = tty_device_create_release;
+ dev_set_name(dev, "%s", name);
+ dev->groups = attr_grp;
+ dev_set_drvdata(dev, drvdata);
+
+ retval = device_register(dev);
+ if (retval)
+ goto error;
+
+ return dev;
+
+error:
+ put_device(dev);
+ if (cdev)
+ cdev_del(&driver->cdevs[index]);
+ return ERR_PTR(retval);
}
-EXPORT_SYMBOL(tty_register_device);
+EXPORT_SYMBOL_GPL(tty_register_device_attr);
/**
* tty_unregister_device - unregister a tty device
@@ -3046,31 +3143,82 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(tty_class,
MKDEV(driver->major, driver->minor_start) + index);
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC))
+ cdev_del(&driver->cdevs[index]);
}
EXPORT_SYMBOL(tty_unregister_device);
-struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
+/**
+ * __tty_alloc_driver -- allocate tty driver
+ * @lines: count of lines this driver can handle at most
+ * @owner: module which is repsonsible for this driver
+ * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags
+ *
+ * This should not be called directly, some of the provided macros should be
+ * used instead. Use IS_ERR and friends on @retval.
+ */
+struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
+ unsigned long flags)
{
struct tty_driver *driver;
+ unsigned int cdevs = 1;
+ int err;
+
+ if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
+ return ERR_PTR(-EINVAL);
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
- if (driver) {
- kref_init(&driver->kref);
- driver->magic = TTY_DRIVER_MAGIC;
- driver->num = lines;
- driver->owner = owner;
- /* later we'll move allocation of tables here */
+ if (!driver)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&driver->kref);
+ driver->magic = TTY_DRIVER_MAGIC;
+ driver->num = lines;
+ driver->owner = owner;
+ driver->flags = flags;
+
+ if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
+ driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
+ GFP_KERNEL);
+ driver->termios = kcalloc(lines, sizeof(*driver->termios),
+ GFP_KERNEL);
+ if (!driver->ttys || !driver->termios) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
}
+
+ if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+ driver->ports = kcalloc(lines, sizeof(*driver->ports),
+ GFP_KERNEL);
+ if (!driver->ports) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+ cdevs = lines;
+ }
+
+ driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
+ if (!driver->cdevs) {
+ err = -ENOMEM;
+ goto err_free_all;
+ }
+
return driver;
+err_free_all:
+ kfree(driver->ports);
+ kfree(driver->ttys);
+ kfree(driver->termios);
+ kfree(driver);
+ return ERR_PTR(err);
}
-EXPORT_SYMBOL(__alloc_tty_driver);
+EXPORT_SYMBOL(__tty_alloc_driver);
static void destruct_tty_driver(struct kref *kref)
{
struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
int i;
struct ktermios *tp;
- void *p;
if (driver->flags & TTY_DRIVER_INSTALLED) {
/*
@@ -3087,13 +3235,14 @@ static void destruct_tty_driver(struct kref *kref)
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
- p = driver->ttys;
proc_tty_unregister_driver(driver);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- cdev_del(&driver->cdev);
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
+ cdev_del(&driver->cdevs[0]);
}
+ kfree(driver->cdevs);
+ kfree(driver->ports);
+ kfree(driver->termios);
+ kfree(driver->ttys);
kfree(driver);
}
@@ -3124,15 +3273,8 @@ int tty_register_driver(struct tty_driver *driver)
int error;
int i;
dev_t dev;
- void **p = NULL;
struct device *d;
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
- p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- }
-
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
@@ -3144,28 +3286,13 @@ int tty_register_driver(struct tty_driver *driver)
dev = MKDEV(driver->major, driver->minor_start);
error = register_chrdev_region(dev, driver->num, driver->name);
}
- if (error < 0) {
- kfree(p);
- return error;
- }
+ if (error < 0)
+ goto err;
- if (p) {
- driver->ttys = (struct tty_struct **)p;
- driver->termios = (struct ktermios **)(p + driver->num);
- } else {
- driver->ttys = NULL;
- driver->termios = NULL;
- }
-
- cdev_init(&driver->cdev, &tty_fops);
- driver->cdev.owner = driver->owner;
- error = cdev_add(&driver->cdev, dev, driver->num);
- if (error) {
- unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
- return error;
+ if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
+ error = tty_cdev_add(driver, dev, 0, driver->num);
+ if (error)
+ goto err_unreg_char;
}
mutex_lock(&tty_mutex);
@@ -3177,7 +3304,7 @@ int tty_register_driver(struct tty_driver *driver)
d = tty_register_device(driver, i, NULL);
if (IS_ERR(d)) {
error = PTR_ERR(d);
- goto err;
+ goto err_unreg_devs;
}
}
}
@@ -3185,7 +3312,7 @@ int tty_register_driver(struct tty_driver *driver)
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;
-err:
+err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);
@@ -3193,13 +3320,11 @@ err:
list_del(&driver->tty_drivers);
mutex_unlock(&tty_mutex);
+err_unreg_char:
unregister_chrdev_region(dev, driver->num);
- driver->ttys = NULL;
- driver->termios = NULL;
- kfree(p);
+err:
return error;
}
-
EXPORT_SYMBOL(tty_register_driver);
/*
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index a1b9a2f68567..12b1fa0f4f86 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -410,7 +410,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
{
- tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+ tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
}
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
@@ -427,7 +427,7 @@ EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
speed_t tty_get_baud_rate(struct tty_struct *tty)
{
- speed_t baud = tty_termios_baud_rate(tty->termios);
+ speed_t baud = tty_termios_baud_rate(&tty->termios);
if (baud == 38400 && tty->alt_speed) {
if (!tty->warned) {
@@ -509,14 +509,14 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
mutex_lock(&tty->termios_mutex);
- old_termios = *tty->termios;
- *tty->termios = *new_termios;
- unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+ old_termios = tty->termios;
+ tty->termios = *new_termios;
+ unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
int extproc = (old_termios.c_lflag & EXTPROC) |
- (tty->termios->c_lflag & EXTPROC);
+ (tty->termios.c_lflag & EXTPROC);
int old_flow = ((old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021'));
@@ -542,7 +542,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
if (tty->ops->set_termios)
(*tty->ops->set_termios)(tty, &old_termios);
else
- tty_termios_copy_hw(tty->termios, &old_termios);
+ tty_termios_copy_hw(&tty->termios, &old_termios);
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
@@ -578,7 +578,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
return retval;
mutex_lock(&tty->termios_mutex);
- memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+ tmp_termios = tty->termios;
mutex_unlock(&tty->termios_mutex);
if (opt & TERMIOS_TERMIO) {
@@ -632,14 +632,14 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
- memcpy(kterm, tty->termios, sizeof(struct ktermios));
+ *kterm = tty->termios;
mutex_unlock(&tty->termios_mutex);
}
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
- memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+ *kterm = tty->termios_locked;
mutex_unlock(&tty->termios_mutex);
}
@@ -707,16 +707,16 @@ static int get_sgflags(struct tty_struct *tty)
{
int flags = 0;
- if (!(tty->termios->c_lflag & ICANON)) {
- if (tty->termios->c_lflag & ISIG)
+ if (!(tty->termios.c_lflag & ICANON)) {
+ if (tty->termios.c_lflag & ISIG)
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
}
- if (tty->termios->c_lflag & ECHO)
+ if (tty->termios.c_lflag & ECHO)
flags |= 0x08; /* echo */
- if (tty->termios->c_oflag & OPOST)
- if (tty->termios->c_oflag & ONLCR)
+ if (tty->termios.c_oflag & OPOST)
+ if (tty->termios.c_oflag & ONLCR)
flags |= 0x10; /* crmod */
return flags;
}
@@ -726,10 +726,10 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
struct sgttyb tmp;
mutex_lock(&tty->termios_mutex);
- tmp.sg_ispeed = tty->termios->c_ispeed;
- tmp.sg_ospeed = tty->termios->c_ospeed;
- tmp.sg_erase = tty->termios->c_cc[VERASE];
- tmp.sg_kill = tty->termios->c_cc[VKILL];
+ tmp.sg_ispeed = tty->termios.c_ispeed;
+ tmp.sg_ospeed = tty->termios.c_ospeed;
+ tmp.sg_erase = tty->termios.c_cc[VERASE];
+ tmp.sg_kill = tty->termios.c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
mutex_unlock(&tty->termios_mutex);
@@ -787,7 +787,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- termios = *tty->termios;
+ termios = tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
@@ -808,12 +808,12 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
struct tchars tmp;
mutex_lock(&tty->termios_mutex);
- tmp.t_intrc = tty->termios->c_cc[VINTR];
- tmp.t_quitc = tty->termios->c_cc[VQUIT];
- tmp.t_startc = tty->termios->c_cc[VSTART];
- tmp.t_stopc = tty->termios->c_cc[VSTOP];
- tmp.t_eofc = tty->termios->c_cc[VEOF];
- tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+ tmp.t_intrc = tty->termios.c_cc[VINTR];
+ tmp.t_quitc = tty->termios.c_cc[VQUIT];
+ tmp.t_startc = tty->termios.c_cc[VSTART];
+ tmp.t_stopc = tty->termios.c_cc[VSTOP];
+ tmp.t_eofc = tty->termios.c_cc[VEOF];
+ tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
mutex_unlock(&tty->termios_mutex);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -825,12 +825,12 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- tty->termios->c_cc[VINTR] = tmp.t_intrc;
- tty->termios->c_cc[VQUIT] = tmp.t_quitc;
- tty->termios->c_cc[VSTART] = tmp.t_startc;
- tty->termios->c_cc[VSTOP] = tmp.t_stopc;
- tty->termios->c_cc[VEOF] = tmp.t_eofc;
- tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+ tty->termios.c_cc[VINTR] = tmp.t_intrc;
+ tty->termios.c_cc[VQUIT] = tmp.t_quitc;
+ tty->termios.c_cc[VSTART] = tmp.t_startc;
+ tty->termios.c_cc[VSTOP] = tmp.t_stopc;
+ tty->termios.c_cc[VEOF] = tmp.t_eofc;
+ tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -842,14 +842,14 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
struct ltchars tmp;
mutex_lock(&tty->termios_mutex);
- tmp.t_suspc = tty->termios->c_cc[VSUSP];
+ tmp.t_suspc = tty->termios.c_cc[VSUSP];
/* what is dsuspc anyway? */
- tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
- tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+ tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
+ tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
/* what is flushc anyway? */
- tmp.t_flushc = tty->termios->c_cc[VEOL2];
- tmp.t_werasc = tty->termios->c_cc[VWERASE];
- tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+ tmp.t_flushc = tty->termios.c_cc[VEOL2];
+ tmp.t_werasc = tty->termios.c_cc[VWERASE];
+ tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
mutex_unlock(&tty->termios_mutex);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -862,14 +862,14 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+ tty->termios.c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
- tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
- tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+ tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
+ tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
/* what is flushc anyway? */
- tty->termios->c_cc[VEOL2] = tmp.t_flushc;
- tty->termios->c_cc[VWERASE] = tmp.t_werasc;
- tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+ tty->termios.c_cc[VEOL2] = tmp.t_flushc;
+ tty->termios.c_cc[VWERASE] = tmp.t_werasc;
+ tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -920,12 +920,12 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
struct ktermios old;
mutex_lock(&tty->termios_mutex);
- old = *tty->termios;
- tty->termios->c_cflag &= ~CLOCAL;
- tty->termios->c_cflag |= bit;
+ old = tty->termios;
+ tty->termios.c_cflag &= ~CLOCAL;
+ tty->termios.c_cflag |= bit;
if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old);
- if ((tty->termios->c_cflag & CLOCAL) != bit)
+ if ((tty->termios.c_cflag & CLOCAL) != bit)
ret = -EINVAL;
mutex_unlock(&tty->termios_mutex);
return ret;
@@ -1031,7 +1031,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
(struct termios __user *) arg))
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
- memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+ real_tty->termios_locked = kterm;
mutex_unlock(&real_tty->termios_mutex);
return 0;
#else
@@ -1048,7 +1048,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
(struct termios __user *) arg))
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
- memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+ real_tty->termios_locked = kterm;
mutex_unlock(&real_tty->termios_mutex);
return ret;
#endif
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 6f99c9959f0c..4d7b56268c79 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{
mutex_lock(&tty->termios_mutex);
- tty->termios->c_line = num;
+ tty->termios.c_line = num;
mutex_unlock(&tty->termios_mutex);
}
@@ -568,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.
@@ -582,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
@@ -595,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);
/*
@@ -605,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);
}
@@ -623,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
@@ -650,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 */
@@ -665,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;
}
@@ -708,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;
}
@@ -722,9 +722,9 @@ enable:
static void tty_reset_termios(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
- *tty->termios = tty->driver->init_termios;
- tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
- tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+ tty->termios = tty->driver->init_termios;
+ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+ tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
mutex_unlock(&tty->termios_mutex);
}
@@ -816,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
@@ -831,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;
@@ -846,7 +846,7 @@ retry:
if (reset == 0) {
- if (!tty_ldisc_reinit(tty, tty->termios->c_line))
+ if (!tty_ldisc_reinit(tty, tty->termios.c_line))
err = tty_ldisc_open(tty, tty->ldisc);
else
err = 1;
@@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_enable(tty);
return 0;
}
+
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+ mutex_lock(&tty->ldisc_mutex);
+ /*
+ * Now kill off the ldisc
+ */
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+
+ /* Ensure the next open requests the N_TTY ldisc */
+ tty_set_termios_ldisc(tty, N_TTY);
+ mutex_unlock(&tty->ldisc_mutex);
+}
+
/**
* tty_ldisc_release - release line discipline
* @tty: tty being shut down
@@ -912,28 +929,21 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
* race with the set_ldisc code path.
*/
- tty_unlock();
+ tty_lock_pair(tty, o_tty);
tty_ldisc_halt(tty);
tty_ldisc_flush_works(tty);
- tty_lock();
-
- mutex_lock(&tty->ldisc_mutex);
- /*
- * Now kill off the ldisc
- */
- tty_ldisc_close(tty, tty->ldisc);
- tty_ldisc_put(tty->ldisc);
- /* Force an oops if we mess this up */
- tty->ldisc = NULL;
-
- /* Ensure the next open requests the N_TTY ldisc */
- tty_set_termios_ldisc(tty, N_TTY);
- mutex_unlock(&tty->ldisc_mutex);
+ if (o_tty) {
+ tty_ldisc_halt(o_tty);
+ tty_ldisc_flush_works(o_tty);
+ }
/* This will need doing differently if we need to lock */
+ tty_ldisc_kill(tty);
+
if (o_tty)
- tty_ldisc_release(o_tty, NULL);
+ tty_ldisc_kill(o_tty);
+ tty_unlock_pair(tty, o_tty);
/* And the memory resources remaining (buffers, termios) will be
disposed of when the kref hits zero */
}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 9ff986c32a21..67feac9e6ebb 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,29 +4,70 @@
#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 */
+
+enum {
+ TTY_MUTEX_NORMAL,
+ TTY_MUTEX_NESTED,
+};
/*
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(void)
+
+static void __lockfunc tty_lock_nested(struct tty_struct *tty,
+ unsigned int subclass)
{
- 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_nested(&tty->legacy_mutex, subclass);
+}
+
+void __lockfunc tty_lock(struct tty_struct *tty)
+{
+ return tty_lock_nested(tty, TTY_MUTEX_NORMAL);
}
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_nested(tty2, TTY_MUTEX_NESTED);
+ } else {
+ if (tty2 && tty2 != tty)
+ tty_lock(tty2);
+ tty_lock_nested(tty, TTY_MUTEX_NESTED);
+ }
+}
+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..d7bdd8d0c23f 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -33,6 +33,70 @@ void tty_port_init(struct tty_port *port)
}
EXPORT_SYMBOL(tty_port_init);
+/**
+ * tty_port_link_device - link tty and tty_port
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ *
+ * Provide the tty layer wit ha link from a tty (specified by @index) to a
+ * tty_port (@port). Use this only if neither tty_port_register_device nor
+ * tty_port_install is used in the driver. If used, this has to be called before
+ * tty_register_driver.
+ */
+void tty_port_link_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index)
+{
+ if (WARN_ON(index >= driver->num))
+ return;
+ driver->ports[index] = port;
+}
+EXPORT_SYMBOL_GPL(tty_port_link_device);
+
+/**
+ * tty_port_register_device - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ *
+ * It is the same as tty_register_device except the provided @port is linked to
+ * a concrete tty specified by @index. Use this or tty_port_install (or both).
+ * Call tty_port_link_device as a last resort.
+ */
+struct device *tty_port_register_device(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device)
+{
+ tty_port_link_device(port, driver, index);
+ return tty_register_device(driver, index, device);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device);
+
+/**
+ * tty_port_register_device_attr - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ * @drvdata: Driver data to be set to device.
+ * @attr_grp: Attribute group to be set on device.
+ *
+ * It is the same as tty_register_device_attr except the provided @port is
+ * linked to a concrete tty specified by @index. Use this or tty_port_install
+ * (or both). Call tty_port_link_device as a last resort.
+ */
+struct device *tty_port_register_device_attr(struct tty_port *port,
+ struct tty_driver *driver, unsigned index,
+ struct device *device, void *drvdata,
+ const struct attribute_group **attr_grp)
+{
+ tty_port_link_device(port, driver, index);
+ return tty_register_device_attr(driver, index, device, drvdata,
+ attr_grp);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
+
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
@@ -230,7 +294,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;
@@ -246,7 +310,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
if (filp->f_flags & O_NONBLOCK) {
/* Indicate we are open */
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
@@ -270,7 +334,7 @@ int tty_port_block_til_ready(struct tty_port *port,
while (1) {
/* Indicate we are open */
- if (tty->termios->c_cflag & CBAUD)
+ if (tty->termios.c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
@@ -296,9 +360,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);
@@ -369,7 +433,7 @@ int tty_port_close_start(struct tty_port *port,
/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
hang up the line */
- if (tty->termios->c_cflag & HUPCL)
+ if (tty->termios.c_cflag & HUPCL)
tty_port_lower_dtr_rts(port);
/* Don't call port->drop for the last reference. Callers will want
@@ -413,6 +477,24 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
}
EXPORT_SYMBOL(tty_port_close);
+/**
+ * tty_port_install - generic tty->ops->install handler
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @tty: tty to be installed
+ *
+ * It is the same as tty_standard_install except the provided @port is linked
+ * to a concrete tty specified by @tty. Use this or tty_port_register_device
+ * (or both). Call tty_port_link_device as a last resort.
+ */
+int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+ struct tty_struct *tty)
+{
+ tty->port = port;
+ return tty_standard_install(driver, tty);
+}
+EXPORT_SYMBOL_GPL(tty_port_install);
+
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 48cc6f25cfd3..681765baef69 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
static struct input_handler kbd_handler;
static DEFINE_SPINLOCK(kbd_event_lock);
+static DEFINE_SPINLOCK(led_lock);
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static bool dead_key_next;
@@ -310,7 +311,7 @@ static void put_queue(struct vc_data *vc, int ch)
if (tty) {
tty_insert_flip_char(tty, ch, 0);
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
}
@@ -325,7 +326,7 @@ static void puts_queue(struct vc_data *vc, char *cp)
tty_insert_flip_char(tty, *cp, 0);
cp++;
}
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void applkey(struct vc_data *vc, int key, char mode)
@@ -586,7 +587,7 @@ static void fn_send_intr(struct vc_data *vc)
if (!tty)
return;
tty_insert_flip_char(tty, 0, TTY_BREAK);
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void fn_scroll_forw(struct vc_data *vc)
@@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
* or (ii) whatever pattern of lights people want to show using KDSETLED,
* or (iii) specified bits of specified words in kernel memory.
*/
-unsigned char getledstate(void)
+static unsigned char getledstate(void)
{
return ledstate;
}
@@ -992,7 +993,7 @@ unsigned char getledstate(void)
void setledstate(struct kbd_struct *kbd, unsigned int led)
{
unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
if (!(led & ~7)) {
ledioctl = led;
kbd->ledmode = LED_SHOW_IOCTL;
@@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
kbd->ledmode = LED_SHOW_FLAGS;
set_leds();
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
}
static inline unsigned char getleds(void)
@@ -1049,13 +1050,13 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
*/
int vt_get_leds(int console, int flag)
{
- unsigned long flags;
struct kbd_struct * kbd = kbd_table + console;
int ret;
+ unsigned long flags;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
ret = vc_kbd_led(kbd, flag);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
return ret;
}
@@ -1091,11 +1092,11 @@ void vt_set_led_state(int console, int leds)
void vt_kbd_con_start(int console)
{
struct kbd_struct * kbd = kbd_table + console;
-/* unsigned long flags; */
-/* spin_lock_irqsave(&kbd_event_lock, flags); */
+ unsigned long flags;
+ spin_lock_irqsave(&led_lock, flags);
clr_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
-/* spin_unlock_irqrestore(&kbd_event_lock, flags); */
+ spin_unlock_irqrestore(&led_lock, flags);
}
/**
@@ -1104,21 +1105,15 @@ void vt_kbd_con_start(int console)
*
* Handle console stop. This is a wrapper for the VT layer
* so that we can keep kbd knowledge internal
- *
- * FIXME: We eventually need to hold the kbd lock here to protect
- * the LED updating. We can't do it yet because fn_hold calls stop_tty
- * and start_tty under the kbd_event_lock, while normal tty paths
- * don't hold the lock. We probably need to split out an LED lock
- * but not during an -rc release!
*/
void vt_kbd_con_stop(int console)
{
struct kbd_struct * kbd = kbd_table + console;
-/* unsigned long flags; */
-/* spin_lock_irqsave(&kbd_event_lock, flags); */
+ unsigned long flags;
+ spin_lock_irqsave(&led_lock, flags);
set_vc_kbd_led(kbd, VC_SCROLLOCK);
set_leds();
-/* spin_unlock_irqrestore(&kbd_event_lock, flags); */
+ spin_unlock_irqrestore(&led_lock, flags);
}
/*
@@ -1130,7 +1125,12 @@ void vt_kbd_con_stop(int console)
*/
static void kbd_bh(unsigned long dummy)
{
- unsigned char leds = getleds();
+ unsigned char leds;
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_lock, flags);
+ leds = getleds();
+ spin_unlock_irqrestore(&led_lock, flags);
if (leds != ledstate) {
input_handler_for_each_handle(&kbd_handler, &leds,
@@ -2035,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
return -EPERM;
if (arg & ~0x77)
return -EINVAL;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
return 0;
/* the ioctls below only set the lights, not the functions */
@@ -2134,8 +2134,10 @@ void vt_reset_keyboard(int console)
clr_vc_kbd_mode(kbd, VC_CRLF);
kbd->lockstate = 0;
kbd->slockstate = 0;
+ spin_lock(&led_lock);
kbd->ledmode = LED_SHOW_FLAGS;
kbd->ledflagstate = kbd->default_ledflagstate;
+ spin_unlock(&led_lock);
/* do not do set_leds here because this causes an endless tasklet loop
when the keyboard hasn't been initialized yet */
spin_unlock_irqrestore(&kbd_event_lock, flags);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 84cbf298c094..999ca63afdef 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -537,45 +537,27 @@ void complement_pos(struct vc_data *vc, int offset)
static void insert_char(struct vc_data *vc, unsigned int nr)
{
- unsigned short *p, *q = (unsigned short *)vc->vc_pos;
+ unsigned short *p = (unsigned short *) vc->vc_pos;
- p = q + vc->vc_cols - nr - vc->vc_x;
- while (--p >= q)
- scr_writew(scr_readw(p), p + nr);
- scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+ scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
+ scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
- if (DO_UPDATE(vc)) {
- unsigned short oldattr = vc->vc_attr;
- vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
- vc->vc_cols - vc->vc_x - nr);
- vc->vc_attr = vc->vc_video_erase_char >> 8;
- while (nr--)
- vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
- vc->vc_attr = oldattr;
- }
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) p,
+ (vc->vc_cols - vc->vc_x) / 2 + 1);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
- unsigned int i = vc->vc_x;
- unsigned short *p = (unsigned short *)vc->vc_pos;
+ unsigned short *p = (unsigned short *) vc->vc_pos;
- while (++i <= vc->vc_cols - nr) {
- scr_writew(scr_readw(p+nr), p);
- p++;
- }
- scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+ scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
+ scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
+ nr * 2);
vc->vc_need_wrap = 0;
- if (DO_UPDATE(vc)) {
- unsigned short oldattr = vc->vc_attr;
- vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x - nr);
- vc->vc_attr = vc->vc_video_erase_char >> 8;
- while (nr--)
- vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
- vc->vc_cols - 1 - nr);
- vc->vc_attr = oldattr;
- }
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) p,
+ (vc->vc_cols - vc->vc_x) / 2);
}
static int softcursor_original;
@@ -1172,45 +1154,26 @@ static void csi_J(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of display */
count = (vc->vc_scr_end - vc->vc_pos) >> 1;
start = (unsigned short *)vc->vc_pos;
- if (DO_UPDATE(vc)) {
- /* do in two stages */
- vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x);
- vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
- vc->vc_rows - vc->vc_y - 1,
- vc->vc_cols);
- }
break;
case 1: /* erase from start to cursor */
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin;
- if (DO_UPDATE(vc)) {
- /* do in two stages */
- vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
- vc->vc_cols);
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- vc->vc_x + 1);
- }
break;
case 3: /* erase scroll-back buffer (and whole display) */
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
vc->vc_screenbuf_size >> 1);
set_origin(vc);
- if (CON_IS_VISIBLE(vc))
- update_screen(vc);
/* fall through */
case 2: /* erase whole display */
count = vc->vc_cols * vc->vc_rows;
start = (unsigned short *)vc->vc_origin;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, 0, 0,
- vc->vc_rows,
- vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0;
}
@@ -1223,29 +1186,22 @@ static void csi_K(struct vc_data *vc, int vpar)
case 0: /* erase from cursor to end of line */
count = vc->vc_cols - vc->vc_x;
start = (unsigned short *)vc->vc_pos;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
- vc->vc_cols - vc->vc_x);
break;
case 1: /* erase from start of line to cursor */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_x + 1;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- vc->vc_x + 1);
break;
case 2: /* erase whole line */
start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
count = vc->vc_cols;
- if (DO_UPDATE(vc))
- vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
- vc->vc_cols);
break;
default:
return;
}
scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0;
+ if (DO_UPDATE(vc))
+ do_update_region(vc, (unsigned long) start, count);
}
static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
@@ -1380,7 +1336,7 @@ static void respond_string(const char *p, struct tty_struct *tty)
tty_insert_flip_char(tty, *p, 0);
p++;
}
- con_schedule_flip(tty);
+ tty_schedule_flip(tty);
}
static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@ -2792,41 +2748,52 @@ static void con_flush_chars(struct tty_struct *tty)
/*
* Allocate the console screen memory.
*/
-static int con_open(struct tty_struct *tty, struct file *filp)
+static int con_install(struct tty_driver *driver, struct tty_struct *tty)
{
unsigned int currcons = tty->index;
- int ret = 0;
+ struct vc_data *vc;
+ int ret;
console_lock();
- if (tty->driver_data == NULL) {
- ret = vc_allocate(currcons);
- if (ret == 0) {
- struct vc_data *vc = vc_cons[currcons].d;
+ ret = vc_allocate(currcons);
+ if (ret)
+ goto unlock;
- /* Still being freed */
- if (vc->port.tty) {
- console_unlock();
- return -ERESTARTSYS;
- }
- tty->driver_data = vc;
- vc->port.tty = tty;
+ vc = vc_cons[currcons].d;
- if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
- tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
- }
- if (vc->vc_utf)
- tty->termios->c_iflag |= IUTF8;
- else
- tty->termios->c_iflag &= ~IUTF8;
- console_unlock();
- return ret;
- }
+ /* Still being freed */
+ if (vc->port.tty) {
+ ret = -ERESTARTSYS;
+ goto unlock;
}
+
+ ret = tty_port_install(&vc->port, driver, tty);
+ if (ret)
+ goto unlock;
+
+ tty->driver_data = vc;
+ vc->port.tty = tty;
+
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+ tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+ }
+ if (vc->vc_utf)
+ tty->termios.c_iflag |= IUTF8;
+ else
+ tty->termios.c_iflag &= ~IUTF8;
+unlock:
console_unlock();
return ret;
}
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+ /* everything done in install */
+ return 0;
+}
+
+
static void con_close(struct tty_struct *tty, struct file *filp)
{
/* Nothing to do - we defer to shutdown */
@@ -2839,7 +2806,6 @@ static void con_shutdown(struct tty_struct *tty)
console_lock();
vc->port.tty = NULL;
console_unlock();
- tty_shutdown(tty);
}
static int default_italic_color = 2; // green (ASCII)
@@ -2947,6 +2913,7 @@ static int __init con_init(void)
console_initcall(con_init);
static const struct tty_operations con_ops = {
+ .install = con_install,
.open = con_open,
.close = con_close,
.write = con_write,
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index c7a032a4f0c5..d214448b677e 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -78,8 +78,7 @@ static inline int ep_to_bit(struct ci13xxx *ci, int n)
}
/**
- * hw_device_state: enables/disables interrupts & starts/stops device (execute
- * without interruption)
+ * hw_device_state: enables/disables interrupts (execute without interruption)
* @dma: 0 => disable, !0 => enable and set dma engine
*
* This function returns an error code
@@ -91,9 +90,7 @@ static int hw_device_state(struct ci13xxx *ci, u32 dma)
/* interrupt, error, port change, reset, sleep/suspend */
hw_write(ci, OP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
- hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
} else {
- hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
hw_write(ci, OP_USBINTR, ~0, 0);
}
return 0;
@@ -774,10 +771,7 @@ __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;
+ int retval = 0;
list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
queue) {
@@ -1420,6 +1414,21 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
return -ENOTSUPP;
}
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnet
+ */
+static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
+{
+ struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
+
+ if (is_on)
+ hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+ else
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+
+ return 0;
+}
+
static int ci13xxx_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int ci13xxx_stop(struct usb_gadget *gadget,
@@ -1432,6 +1441,7 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci13xxx_vbus_session,
.wakeup = ci13xxx_wakeup,
+ .pullup = ci13xxx_pullup,
.vbus_draw = ci13xxx_vbus_draw,
.udc_start = ci13xxx_start,
.udc_stop = ci13xxx_stop,
@@ -1455,7 +1465,12 @@ static int init_eps(struct ci13xxx *ci)
mEp->ep.name = mEp->name;
mEp->ep.ops = &usb_ep_ops;
- mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+ /*
+ * for ep0: maxP defined in desc, for other
+ * eps, maxP is set by epautoconfig() called
+ * by gadget layer
+ */
+ mEp->ep.maxpacket = (unsigned short)~0;
INIT_LIST_HEAD(&mEp->qh.queue);
mEp->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL,
@@ -1475,6 +1490,7 @@ static int init_eps(struct ci13xxx *ci)
else
ci->ep0in = mEp;
+ mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
continue;
}
@@ -1484,6 +1500,17 @@ static int init_eps(struct ci13xxx *ci)
return retval;
}
+static void destroy_eps(struct ci13xxx *ci)
+{
+ int i;
+
+ for (i = 0; i < ci->hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+
+ dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+ }
+}
+
/**
* ci13xxx_start: register a gadget driver
* @gadget: our gadget
@@ -1691,7 +1718,7 @@ static int udc_start(struct ci13xxx *ci)
if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (ci->transceiver == NULL) {
retval = -ENODEV;
- goto free_pools;
+ goto destroy_eps;
}
}
@@ -1729,7 +1756,7 @@ static int udc_start(struct ci13xxx *ci)
remove_trans:
if (!IS_ERR_OR_NULL(ci->transceiver)) {
- otg_set_peripheral(ci->transceiver->otg, &ci->gadget);
+ otg_set_peripheral(ci->transceiver->otg, NULL);
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
@@ -1742,6 +1769,8 @@ unreg_device:
put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver);
+destroy_eps:
+ destroy_eps(ci);
free_pools:
dma_pool_destroy(ci->td_pool);
free_qh_pool:
@@ -1756,18 +1785,12 @@ free_qh_pool:
*/
static void udc_stop(struct ci13xxx *ci)
{
- int i;
-
if (ci == NULL)
return;
usb_del_gadget_udc(&ci->gadget);
- for (i = 0; i < ci->hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
-
- dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
- }
+ destroy_eps(ci);
dma_pool_destroy(ci->td_pool);
dma_pool_destroy(ci->qh_pool);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index f763ed7ba91e..ff7b5a8d501c 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -826,7 +826,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
struct usb_cdc_line_coding newline;
int newctrl = acm->ctrlout;
@@ -1299,7 +1299,8 @@ skip_countries:
usb_set_intfdata(data_interface, acm);
usb_get_intf(control_interface);
- tty_register_device(acm_tty_driver, minor, &control_interface->dev);
+ tty_port_register_device(&acm->port, acm_tty_driver, minor,
+ &control_interface->dev);
return 0;
alloc_fail7:
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 65a55abb791f..5f0cb417b736 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -109,12 +109,14 @@ static struct usb_driver wdm_driver;
/* return intfdata if we own the interface, else look up intf in the list */
static struct wdm_device *wdm_find_device(struct usb_interface *intf)
{
- struct wdm_device *desc = NULL;
+ struct wdm_device *desc;
spin_lock(&wdm_device_list_lock);
list_for_each_entry(desc, &wdm_device_list, device_list)
if (desc->intf == intf)
- break;
+ goto found;
+ desc = NULL;
+found:
spin_unlock(&wdm_device_list_lock);
return desc;
@@ -122,12 +124,14 @@ static struct wdm_device *wdm_find_device(struct usb_interface *intf)
static struct wdm_device *wdm_find_device_by_minor(int minor)
{
- struct wdm_device *desc = NULL;
+ struct wdm_device *desc;
spin_lock(&wdm_device_list_lock);
list_for_each_entry(desc, &wdm_device_list, device_list)
if (desc->intf->minor == minor)
- break;
+ goto found;
+ desc = NULL;
+found:
spin_unlock(&wdm_device_list_lock);
return desc;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f15501f4c585..e77a8e8eaa23 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -71,6 +71,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x04b4, 0x0526), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
+ /* Microchip Joss Optical infrared touchboard device */
+ { USB_DEVICE(0x04d8, 0x000c), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
/* Samsung Android phone modem - ID conflict with SPH-I500 */
{ USB_DEVICE(0x04e8, 0x6601), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c34452a7304f..a68ff53124dc 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -436,16 +436,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
- dwc->xhci_resources[1] = *res;
+ dwc->xhci_resources[1].start = res->start;
+ dwc->xhci_resources[1].end = res->end;
+ dwc->xhci_resources[1].flags = res->flags;
+ dwc->xhci_resources[1].name = res->name;
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].start = res->start;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
DWC3_XHCI_REGS_END;
+ dwc->xhci_resources[0].flags = res->flags;
+ dwc->xhci_resources[0].name = res->name;
/*
* Request memory region but exclude xHCI regs,
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 9b94886b66e5..e4d5ca86b9da 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -720,7 +720,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
transferred = min_t(u32, ur->length,
transfer_size - length);
memcpy(ur->buf, dwc->ep0_bounce, transferred);
- dwc->ep0_bounced = false;
} else {
transferred = ur->length - length;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 58fdfad96b4d..c2813c2b005a 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -263,8 +263,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS)
req->request.status = status;
- usb_gadget_unmap_request(&dwc->gadget, &req->request,
- req->direction);
+ if (dwc->ep0_bounced && dep->number == 0)
+ dwc->ep0_bounced = false;
+ else
+ usb_gadget_unmap_request(&dwc->gadget, &req->request,
+ req->direction);
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
@@ -1026,6 +1029,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
dep->name);
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
}
@@ -1089,6 +1093,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
int ret;
+ /*
+ * If xfernotready is already elapsed and it is a case
+ * of isoc transfer, then issue END TRANSFER, so that
+ * you can receive xfernotready again and can have
+ * notion of current microframe.
+ */
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ dwc3_stop_active_transfer(dwc, dep->number);
+ return 0;
+ }
+
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index c9e66dfb02e6..1e35963bd4ed 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -475,8 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
unsigned long flags;
if (!_ep || !ep
- || !desc || ep->ep.desc
- || _ep->name == ep0name
+ || !desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| (maxpacket = usb_endpoint_maxp(desc)) == 0
|| maxpacket > ep->maxpacket) {
@@ -530,7 +529,6 @@ ok:
tmp |= AT91_UDP_EPEDS;
__raw_writel(tmp, ep->creg);
- ep->ep.desc = desc;
ep->ep.maxpacket = maxpacket;
/*
@@ -1635,7 +1633,6 @@ static int at91_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
- dev_set_drvdata(&udc->gadget.dev, &driver->driver);
udc->enabled = 1;
udc->selfpowered = 1;
@@ -1656,7 +1653,6 @@ static int at91_stop(struct usb_gadget *gadget,
spin_unlock_irqrestore(&udc->lock, flags);
udc->gadget.dev.driver = NULL;
- dev_set_drvdata(&udc->gadget.dev, NULL);
udc->driver = NULL;
DBG("unbound from %s\n", driver->driver.name);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index b799106027ad..afdbb1cbf5d9 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1916,6 +1916,27 @@ done:
return retval;
}
+/* usb 3.0 root hub device descriptor */
+struct {
+ struct usb_bos_descriptor bos;
+ struct usb_ss_cap_descriptor ss_cap;
+} __packed usb3_bos_desc = {
+
+ .bos = {
+ .bLength = USB_DT_BOS_SIZE,
+ .bDescriptorType = USB_DT_BOS,
+ .wTotalLength = cpu_to_le16(sizeof(usb3_bos_desc)),
+ .bNumDeviceCaps = 1,
+ },
+ .ss_cap = {
+ .bLength = USB_DT_USB_SS_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_SS_CAP_TYPE,
+ .wSpeedSupported = cpu_to_le16(USB_5GBPS_OPERATION),
+ .bFunctionalitySupport = ilog2(USB_5GBPS_OPERATION),
+ },
+};
+
static inline void
ss_hub_descriptor(struct usb_hub_descriptor *desc)
{
@@ -2006,6 +2027,18 @@ static int dummy_hub_control(
else
hub_descriptor((struct usb_hub_descriptor *) buf);
break;
+
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+
+ if ((wValue >> 8) != USB_DT_BOS)
+ goto error;
+
+ memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc));
+ retval = sizeof(usb3_bos_desc);
+ break;
+
case GetHubStatus:
*(__le32 *) buf = cpu_to_le32(0);
break;
@@ -2503,10 +2536,8 @@ static int dummy_hcd_probe(struct platform_device *pdev)
hs_hcd->has_tt = 1;
retval = usb_add_hcd(hs_hcd, 0, 0);
- if (retval != 0) {
- usb_put_hcd(hs_hcd);
- return retval;
- }
+ if (retval)
+ goto put_usb2_hcd;
if (mod_data.is_super_speed) {
ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
@@ -2525,6 +2556,8 @@ static int dummy_hcd_probe(struct platform_device *pdev)
put_usb3_hcd:
usb_put_hcd(ss_hcd);
dealloc_usb2_hcd:
+ usb_remove_hcd(hs_hcd);
+put_usb2_hcd:
usb_put_hcd(hs_hcd);
the_controller.hs_hcd = the_controller.ss_hcd = NULL;
return retval;
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 8adc79d1b402..829aba75a6df 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -34,11 +34,15 @@
/* Debugging ****************************************************************/
#ifdef VERBOSE_DEBUG
+#ifndef pr_vdebug
# define pr_vdebug pr_debug
+#endif /* pr_vdebug */
# define ffs_dump_mem(prefix, ptr, len) \
print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
#else
+#ifndef pr_vdebug
# define pr_vdebug(...) do { } while (0)
+#endif /* pr_vdebug */
# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
#endif /* VERBOSE_DEBUG */
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index b13e0bb5f5b8..0bb617e1dda2 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -3599,6 +3599,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
if (hsotg->num_of_eps == 0) {
dev_err(dev, "wrong number of EPs (zero)\n");
+ ret = -EINVAL;
goto err_supplies;
}
@@ -3606,6 +3607,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!eps) {
dev_err(dev, "cannot get memory\n");
+ ret = -ENOMEM;
goto err_supplies;
}
@@ -3622,6 +3624,7 @@ 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");
+ ret = -ENOMEM;
goto err_ep_mem;
}
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 5b3f5fffea92..f1739526820f 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -132,11 +132,15 @@ static unsigned n_ports;
#ifdef VERBOSE_DEBUG
+#ifndef pr_vdebug
#define pr_vdebug(fmt, arg...) \
pr_debug(fmt, ##arg)
+#endif /* pr_vdebug */
#else
+#ifndef pr_vdebig
#define pr_vdebug(fmt, arg...) \
({ if (0) pr_debug(fmt, ##arg); })
+#endif /* pr_vdebug */
#endif
/*-------------------------------------------------------------------------*/
@@ -1129,7 +1133,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count)
for (i = 0; i < count; i++) {
struct device *tty_dev;
- tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+ tty_dev = tty_port_register_device(&ports[i].port->port,
+ gs_tty_driver, i, &g->dev);
if (IS_ERR(tty_dev))
pr_warning("%s: no classdev for port %d, err %ld\n",
__func__, i, PTR_ERR(tty_dev));
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 9bc39ca460c8..4b66374bdc8e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -128,9 +128,17 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
else {
qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list);
- /* first qtd may already be partially processed */
- if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current)
+ /*
+ * first qtd may already be partially processed.
+ * If we come here during unlink, the QH overlay region
+ * might have reference to the just unlinked qtd. The
+ * qtd is updated in qh_completions(). Update the QH
+ * overlay here.
+ */
+ if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) {
+ qh->hw->hw_qtd_next = qtd->hw_next;
qtd = NULL;
+ }
}
if (qtd)
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index a665b3eaa746..aaa8d2bce217 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -570,6 +570,16 @@ static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev)
if (pdata) {
at91_for_each_port(i) {
+ /*
+ * do not configure PIO if not in relation with
+ * real USB port on board
+ */
+ if (i >= pdata->ports) {
+ pdata->vbus_pin[i] = -EINVAL;
+ pdata->overcurrent_pin[i] = -EINVAL;
+ break;
+ }
+
if (!gpio_is_valid(pdata->vbus_pin[i]))
continue;
gpio = pdata->vbus_pin[i];
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index c5e9e4a76f14..966d1484ee79 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -75,7 +75,9 @@
#define NB_PIF0_PWRDOWN_1 0x01100013
#define USB_INTEL_XUSB2PR 0xD0
+#define USB_INTEL_USB2PRM 0xD4
#define USB_INTEL_USB3_PSSEN 0xD8
+#define USB_INTEL_USB3PRM 0xDC
static struct amd_chipset_info {
struct pci_dev *nb_dev;
@@ -772,10 +774,18 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
return;
}
- ports_available = 0xffffffff;
+ /* Read USB3PRM, the USB 3.0 Port Routing Mask Register
+ * Indicate the ports that can be changed from OS.
+ */
+ pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM,
+ &ports_available);
+
+ dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n",
+ ports_available);
+
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
- * Register, to turn on SuperSpeed terminations for all
- * available ports.
+ * Register, to turn on SuperSpeed terminations for the
+ * switchable ports.
*/
pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
cpu_to_le32(ports_available));
@@ -785,7 +795,16 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
"under xHCI: 0x%x\n", ports_available);
- ports_available = 0xffffffff;
+ /* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register
+ * Indicate the USB 2.0 ports to be controlled by the xHCI host.
+ */
+
+ pci_read_config_dword(xhci_pdev, USB_INTEL_USB2PRM,
+ &ports_available);
+
+ dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n",
+ ports_available);
+
/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to
* switch the USB 2.0 power and data lines over to the xHCI
* host.
@@ -822,12 +841,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
void __iomem *op_reg_base;
u32 val;
int timeout;
+ int len = pci_resource_len(pdev, 0);
if (!mmio_resource_enabled(pdev, 0))
return;
- base = ioremap_nocache(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ base = ioremap_nocache(pci_resource_start(pdev, 0), len);
if (base == NULL)
return;
@@ -837,9 +856,17 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
*/
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
do {
+ if ((ext_cap_offset + sizeof(val)) > len) {
+ /* We're reading garbage from the controller */
+ dev_warn(&pdev->dev,
+ "xHCI controller failing to respond");
+ return;
+ }
+
if (!ext_cap_offset)
/* We've reached the end of the extended capabilities */
goto hc_init;
+
val = readl(base + ext_cap_offset);
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
break;
@@ -870,9 +897,10 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
/* Disable any BIOS SMIs and clear all SMI events*/
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+hc_init:
if (usb_is_intel_switchable_xhci(pdev))
usb_enable_xhci_ports(pdev);
-hc_init:
+
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
/* Wait for the host controller to be ready before writing any
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index ef004a5de20f..7f69a39163ce 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -15,6 +15,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
static inline void usb_amd_quirk_pll_disable(void) {}
static inline void usb_amd_quirk_pll_enable(void) {}
static inline void usb_amd_dev_put(void) {}
+static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
#endif /* CONFIG_PCI */
#endif /* __LINUX_USB_PCI_QUIRKS_H */
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 74bfc868b7ad..d5eb357aa5c4 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -493,11 +493,48 @@ static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
* when this bit is set.
*/
pls |= USB_PORT_STAT_CONNECTION;
+ } else {
+ /*
+ * If CAS bit isn't set but the Port is already at
+ * Compliance Mode, fake a connection so the USB core
+ * notices the Compliance state and resets the port.
+ * This resolves an issue generated by the SN65LVPE502CP
+ * in which sometimes the port enters compliance mode
+ * caused by a delay on the host-device negotiation.
+ */
+ if (pls == USB_SS_PORT_LS_COMP_MOD)
+ pls |= USB_PORT_STAT_CONNECTION;
}
+
/* update status field */
*status |= pls;
}
+/*
+ * Function for Compliance Mode Quirk.
+ *
+ * This Function verifies if all xhc USB3 ports have entered U0, if so,
+ * the compliance mode timer is deleted. A port won't enter
+ * compliance mode if it has previously entered U0.
+ */
+void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)
+{
+ u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);
+ bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0);
+
+ if (!(xhci->quirks & XHCI_COMP_MODE_QUIRK))
+ return;
+
+ if ((xhci->port_status_u0 != all_ports_seen_u0) && port_in_u0) {
+ xhci->port_status_u0 |= 1 << wIndex;
+ if (xhci->port_status_u0 == all_ports_seen_u0) {
+ del_timer_sync(&xhci->comp_mode_recovery_timer);
+ xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n");
+ xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n");
+ }
+ }
+}
+
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@@ -651,6 +688,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/* Update Port Link State for super speed ports*/
if (hcd->speed == HCD_USB3) {
xhci_hub_report_link_state(&status, temp);
+ /*
+ * Verify if all USB3 Ports Have entered U0 already.
+ * Delete Compliance Mode Timer if so.
+ */
+ xhci_del_comp_mod_timer(xhci, temp, wIndex);
}
if (bus_state->port_c_suspend & (1 << wIndex))
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 689bc18b051d..df90fe51b4aa 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -118,7 +118,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_hcd;
}
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_dbg(&pdev->dev, "error mapping memory\n");
ret = -EFAULT;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c59d5b5b6c7d..6ece0ed288d4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
+#include <linux/dmi.h>
#include "xhci.h"
@@ -398,6 +399,95 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
#endif
+static void compliance_mode_recovery(unsigned long arg)
+{
+ struct xhci_hcd *xhci;
+ struct usb_hcd *hcd;
+ u32 temp;
+ int i;
+
+ xhci = (struct xhci_hcd *)arg;
+
+ for (i = 0; i < xhci->num_usb3_ports; i++) {
+ temp = xhci_readl(xhci, xhci->usb3_ports[i]);
+ if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
+ /*
+ * Compliance Mode Detected. Letting USB Core
+ * handle the Warm Reset
+ */
+ xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n",
+ i + 1);
+ xhci_dbg(xhci, "Attempting Recovery routine!\n");
+ hcd = xhci->shared_hcd;
+
+ if (hcd->state == HC_STATE_SUSPENDED)
+ usb_hcd_resume_root_hub(hcd);
+
+ usb_hcd_poll_rh_status(hcd);
+ }
+ }
+
+ if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1))
+ mod_timer(&xhci->comp_mode_recovery_timer,
+ jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
+}
+
+/*
+ * Quirk to work around issue generated by the SN65LVPE502CP USB3.0 re-driver
+ * that causes ports behind that hardware to enter compliance mode sometimes.
+ * The quirk creates a timer that polls every 2 seconds the link state of
+ * each host controller's port and recovers it by issuing a Warm reset
+ * if Compliance mode is detected, otherwise the port will become "dead" (no
+ * device connections or disconnections will be detected anymore). Becasue no
+ * status event is generated when entering compliance mode (per xhci spec),
+ * this quirk is needed on systems that have the failing hardware installed.
+ */
+static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
+{
+ xhci->port_status_u0 = 0;
+ init_timer(&xhci->comp_mode_recovery_timer);
+
+ xhci->comp_mode_recovery_timer.data = (unsigned long) xhci;
+ xhci->comp_mode_recovery_timer.function = compliance_mode_recovery;
+ xhci->comp_mode_recovery_timer.expires = jiffies +
+ msecs_to_jiffies(COMP_MODE_RCVRY_MSECS);
+
+ set_timer_slack(&xhci->comp_mode_recovery_timer,
+ msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
+ add_timer(&xhci->comp_mode_recovery_timer);
+ xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n");
+}
+
+/*
+ * This function identifies the systems that have installed the SN65LVPE502CP
+ * USB3.0 re-driver and that need the Compliance Mode Quirk.
+ * Systems:
+ * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820
+ */
+static bool compliance_mode_recovery_timer_quirk_check(void)
+{
+ const char *dmi_product_name, *dmi_sys_vendor;
+
+ dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME);
+ dmi_sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+
+ if (!(strstr(dmi_sys_vendor, "Hewlett-Packard")))
+ return false;
+
+ if (strstr(dmi_product_name, "Z420") ||
+ strstr(dmi_product_name, "Z620") ||
+ strstr(dmi_product_name, "Z820"))
+ return true;
+
+ return false;
+}
+
+static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
+{
+ return (xhci->port_status_u0 == ((1 << xhci->num_usb3_ports)-1));
+}
+
+
/*
* Initialize memory for HCD and xHC (one-time init).
*
@@ -421,6 +511,12 @@ int xhci_init(struct usb_hcd *hcd)
retval = xhci_mem_init(xhci, GFP_KERNEL);
xhci_dbg(xhci, "Finished xhci_init\n");
+ /* Initializing Compliance Mode Recovery Data If Needed */
+ if (compliance_mode_recovery_timer_quirk_check()) {
+ xhci->quirks |= XHCI_COMP_MODE_QUIRK;
+ compliance_mode_recovery_timer_init(xhci);
+ }
+
return retval;
}
@@ -629,6 +725,11 @@ void xhci_stop(struct usb_hcd *hcd)
del_timer_sync(&xhci->event_ring_timer);
#endif
+ /* Deleting Compliance Mode Recovery Timer */
+ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
+ (!(xhci_all_ports_seen_u0(xhci))))
+ del_timer_sync(&xhci->comp_mode_recovery_timer);
+
if (xhci->quirks & XHCI_AMD_PLL_FIX)
usb_amd_dev_put();
@@ -659,7 +760,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
+ if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
spin_lock_irq(&xhci->lock);
@@ -806,6 +907,16 @@ int xhci_suspend(struct xhci_hcd *xhci)
}
spin_unlock_irq(&xhci->lock);
+ /*
+ * Deleting Compliance Mode Recovery Timer because the xHCI Host
+ * is about to be suspended.
+ */
+ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
+ (!(xhci_all_ports_seen_u0(xhci)))) {
+ del_timer_sync(&xhci->comp_mode_recovery_timer);
+ xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n");
+ }
+
/* step 5: remove core well power */
/* synchronize irq when using MSI-X */
xhci_msix_sync_irqs(xhci);
@@ -938,6 +1049,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
usb_hcd_resume_root_hub(hcd);
usb_hcd_resume_root_hub(xhci->shared_hcd);
}
+
+ /*
+ * If system is subject to the Quirk, Compliance Mode Timer needs to
+ * be re-initialized Always after a system resume. Ports are subject
+ * to suffer the Compliance Mode issue again. It doesn't matter if
+ * ports have entered previously to U0 before system's suspension.
+ */
+ if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
+ compliance_mode_recovery_timer_init(xhci);
+
return retval;
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c713256297ac..1a05908c6673 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1495,6 +1495,7 @@ struct xhci_hcd {
#define XHCI_LPM_SUPPORT (1 << 11)
#define XHCI_INTEL_HOST (1 << 12)
#define XHCI_SPURIOUS_REBOOT (1 << 13)
+#define XHCI_COMP_MODE_QUIRK (1 << 14)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1511,6 +1512,11 @@ struct xhci_hcd {
unsigned sw_lpm_support:1;
/* support xHCI 1.0 spec USB2 hardware LPM */
unsigned hw_lpm_support:1;
+ /* Compliance Mode Recovery Data */
+ struct timer_list comp_mode_recovery_timer;
+ u32 port_status_u0;
+/* Compliance Mode Timer Triggered every 2 seconds */
+#define COMP_MODE_RCVRY_MSECS 2000
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 4bb717d0bd41..1ae378d5fc6f 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2049,7 +2049,7 @@ static int musb_urb_enqueue(
* we only have work to do in the former case.
*/
spin_lock_irqsave(&musb->lock, flags);
- if (hep->hcpriv) {
+ if (hep->hcpriv || !next_urb(qh)) {
/* some concurrent activity submitted another urb to hep...
* odd, rare, error prone, but legal.
*/
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 57a608584e16..c1be687e00ec 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -388,7 +388,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)
struct platform_device *pdev = to_platform_device(dev);
int irq = platform_get_irq_byname(pdev, "dma");
- if (irq == 0) {
+ if (irq <= 0) {
dev_err(dev, "No DMA interrupt line!\n");
return NULL;
}
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 1a1bd9cf40c5..341625442377 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1215,7 +1215,7 @@ static int __devinit tusb_probe(struct platform_device *pdev)
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err1;
+ goto err2;
}
return 0;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index ecd173032fd4..143c4e9e1be4 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -818,7 +818,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_is_dcp(pipe))
goto usbhsf_pio_prepare_push;
- if (len % 4) /* 32bit alignment */
+ if (len & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_push;
if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
@@ -905,7 +905,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
/* use PIO if packet is less than pio_dma_border */
len = usbhsf_fifo_rcv_len(priv, fifo);
len = min(pkt->length - pkt->actual, len);
- if (len % 4) /* 32bit alignment */
+ if (len & 0x7) /* 8byte alignment */
goto usbhsf_pio_prepare_pop_unselect;
if (len < usbhs_get_dparam(priv, pio_dma_border))
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index f8ce97d8b0ad..3b98fb733362 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -215,7 +215,7 @@ static void ark3116_release(struct usb_serial *serial)
static void ark3116_init_termios(struct tty_struct *tty)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
*termios = tty_std_termios;
termios->c_cflag = B9600 | CS8
| CREAD | HUPCL | CLOCAL;
@@ -229,7 +229,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
{
struct usb_serial *serial = port->serial;
struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
int bps = tty_get_baud_rate(tty);
int quot;
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 6b7365632951..a46df73ee96e 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -307,7 +307,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
unsigned long control_state;
int bad_flow_control;
speed_t baud;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
iflag = termios->c_iflag;
cflag = termios->c_cflag;
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index b9cca6dcde07..9a564286bfd7 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -165,8 +165,8 @@ static int usb_console_setup(struct console *co, char *options)
}
if (serial->type->set_termios) {
- tty->termios->c_cflag = cflag;
- tty_termios_encode_baud_rate(tty->termios, baud, baud);
+ tty->termios.c_cflag = cflag;
+ tty_termios_encode_baud_rate(&tty->termios, baud, baud);
memset(&dummy, 0, sizeof(struct ktermios));
serial->type->set_termios(tty, port, &dummy);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 1e71079ce33b..ba5e07e188a0 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -469,7 +469,7 @@ static void cp210x_get_termios(struct tty_struct *tty,
if (tty) {
cp210x_get_termios_port(tty->driver_data,
- &tty->termios->c_cflag, &baud);
+ &tty->termios.c_cflag, &baud);
tty_encode_baud_rate(tty, baud, baud);
}
@@ -631,7 +631,7 @@ static void cp210x_change_speed(struct tty_struct *tty,
{
u32 baud;
- baud = tty->termios->c_ospeed;
+ baud = tty->termios.c_ospeed;
/* This maps the requested rate to a rate valid on cp2102 or cp2103,
* or to an arbitrary rate in [1M,2M].
@@ -665,10 +665,10 @@ static void cp210x_set_termios(struct tty_struct *tty,
if (!tty)
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
- if (tty->termios->c_ospeed != old_termios->c_ospeed)
+ if (tty->termios.c_ospeed != old_termios->c_ospeed)
cp210x_change_speed(tty, port, old_termios);
/* If the number of data bits is to be updated */
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index b78c34eb5d3f..be34f153e566 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -922,38 +922,38 @@ static void cypress_set_termios(struct tty_struct *tty,
early enough */
if (!priv->termios_initialized) {
if (priv->chiptype == CT_EARTHMATE) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 4800;
- tty->termios->c_ospeed = 4800;
+ tty->termios.c_ispeed = 4800;
+ tty->termios.c_ospeed = 4800;
} else if (priv->chiptype == CT_CYPHIDCOM) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
} else if (priv->chiptype == CT_CA42V2) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
CLOCAL;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
}
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
/* Unsupported features need clearing */
- tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+ tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS);
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* check if there are new settings */
if (old_termios) {
spin_lock_irqsave(&priv->lock, flags);
- priv->tmp_termios = *(tty->termios);
+ priv->tmp_termios = tty->termios;
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -1021,7 +1021,7 @@ static void cypress_set_termios(struct tty_struct *tty,
"4800bps.");
/* define custom termios settings for NMEA protocol */
- tty->termios->c_iflag /* input modes - */
+ tty->termios.c_iflag /* input modes - */
&= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
| PARMRK /* disable mark parity errors */
@@ -1031,10 +1031,10 @@ static void cypress_set_termios(struct tty_struct *tty,
| ICRNL /* disable translate CR to NL */
| IXON); /* disable enable XON/XOFF flow control */
- tty->termios->c_oflag /* output modes */
+ tty->termios.c_oflag /* output modes */
&= ~OPOST; /* disable postprocess output char */
- tty->termios->c_lflag /* line discipline modes */
+ tty->termios.c_lflag /* line discipline modes */
&= ~(ECHO /* disable echo input characters */
| ECHONL /* disable echo new line */
| ICANON /* disable erase, kill, werase, and rprnt
@@ -1200,7 +1200,7 @@ static void cypress_read_int_callback(struct urb *urb)
/* hangup, as defined in acm.c... this might be a bad place for it
* though */
- if (tty && !(tty->termios->c_cflag & CLOCAL) &&
+ if (tty && !(tty->termios.c_cflag & CLOCAL) &&
!(priv->current_status & UART_CD)) {
dbg("%s - calling hangup", __func__);
tty_hangup(tty);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index b5cd838093ef..afd9d2ec577b 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -687,8 +687,8 @@ static void digi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned int iflag = tty->termios->c_iflag;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int iflag = tty->termios.c_iflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned char buf[32];
@@ -709,7 +709,7 @@ static void digi_set_termios(struct tty_struct *tty,
/* don't set RTS if using hardware flow control */
/* and throttling input */
modem_signals = TIOCM_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios.c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
modem_signals |= TIOCM_RTS;
digi_set_modem_signals(port, modem_signals, 1);
@@ -748,7 +748,7 @@ static void digi_set_termios(struct tty_struct *tty,
}
}
/* set parity */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
if (cflag&PARENB) {
@@ -1124,8 +1124,8 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set termios settings */
if (tty) {
- not_termios.c_cflag = ~tty->termios->c_cflag;
- not_termios.c_iflag = ~tty->termios->c_iflag;
+ not_termios.c_cflag = ~tty->termios.c_cflag;
+ not_termios.c_iflag = ~tty->termios.c_iflag;
digi_set_termios(tty, port, &not_termios);
}
return 0;
@@ -1500,7 +1500,7 @@ static int digi_read_oob_callback(struct urb *urb)
rts = 0;
if (tty)
- rts = tty->termios->c_cflag & CRTSCTS;
+ rts = tty->termios.c_cflag & CRTSCTS;
if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
spin_lock(&priv->dp_port_lock);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index cdf61dd07318..34e86383090a 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -87,7 +87,7 @@ static int empeg_startup(struct usb_serial *serial)
static void empeg_init_termios(struct tty_struct *tty)
{
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
/*
* The empeg-car player wants these particular tty settings.
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 499b15fd82f1..79451ee12ca0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -173,10 +173,11 @@ static void f81232_set_termios(struct tty_struct *tty,
/* FIXME - Stubbed out for now */
/* Don't change anything if nothing has changed */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
/* Do the real work here... */
+ tty_termios_copy_hw(&tty->termios, old_termios);
}
static int f81232_tiocmget(struct tty_struct *tty)
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 5620db6469e5..0c8d1c226273 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -704,6 +704,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
@@ -804,13 +805,32 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
+ USB_CLASS_VENDOR_SPEC,
+ USB_SUBCLASS_VENDOR_SPEC, 0x00) },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.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(FTDI_VID, PI_C865_PID) },
+ { USB_DEVICE(FTDI_VID, PI_C857_PID) },
+ { USB_DEVICE(PI_VID, PI_C866_PID) },
+ { USB_DEVICE(PI_VID, PI_C663_PID) },
+ { USB_DEVICE(PI_VID, PI_C725_PID) },
+ { USB_DEVICE(PI_VID, PI_E517_PID) },
+ { USB_DEVICE(PI_VID, PI_C863_PID) },
{ USB_DEVICE(PI_VID, PI_E861_PID) },
+ { USB_DEVICE(PI_VID, PI_C867_PID) },
+ { USB_DEVICE(PI_VID, PI_E609_PID) },
+ { USB_DEVICE(PI_VID, PI_E709_PID) },
+ { USB_DEVICE(PI_VID, PI_100F_PID) },
+ { USB_DEVICE(PI_VID, PI_1011_PID) },
+ { USB_DEVICE(PI_VID, PI_1012_PID) },
+ { USB_DEVICE(PI_VID, PI_1013_PID) },
+ { USB_DEVICE(PI_VID, PI_1014_PID) },
+ { USB_DEVICE(PI_VID, PI_1015_PID) },
+ { USB_DEVICE(PI_VID, PI_1016_PID) },
{ USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
@@ -2082,7 +2102,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
{
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
__u16 urb_value; /* will hold the new flags */
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 5dd96ca6c380..41fe5826100c 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -75,6 +75,9 @@
#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
#define FTDI_OPENDCC_GBM_PID 0xBFDC
+/* NZR SEM 16+ USB (http://www.nzr.de) */
+#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */
+
/*
* RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com)
*/
@@ -539,7 +542,10 @@
/*
* Microchip Technology, Inc.
*
- * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by:
+ * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are
+ * used by single function CDC ACM class based firmware demo
+ * applications. The VID/PID has also been used in firmware
+ * emulating FTDI serial chips by:
* Hornby Elite - Digital Command Control Console
* http://www.hornby.com/hornby-dcc/controllers/
*/
@@ -791,8 +797,27 @@
* Physik Instrumente
* http://www.physikinstrumente.com/en/products/
*/
+/* These two devices use the VID of FTDI */
+#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */
+#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */
+
#define PI_VID 0x1a72 /* Vendor ID */
-#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */
+#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */
+#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */
+#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */
+#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */
+#define PI_C863_PID 0x1007 /* PI C-863 */
+#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */
+#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */
+#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */
+#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */
+#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */
+#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */
+#define PI_1012_PID 0x1012 /* PI Motion Controller */
+#define PI_1013_PID 0x1013 /* PI Motion Controller */
+#define PI_1014_PID 0x1014 /* PI Device */
+#define PI_1015_PID 0x1015 /* PI Device */
+#define PI_1016_PID 0x1016 /* PI Digital Servo Module */
/*
* Kondo Kagaku Co.Ltd.
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index e1f5ccd1e8f8..f435575c4e6e 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1458,7 +1458,7 @@ static void edge_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
edge_port->shadowMCR &= ~MCR_RTS;
status = send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
@@ -1497,7 +1497,7 @@ static void edge_unthrottle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
edge_port->shadowMCR |= MCR_RTS;
send_cmd_write_uart_register(edge_port, MCR,
edge_port->shadowMCR);
@@ -1516,9 +1516,9 @@ static void edge_set_termios(struct tty_struct *tty,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int cflag;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, tty->termios->c_iflag);
+ tty->termios.c_cflag, tty->termios.c_iflag);
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
@@ -1987,7 +1987,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
tty = tty_port_tty_get(&edge_port->port->port);
if (tty) {
change_port_settings(tty,
- edge_port, tty->termios);
+ edge_port, &tty->termios);
tty_kref_put(tty);
}
@@ -2570,7 +2570,7 @@ static void change_port_settings(struct tty_struct *tty,
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
switch (cflag & CSIZE) {
case CS5:
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 3936904c6419..765978ae752e 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1870,7 +1870,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set up the port settings */
if (tty)
- edge_set_termios(tty, port, tty->termios);
+ edge_set_termios(tty, port, &tty->termios);
/* open up the port */
@@ -2272,13 +2272,13 @@ static void change_port_settings(struct tty_struct *tty,
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
- *tty->termios = *old_termios;
+ tty->termios = *old_termios;
dev_err(&edge_port->port->dev, "%s - out of memory\n",
__func__);
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
config->wFlags = 0;
@@ -2362,7 +2362,7 @@ static void change_port_settings(struct tty_struct *tty,
} else
dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
/* Round the baud rate */
baud = tty_get_baud_rate(tty);
@@ -2408,10 +2408,10 @@ static void edge_set_termios(struct tty_struct *tty,
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned int cflag;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, tty->termios->c_iflag);
+ tty->termios.c_cflag, tty->termios.c_iflag);
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, old_termios->c_iflag);
dbg("%s - port %d", __func__, port->number);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index fc09414c960f..5a96692b12a2 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -381,7 +381,7 @@ static void ir_set_termios(struct tty_struct *tty,
ir_xbof = ir_xbof_change(xbof) ;
/* Only speed changes are supported */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
tty_encode_baud_rate(tty, baud, baud);
/*
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 22b1eb5040b7..bf3864045c18 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -921,7 +921,7 @@ static void iuu_set_termios(struct tty_struct *tty,
{
const u32 supported_mask = CMSPAR|PARENB|PARODD;
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
int status;
u32 actual;
u32 parity;
@@ -930,7 +930,7 @@ static void iuu_set_termios(struct tty_struct *tty,
u32 newval = cflag & supported_mask;
/* Just use the ospeed. ispeed should be the same. */
- baud = tty->termios->c_ospeed;
+ baud = tty->termios.c_ospeed;
dbg("%s - enter c_ospeed or baud=%d", __func__, baud);
@@ -961,13 +961,13 @@ static void iuu_set_termios(struct tty_struct *tty,
* settings back over and then adjust them
*/
if (old_termios)
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
if (status != 0) /* Set failed - return old bits */
return;
/* Re-encode speed, parity and csize */
tty_encode_baud_rate(tty, baud, baud);
- tty->termios->c_cflag &= ~(supported_mask|CSIZE);
- tty->termios->c_cflag |= newval | csize;
+ tty->termios.c_cflag &= ~(supported_mask|CSIZE);
+ tty->termios.c_cflag |= newval | csize;
}
static void iuu_close(struct usb_serial_port *port)
@@ -993,14 +993,14 @@ static void iuu_close(struct usb_serial_port *port)
static void iuu_init_termios(struct tty_struct *tty)
{
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600
| TIOCM_CTS | CSTOPB | PARENB;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
- tty->termios->c_lflag = 0;
- tty->termios->c_oflag = 0;
- tty->termios->c_iflag = 0;
+ tty->termios.c_ispeed = 9600;
+ tty->termios.c_ospeed = 9600;
+ tty->termios.c_lflag = 0;
+ tty->termios.c_oflag = 0;
+ tty->termios.c_iflag = 0;
}
static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -1012,8 +1012,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
u32 actual;
struct iuu_private *priv = usb_get_serial_port_data(port);
- baud = tty->termios->c_ospeed;
- tty->termios->c_ispeed = baud;
+ baud = tty->termios.c_ospeed;
+ tty->termios.c_ispeed = baud;
/* Re-encode speed */
tty_encode_baud_rate(tty, baud, baud);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index af0b70eaf032..7bcbb47e1449 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -158,7 +158,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
device_port = port->number - port->serial->minor;
/* Baud rate calculation takes baud rate as an integer
@@ -179,7 +179,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
/* Mark/Space not supported */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
keyspan_send_setup(port, 0);
}
@@ -1086,7 +1086,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
device_port = port->number - port->serial->minor;
if (tty) {
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
/* Baud rate calculation takes baud rate as an integer
so other rates can be generated if desired. */
baud_rate = tty_get_baud_rate(tty);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index a4ac3cfeffc4..dcada8615fcf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -338,7 +338,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
7[EOMS]1: 10 bit, b0/b7 is parity
7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
- HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+ HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
bit.
For now, just do baud. */
@@ -353,7 +353,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
}
/* Only speed can change so copy the old h/w parameters
then encode the new speed */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
tty_encode_baud_rate(tty, speed, speed);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5bed59cd5776..def9ad258715 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -311,12 +311,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
/* set up termios structure */
spin_lock_irqsave(&priv->lock, flags);
- priv->termios.c_iflag = tty->termios->c_iflag;
- priv->termios.c_oflag = tty->termios->c_oflag;
- priv->termios.c_cflag = tty->termios->c_cflag;
- priv->termios.c_lflag = tty->termios->c_lflag;
+ priv->termios.c_iflag = tty->termios.c_iflag;
+ priv->termios.c_oflag = tty->termios.c_oflag;
+ priv->termios.c_cflag = tty->termios.c_cflag;
+ priv->termios.c_lflag = tty->termios.c_lflag;
for (i = 0; i < NCCS; i++)
- priv->termios.c_cc[i] = tty->termios->c_cc[i];
+ priv->termios.c_cc[i] = tty->termios.c_cc[i];
priv->cfg.pktlen = cfg->pktlen;
priv->cfg.baudrate = cfg->baudrate;
priv->cfg.databits = cfg->databits;
@@ -445,9 +445,9 @@ static void klsi_105_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
- unsigned int iflag = tty->termios->c_iflag;
+ unsigned int iflag = tty->termios.c_iflag;
unsigned int old_iflag = old_termios->c_iflag;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
struct klsi_105_port_settings *cfg;
unsigned long flags;
@@ -560,7 +560,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
|| (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
/* Not currently supported */
- tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
+ tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
#if 0
priv->last_lcr = 0;
@@ -587,7 +587,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
|| (iflag & IXON) != (old_iflag & IXON)
|| (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
/* Not currently supported */
- tty->termios->c_cflag &= ~CRTSCTS;
+ tty->termios.c_cflag &= ~CRTSCTS;
/* Drop DTR/RTS if no flow control otherwise assert */
#if 0
if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index fafeabb64c55..bf5c74965d34 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -191,11 +191,11 @@ static void kobil_release(struct usb_serial *serial)
static void kobil_init_termios(struct tty_struct *tty)
{
/* Default to echo off and other sane device settings */
- tty->termios->c_lflag = 0;
- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+ tty->termios.c_lflag = 0;
+ tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+ tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF;
/* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
- tty->termios->c_oflag &= ~ONLCR;
+ tty->termios.c_oflag &= ~ONLCR;
}
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -581,14 +581,14 @@ static void kobil_set_termios(struct tty_struct *tty,
struct kobil_private *priv;
int result;
unsigned short urb_val = 0;
- int c_cflag = tty->termios->c_cflag;
+ int c_cflag = tty->termios.c_cflag;
speed_t speed;
priv = usb_get_serial_port_data(port);
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
/* This device doesn't support ioctl calls */
- *tty->termios = *old;
+ tty_termios_copy_hw(&tty->termios, old);
return;
}
@@ -612,7 +612,7 @@ static void kobil_set_termios(struct tty_struct *tty,
urb_val |= SUSBCR_SPASB_EvenParity;
} else
urb_val |= SUSBCR_SPASB_NoParity;
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
tty_encode_baud_rate(tty, speed, speed);
result = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index a71fa0aa0406..df98cffdba65 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -454,7 +454,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
* either.
*/
spin_lock_irqsave(&priv->lock, flags);
- if (tty && (tty->termios->c_cflag & CBAUD))
+ if (tty && (tty->termios.c_cflag & CBAUD))
priv->control_state = TIOCM_DTR | TIOCM_RTS;
else
priv->control_state = 0;
@@ -634,7 +634,7 @@ static void mct_u232_set_termios(struct tty_struct *tty,
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
unsigned int cflag = termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index d47eb06fe463..2b0627b5fe2c 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -130,12 +130,6 @@ 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_err(&port->dev, "%s - bad tty pointer - exiting\n",
- __func__);
- return;
- }
-
if (tty && urb->actual_length) {
/* Loop through the data copying each byte to the tty layer. */
tty_insert_flip_string(tty, data, urb->actual_length);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index a07dd3c8cfef..012f67b2e4cc 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1349,7 +1349,7 @@ static void mos7720_throttle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
write_mos_reg(port->serial, port->number - port->serial->minor,
MCR, mos7720_port->shadowMCR);
@@ -1383,7 +1383,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR |= UART_MCR_RTS;
write_mos_reg(port->serial, port->number - port->serial->minor,
MCR, mos7720_port->shadowMCR);
@@ -1604,8 +1604,8 @@ static void change_port_settings(struct tty_struct *tty,
lStop = 0x00; /* 1 stop bit */
lParity = 0x00; /* No parity */
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* Change the number of bits */
switch (cflag & CSIZE) {
@@ -1753,11 +1753,11 @@ static void mos7720_set_termios(struct tty_struct *tty,
dbg("%s\n", "setting termios - ASPIRE");
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - cflag %08x iflag %08x", __func__,
- tty->termios->c_cflag,
- RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios.c_cflag,
+ RELEVANT_IFLAG(tty->termios.c_iflag));
dbg("%s - old cflag %08x old iflag %08x", __func__,
old_termios->c_cflag,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 2f6da1e89bfa..402c32d7accb 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1651,7 +1651,7 @@ static void mos7840_throttle(struct tty_struct *tty)
return;
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7840_port->shadowMCR &= ~MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -1694,7 +1694,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
}
/* if we are implementing RTS/CTS, toggle that line */
- if (tty->termios->c_cflag & CRTSCTS) {
+ if (tty->termios.c_cflag & CRTSCTS) {
mos7840_port->shadowMCR |= MCR_RTS;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
mos7840_port->shadowMCR);
@@ -2000,8 +2000,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
lStop = LCR_STOP_1;
lParity = LCR_PAR_NONE;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
/* Change the number of bits */
if (cflag & CSIZE) {
@@ -2161,10 +2161,10 @@ static void mos7840_set_termios(struct tty_struct *tty,
dbg("%s", "setting termios - ");
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
dbg("%s - clfag %08x iflag %08x", __func__,
- tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
+ tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
dbg("%s - old clfag %08x old iflag %08x", __func__,
old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
dbg("%s - port %d", __func__, port->number);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index cc40f47ecea1..5ce88d1bc6f1 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -886,8 +886,6 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
@@ -1092,6 +1090,10 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
+ { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
+ { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
+
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
{ USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 5976b65ab6ee..9f555560bfbf 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -404,10 +404,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
static void oti6858_init_termios(struct tty_struct *tty)
{
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 38400;
- tty->termios->c_ospeed = 38400;
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios.c_ispeed = 38400;
+ tty->termios.c_ospeed = 38400;
}
static void oti6858_set_termios(struct tty_struct *tty,
@@ -425,7 +425,7 @@ static void oti6858_set_termios(struct tty_struct *tty,
return;
}
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
spin_lock_irqsave(&priv->lock, flags);
divisor = priv->pending_setup.divisor;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 13b8dd6481f5..2b9108a8ea64 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -260,16 +260,16 @@ static void pl2303_set_termios(struct tty_struct *tty,
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
- cflag = tty->termios->c_cflag;
+ cflag = tty->termios.c_cflag;
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __func__);
/* Report back no change occurred */
- *tty->termios = *old_termios;
+ tty->termios = *old_termios;
return;
}
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 151670b6b72a..7df9cdb053ed 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -275,7 +275,7 @@ static void qt2_set_termios(struct tty_struct *tty,
{
struct usb_device *dev = port->serial->dev;
struct qt2_port_private *port_priv;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
u16 baud;
unsigned int cflag = termios->c_cflag;
u16 new_lcr = 0;
@@ -406,7 +406,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
port_priv->device_port = (u8) device_port;
if (tty)
- qt2_set_termios(tty, port, tty->termios);
+ qt2_set_termios(tty, port, &tty->termios);
return 0;
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 0274710cced5..b14ebbd73567 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -382,7 +382,7 @@ 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)
{
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
sierra_send_setup(port);
}
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index cad608984710..ab68a4d74d61 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -316,10 +316,10 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
static void spcp8x5_init_termios(struct tty_struct *tty)
{
/* for the 1st time call this function */
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 115200;
- tty->termios->c_ospeed = 115200;
+ tty->termios = tty_std_termios;
+ tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios.c_ispeed = 115200;
+ tty->termios.c_ospeed = 115200;
}
/* set the serial param for transfer. we should check if we really need to
@@ -330,7 +330,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned short uartdata;
unsigned char buf[2] = {0, 0};
@@ -340,7 +340,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
/* check that they really want us to change something */
- if (!tty_termios_hw_change(tty->termios, old_termios))
+ if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
/* set DTR/RTS active */
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 3fee23bf0c14..cf2d30cf7588 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -216,7 +216,7 @@ static void ssu100_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct usb_device *dev = port->serial->dev;
- struct ktermios *termios = tty->termios;
+ struct ktermios *termios = &tty->termios;
u16 baud, divisor, remainder;
unsigned int cflag = termios->c_cflag;
u16 urb_value = 0; /* will hold the new flags */
@@ -322,7 +322,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
dbg("%s - set uart failed", __func__);
if (tty)
- ssu100_set_termios(tty, port, tty->termios);
+ ssu100_set_termios(tty, port, &tty->termios);
return usb_serial_generic_open(tty, port);
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index a4404f5ad68e..f502a16aac21 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -520,7 +520,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
}
if (tty)
- ti_set_termios(tty, port, tty->termios);
+ ti_set_termios(tty, port, &tty->termios);
dbg("%s - sending TI_OPEN_PORT", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -562,7 +562,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(dev, port->read_urb->pipe);
if (tty)
- ti_set_termios(tty, port, tty->termios);
+ ti_set_termios(tty, port, &tty->termios);
dbg("%s - sending TI_OPEN_PORT (2)", __func__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -831,8 +831,8 @@ static void ti_set_termios(struct tty_struct *tty,
int port_number = port->number - port->serial->minor;
unsigned int mcr;
- cflag = tty->termios->c_cflag;
- iflag = tty->termios->c_iflag;
+ cflag = tty->termios.c_cflag;
+ iflag = tty->termios.c_iflag;
dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
dbg("%s - old clfag %08x, old iflag %08x", __func__,
@@ -871,7 +871,7 @@ static void ti_set_termios(struct tty_struct *tty,
}
/* CMSPAR isn't supported by this driver */
- tty->termios->c_cflag &= ~CMSPAR;
+ tty->termios.c_cflag &= ~CMSPAR;
if (cflag & PARENB) {
if (cflag & PARODD) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 27483f91a4a3..aa4b0d775992 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
if (retval)
goto error_get_interface;
- retval = tty_standard_install(driver, tty);
+ retval = tty_port_install(&port->port, driver, tty);
if (retval)
goto error_init_termios;
@@ -305,8 +305,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
* Do the resource freeing and refcount dropping for the port.
* Avoid freeing the console.
*
- * Called asynchronously after the last tty kref is dropped,
- * and the tty layer has already done the tty_shutdown(tty);
+ * Called asynchronously after the last tty kref is dropped.
*/
static void serial_cleanup(struct tty_struct *tty)
{
@@ -423,7 +422,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
else
- tty_termios_copy_hw(tty->termios, old);
+ tty_termios_copy_hw(&tty->termios, old);
}
static int serial_break(struct tty_struct *tty, int break_state)
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 6855d5ed0331..72b678d90831 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -67,7 +67,7 @@ void usb_wwan_set_termios(struct tty_struct *tty,
struct usb_wwan_intf_private *intfdata = port->serial->private;
/* Doesn't support option setting */
- tty_termios_copy_hw(tty->termios, old_termios);
+ tty_termios_copy_hw(&tty->termios, old_termios);
if (intfdata->send_setup)
intfdata->send_setup(port);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 473635e7f5db..b36077de72b9 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -724,7 +724,7 @@ static void firm_setup_port(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_port_settings port_settings;
- unsigned int cflag = tty->termios->c_cflag;
+ unsigned int cflag = tty->termios.c_cflag;
port_settings.port = port->number + 1;
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index bfdc5fbeaa11..92257ef19403 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -27,9 +27,9 @@
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/slab.h>
+#include <linux/platform_data/omap1_bl.h>
#include <mach/hardware.h>
-#include <plat/board.h>
#include <plat/mux.h>
#define OMAPBL_MAX_INTENSITY 0xff
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 5b289c5f695b..ee9e29639dcc 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -37,6 +37,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <plat/cpu.h>
#include <plat/clock.h>
#include <video/omapdss.h>
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index fc671d3d8004..3c39aa8de928 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -31,6 +31,7 @@
#include <linux/omapfb.h>
#include <video/omapdss.h>
+#include <plat/cpu.h>
#include <plat/vram.h>
#include <plat/vrfb.h>
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 4b0fcf3c2d03..fee195a76941 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -19,7 +19,6 @@
#include <linux/pm_runtime.h>
#include <asm/irq.h>
-#include <mach/hardware.h>
#include "../w1.h"
#include "../w1_int.h"
@@ -644,7 +643,7 @@ static int omap_hdq_remove(struct platform_device *pdev)
/* remove module dependency */
pm_runtime_disable(&pdev->dev);
- free_irq(INT_24XX_HDQ_IRQ, hdq_data);
+ free_irq(platform_get_irq(pdev, 0), hdq_data);
platform_set_drvdata(pdev, NULL);
iounmap(hdq_data->hdq_base);
kfree(hdq_data);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index fceec4f4eb7e..f5db18dbc0f9 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -46,6 +46,7 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
+#include <plat/cpu.h>
#include <plat/prcm.h>
#include "omap_wdt.h"
@@ -218,12 +219,16 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_GETSTATUS:
return put_user(0, (int __user *)arg);
case WDIOC_GETBOOTSTATUS:
+#ifdef CONFIG_ARCH_OMAP1
if (cpu_is_omap16xx())
return put_user(__raw_readw(ARM_SYSST),
(int __user *)arg);
+#endif
+#ifdef CONFIG_ARCH_OMAP2PLUS
if (cpu_is_omap24xx())
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
+#endif
return put_user(0, (int __user *)arg);
case WDIOC_KEEPALIVE:
spin_lock(&wdt_lock);