aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:45:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-09-01 09:45:57 -0700
commitebf435d3b51b22340ef047aad0c2936ec4833ab2 (patch)
treee67a3e22305b679d5ba990495edb0a7d07df9b23
parentc6c3c5704ba70820f6b632982abde06661b7222a (diff)
parent4adb389e08c95fdf91995271932c59250ff0d561 (diff)
Merge tag 'staging-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull IIO and staging driver updates from Greg KH: "Here is the big set of staging and IIO driver updates for 5.15-rc1. Also included in here are the counter driver subsystem updates as the IIO drivers needed them. Lots of churn in some staging drivers, we dropped the "old" rtl8188eu driver and replaced it with a newer version of the driver that had been maintained out-of-tree by Larry with the end goal of actually being able to get this driver out of staging eventually. Despite that driver being "newer" the line count of this pull request is going up. Some drivers moved out of staging as well, which is always nice to see, that is why there are additions to the mfc and misc driver subsystems. All of these were acked by the various subsystem maintainers involved. But by far, as normal, it's coding style cleanups all over the drivers/staging/ tree in here. Full details of these changes are in the shortlog. All of these have been in linux-next for a while with no reported problems" [ Note: the r8188eu merge clashed with commit 89939e890605 ("staging: rtlwifi: use siocdevprivate") from the networking tree. When resolving the issue, I noted that the whole r8188eu rtw_android code is dead since commit ae7471cae00a ("staging: r8188eu: remove rtw_ioctl function"). End result: the merge resolution was to throw all of that away, rather than do the mindless fixup to code that isn't actually reachable - Linus ] * tag 'staging-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (551 commits) staging: vt6655: Remove filenames in files staging: r8188eu: add extra TODO entries staging: vt6656: Remove filenames in files staging: wlan-ng: fix invalid assignment warning staging: r8188eu: rename fields of struct rtl_ps staging: r8188eu: remove ODM_DynamicPrimaryCCA_DupRTS() staging: r8188eu: rename fields of struct dyn_primary_cca staging: r8188eu: rename struct field Wifi_Error_Status staging: r8188eu: Provide a TODO file for this driver staging: r8188eu: remove unneeded variable staging: r8188eu: remove unneeded conversions to bool staging: r8188eu: remove {read,write}_macreg staging: r8188eu: core: remove condition with no effect staging: r8188eu: remove ethernet.h header file staging: r8188eu: remove ip.h header file staging: r8188eu: remove if_ether.h header file staging: r8188eu: make rtw_deinit_intf_priv return void staging: r8188eu: use is_multicast_ether_addr in os_dep/recv_linux.c staging: r8188eu: use is_multicast_ether_addr in hal/rtl8188eu_xmit.c staging: r8188eu: use is_multicast_ether_addr in core/rtw_xmit.c ...
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp4031
-rw-r--r--Documentation/devicetree/bindings/iio/accel/bosch,bma180.yaml61
-rw-r--r--Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml55
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml19
-rw-r--r--Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml134
-rw-r--r--Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml1
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5064.yaml268
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5360.yaml79
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml70
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5421.yaml51
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5449.yaml97
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5504.yaml50
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5624r.yaml47
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml75
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5761.yaml60
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5764.yaml62
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml52
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad8801.yaml60
-rw-r--r--Documentation/devicetree/bindings/iio/dac/microchip,mcp4922.yaml46
-rw-r--r--Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml (renamed from drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml)31
-rw-r--r--Documentation/devicetree/bindings/trivial-devices.yaml6
-rw-r--r--MAINTAINERS31
-rw-r--r--drivers/counter/104-quad-8.c47
-rw-r--r--drivers/counter/counter.c50
-rw-r--r--drivers/counter/ftm-quaddec.c5
-rw-r--r--drivers/counter/intel-qep.c7
-rw-r--r--drivers/counter/interrupt-cnt.c11
-rw-r--r--drivers/counter/microchip-tcb-capture.c16
-rw-r--r--drivers/counter/stm32-lptimer-cnt.c18
-rw-r--r--drivers/counter/stm32-timer-cnt.c10
-rw-r--r--drivers/counter/ti-eqep.c37
-rw-r--r--drivers/iio/accel/Kconfig5
-rw-r--r--drivers/iio/accel/adxl345.h1
-rw-r--r--drivers/iio/accel/adxl345_core.c29
-rw-r--r--drivers/iio/accel/adxl345_i2c.c6
-rw-r--r--drivers/iio/accel/adxl345_spi.c6
-rw-r--r--drivers/iio/accel/bma220_spi.c79
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c78
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c10
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c10
-rw-r--r--drivers/iio/accel/bmc150-accel.h20
-rw-r--r--drivers/iio/accel/da280.c26
-rw-r--r--drivers/iio/accel/da311.c26
-rw-r--r--drivers/iio/accel/dmard10.c27
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c10
-rw-r--r--drivers/iio/accel/st_accel.h4
-rw-r--r--drivers/iio/accel/st_accel_buffer.c16
-rw-r--r--drivers/iio/accel/st_accel_core.c14
-rw-r--r--drivers/iio/accel/st_accel_i2c.c3
-rw-r--r--drivers/iio/accel/st_accel_spi.c2
-rw-r--r--drivers/iio/adc/Kconfig10
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ep93xx_adc.c6
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c17
-rw-r--r--drivers/iio/adc/ingenic-adc.c102
-rw-r--r--drivers/iio/adc/meson_saradc.c20
-rw-r--r--drivers/iio/adc/rockchip_saradc.c69
-rw-r--r--drivers/iio/adc/rzg2l_adc.c600
-rw-r--r--drivers/iio/chemical/Kconfig11
-rw-r--r--drivers/iio/chemical/Makefile1
-rw-r--r--drivers/iio/chemical/sgp40.c378
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_buffer.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c1
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.h1
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_i2c.c3
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_spi.c3
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c1
-rw-r--r--drivers/iio/dac/ad5624r_spi.c18
-rw-r--r--drivers/iio/dac/max5821.c41
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c11
-rw-r--r--drivers/iio/gyro/st_gyro.h4
-rw-r--r--drivers/iio/gyro/st_gyro_buffer.c16
-rw-r--r--drivers/iio/gyro/st_gyro_core.c15
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c2
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c22
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h18
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c15
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c1
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c3
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c3
-rw-r--r--drivers/iio/industrialio-buffer.c9
-rw-r--r--drivers/iio/industrialio-core.c33
-rw-r--r--drivers/iio/light/adjd_s311.c53
-rw-r--r--drivers/iio/light/cm3323.c7
-rw-r--r--drivers/iio/light/hid-sensor-als.c11
-rw-r--r--drivers/iio/light/hid-sensor-prox.c11
-rw-r--r--drivers/iio/light/si1145.c1
-rw-r--r--drivers/iio/light/tcs3414.c48
-rw-r--r--drivers/iio/magnetometer/st_magn.h12
-rw-r--r--drivers/iio/magnetometer/st_magn_buffer.c16
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c17
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c2
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c11
-rw-r--r--drivers/iio/potentiometer/Kconfig10
-rw-r--r--drivers/iio/potentiometer/Makefile1
-rw-r--r--drivers/iio/potentiometer/ad5110.c344
-rw-r--r--drivers/iio/potentiometer/max5481.c22
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c51
-rw-r--r--drivers/iio/pressure/hp03.c36
-rw-r--r--drivers/iio/pressure/st_pressure.h5
-rw-r--r--drivers/iio/pressure/st_pressure_buffer.c16
-rw-r--r--drivers/iio/pressure/st_pressure_core.c16
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c3
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c2
-rw-r--r--drivers/iio/proximity/rfd77402.c83
-rw-r--r--drivers/iio/proximity/sx9310.c48
-rw-r--r--drivers/iio/proximity/vcnl3020.c351
-rw-r--r--drivers/iio/temperature/ltc2983.c30
-rw-r--r--drivers/iio/temperature/tmp006.c53
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/hi6421-spmi-pmic.c72
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/hi6421v600-irq.c307
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile3
-rw-r--r--drivers/staging/board/board.c7
-rw-r--r--drivers/staging/clocking-wizard/Kconfig2
-rw-r--r--drivers/staging/fbtft/fbtft-core.c23
-rw-r--r--drivers/staging/gdm724x/netlink_k.c4
-rw-r--r--drivers/staging/hikey9xx/Kconfig19
-rw-r--r--drivers/staging/hikey9xx/Makefile3
-rw-r--r--drivers/staging/hikey9xx/TODO5
-rw-r--r--drivers/staging/hikey9xx/hi6421-spmi-pmic.c311
-rw-r--r--drivers/staging/ks7010/ks7010_sdio.c2
-rw-r--r--drivers/staging/ks7010/ks_wlan_net.c10
-rw-r--r--drivers/staging/most/video/video.c4
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c13
-rw-r--r--drivers/staging/qlge/qlge_dbg.c4
-rw-r--r--drivers/staging/r8188eu/Kconfig (renamed from drivers/staging/rtl8188eu/Kconfig)7
-rw-r--r--drivers/staging/r8188eu/Makefile105
-rw-r--r--drivers/staging/r8188eu/TODO16
-rw-r--r--drivers/staging/r8188eu/core/rtw_ap.c (renamed from drivers/staging/rtl8188eu/core/rtw_ap.c)763
-rw-r--r--drivers/staging/r8188eu/core/rtw_br_ext.c717
-rw-r--r--drivers/staging/r8188eu/core/rtw_cmd.c2128
-rw-r--r--drivers/staging/r8188eu/core/rtw_debug.c904
-rw-r--r--drivers/staging/r8188eu/core/rtw_efuse.c848
-rw-r--r--drivers/staging/r8188eu/core/rtw_ieee80211.c1539
-rw-r--r--drivers/staging/r8188eu/core/rtw_io.c299
-rw-r--r--drivers/staging/r8188eu/core/rtw_ioctl_set.c891
-rw-r--r--drivers/staging/r8188eu/core/rtw_iol.c192
-rw-r--r--drivers/staging/r8188eu/core/rtw_led.c1612
-rw-r--r--drivers/staging/r8188eu/core/rtw_mlme.c (renamed from drivers/staging/rtl8188eu/core/rtw_mlme.c)1114
-rw-r--r--drivers/staging/r8188eu/core/rtw_mlme_ext.c8327
-rw-r--r--drivers/staging/r8188eu/core/rtw_mp.c935
-rw-r--r--drivers/staging/r8188eu/core/rtw_mp_ioctl.c1170
-rw-r--r--drivers/staging/r8188eu/core/rtw_p2p.c1997
-rw-r--r--drivers/staging/r8188eu/core/rtw_pwrctrl.c (renamed from drivers/staging/rtl8188eu/core/rtw_pwrctrl.c)354
-rw-r--r--drivers/staging/r8188eu/core/rtw_recv.c (renamed from drivers/staging/rtl8188eu/core/rtw_recv.c)888
-rw-r--r--drivers/staging/r8188eu/core/rtw_rf.c (renamed from drivers/staging/rtl8188eu/core/rtw_rf.c)34
-rw-r--r--drivers/staging/r8188eu/core/rtw_security.c1656
-rw-r--r--drivers/staging/r8188eu/core/rtw_sreset.c62
-rw-r--r--drivers/staging/r8188eu/core/rtw_sta_mgt.c (renamed from drivers/staging/rtl8188eu/core/rtw_sta_mgt.c)271
-rw-r--r--drivers/staging/r8188eu/core/rtw_wlan_util.c (renamed from drivers/staging/rtl8188eu/core/rtw_wlan_util.c)940
-rw-r--r--drivers/staging/r8188eu/core/rtw_xmit.c (renamed from drivers/staging/rtl8188eu/core/rtw_xmit.c)840
-rw-r--r--drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c69
-rw-r--r--drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c (renamed from drivers/staging/rtl8188eu/hal/hal8188e_rate_adaptive.c)148
-rw-r--r--drivers/staging/r8188eu/hal/HalHWImg8188E_BB.c (renamed from drivers/staging/rtl8188eu/hal/bb_cfg.c)473
-rw-r--r--drivers/staging/r8188eu/hal/HalHWImg8188E_MAC.c213
-rw-r--r--drivers/staging/r8188eu/hal/HalHWImg8188E_RF.c250
-rw-r--r--drivers/staging/r8188eu/hal/HalPhyRf_8188e.c1264
-rw-r--r--drivers/staging/r8188eu/hal/HalPwrSeqCmd.c95
-rw-r--r--drivers/staging/r8188eu/hal/hal_com.c (renamed from drivers/staging/rtl8188eu/hal/hal_com.c)189
-rw-r--r--drivers/staging/r8188eu/hal/hal_intf.c441
-rw-r--r--drivers/staging/r8188eu/hal/odm.c1968
-rw-r--r--drivers/staging/r8188eu/hal/odm_HWConfig.c567
-rw-r--r--drivers/staging/r8188eu/hal/odm_RTL8188E.c337
-rw-r--r--drivers/staging/r8188eu/hal/odm_RegConfig8188E.c98
-rw-r--r--drivers/staging/r8188eu/hal/odm_debug.c6
-rw-r--r--drivers/staging/r8188eu/hal/odm_interface.c178
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_cmd.c (renamed from drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c)422
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_dm.c238
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_hal_init.c2304
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_mp.c798
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_phycfg.c1105
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_rf6052.c550
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_rxdesc.c (renamed from drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c)43
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_sreset.c64
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188e_xmit.c (renamed from drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c)13
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188eu_led.c94
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188eu_recv.c117
-rw-r--r--drivers/staging/r8188eu/hal/rtl8188eu_xmit.c (renamed from drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c)204
-rw-r--r--drivers/staging/r8188eu/hal/usb_halinit.c (renamed from drivers/staging/rtl8188eu/hal/usb_halinit.c)1178
-rw-r--r--drivers/staging/r8188eu/hal/usb_ops_linux.c562
-rw-r--r--drivers/staging/r8188eu/include/Hal8188EPhyCfg.h (renamed from drivers/staging/rtl8188eu/include/hal8188e_phy_cfg.h)140
-rw-r--r--drivers/staging/r8188eu/include/Hal8188EPhyReg.h1072
-rw-r--r--drivers/staging/r8188eu/include/Hal8188EPwrSeq.h155
-rw-r--r--drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h64
-rw-r--r--drivers/staging/r8188eu/include/HalHWImg8188E_BB.h27
-rw-r--r--drivers/staging/r8188eu/include/HalHWImg8188E_FW.h16
-rw-r--r--drivers/staging/r8188eu/include/HalHWImg8188E_MAC.h13
-rw-r--r--drivers/staging/r8188eu/include/HalHWImg8188E_RF.h13
-rw-r--r--drivers/staging/r8188eu/include/HalPhyRf_8188e.h41
-rw-r--r--drivers/staging/r8188eu/include/HalPwrSeqCmd.h110
-rw-r--r--drivers/staging/r8188eu/include/HalVerDef.h149
-rw-r--r--drivers/staging/r8188eu/include/basic_types.h (renamed from drivers/staging/rtl8188eu/include/basic_types.h)101
-rw-r--r--drivers/staging/r8188eu/include/drv_types.h323
-rw-r--r--drivers/staging/r8188eu/include/hal_com.h (renamed from drivers/staging/rtl8188eu/include/hal_com.h)28
-rw-r--r--drivers/staging/r8188eu/include/hal_intf.h411
-rw-r--r--drivers/staging/r8188eu/include/ieee80211.h (renamed from drivers/staging/rtl8188eu/include/ieee80211.h)680
-rw-r--r--drivers/staging/r8188eu/include/ieee80211_ext.h271
-rw-r--r--drivers/staging/r8188eu/include/ioctl_cfg80211.h91
-rw-r--r--drivers/staging/r8188eu/include/mlme_osdep.h (renamed from drivers/staging/rtl8188eu/include/mlme_osdep.h)14
-rw-r--r--drivers/staging/r8188eu/include/mp_custom_oid.h333
-rw-r--r--drivers/staging/r8188eu/include/odm.h (renamed from drivers/staging/rtl8188eu/include/odm.h)227
-rw-r--r--drivers/staging/r8188eu/include/odm_HWConfig.h (renamed from drivers/staging/rtl8188eu/include/odm_hwconfig.h)37
-rw-r--r--drivers/staging/r8188eu/include/odm_RTL8188E.h36
-rw-r--r--drivers/staging/r8188eu/include/odm_RegConfig8188E.h27
-rw-r--r--drivers/staging/r8188eu/include/odm_RegDefine11AC.h29
-rw-r--r--drivers/staging/r8188eu/include/odm_RegDefine11N.h143
-rw-r--r--drivers/staging/r8188eu/include/odm_interface.h147
-rw-r--r--drivers/staging/r8188eu/include/odm_precomp.h (renamed from drivers/staging/rtl8188eu/include/odm_precomp.h)45
-rw-r--r--drivers/staging/r8188eu/include/odm_reg.h89
-rw-r--r--drivers/staging/r8188eu/include/odm_types.h45
-rw-r--r--drivers/staging/r8188eu/include/osdep_intf.h64
-rw-r--r--drivers/staging/r8188eu/include/osdep_service.h315
-rw-r--r--drivers/staging/r8188eu/include/recv_osdep.h37
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_cmd.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_cmd.h)48
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_dm.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_dm.h)21
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_hal.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_hal.h)223
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_led.h18
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_recv.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_recv.h)22
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_rf.h19
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_spec.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_spec.h)457
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_sreset.h15
-rw-r--r--drivers/staging/r8188eu/include/rtl8188e_xmit.h (renamed from drivers/staging/rtl8188eu/include/rtl8188e_xmit.h)51
-rw-r--r--drivers/staging/r8188eu/include/rtw_ap.h (renamed from drivers/staging/rtl8188eu/include/rtw_ap.h)18
-rw-r--r--drivers/staging/r8188eu/include/rtw_br_ext.h49
-rw-r--r--drivers/staging/r8188eu/include/rtw_cmd.h975
-rw-r--r--drivers/staging/r8188eu/include/rtw_debug.h231
-rw-r--r--drivers/staging/r8188eu/include/rtw_eeprom.h (renamed from drivers/staging/rtl8188eu/include/rtw_eeprom.h)32
-rw-r--r--drivers/staging/r8188eu/include/rtw_efuse.h134
-rw-r--r--drivers/staging/r8188eu/include/rtw_event.h97
-rw-r--r--drivers/staging/r8188eu/include/rtw_ht.h28
-rw-r--r--drivers/staging/r8188eu/include/rtw_io.h367
-rw-r--r--drivers/staging/r8188eu/include/rtw_ioctl.h (renamed from drivers/staging/rtl8188eu/include/rtw_ioctl.h)35
-rw-r--r--drivers/staging/r8188eu/include/rtw_ioctl_rtl.h63
-rw-r--r--drivers/staging/r8188eu/include/rtw_ioctl_set.h33
-rw-r--r--drivers/staging/r8188eu/include/rtw_iol.h68
-rw-r--r--drivers/staging/r8188eu/include/rtw_led.h181
-rw-r--r--drivers/staging/r8188eu/include/rtw_mlme.h632
-rw-r--r--drivers/staging/r8188eu/include/rtw_mlme_ext.h (renamed from drivers/staging/rtl8188eu/include/rtw_mlme_ext.h)355
-rw-r--r--drivers/staging/r8188eu/include/rtw_mp.h474
-rw-r--r--drivers/staging/r8188eu/include/rtw_mp_ioctl.h242
-rw-r--r--drivers/staging/r8188eu/include/rtw_mp_phy_regdef.h1063
-rw-r--r--drivers/staging/r8188eu/include/rtw_p2p.h119
-rw-r--r--drivers/staging/r8188eu/include/rtw_pwrctrl.h (renamed from drivers/staging/rtl8188eu/include/rtw_pwrctrl.h)75
-rw-r--r--drivers/staging/r8188eu/include/rtw_recv.h413
-rw-r--r--drivers/staging/r8188eu/include/rtw_rf.h (renamed from drivers/staging/rtl8188eu/include/rtw_rf.h)37
-rw-r--r--drivers/staging/r8188eu/include/rtw_security.h (renamed from drivers/staging/rtl8188eu/include/rtw_security.h)168
-rw-r--r--drivers/staging/r8188eu/include/rtw_sreset.h34
-rw-r--r--drivers/staging/r8188eu/include/rtw_xmit.h (renamed from drivers/staging/rtl8188eu/include/rtw_xmit.h)71
-rw-r--r--drivers/staging/r8188eu/include/sta_info.h (renamed from drivers/staging/rtl8188eu/include/sta_info.h)61
-rw-r--r--drivers/staging/r8188eu/include/usb_ops.h72
-rw-r--r--drivers/staging/r8188eu/include/usb_ops_linux.h39
-rw-r--r--drivers/staging/r8188eu/include/usb_osintf.h29
-rw-r--r--drivers/staging/r8188eu/include/usb_vendor_req.h35
-rw-r--r--drivers/staging/r8188eu/include/wifi.h1029
-rw-r--r--drivers/staging/r8188eu/include/wlan_bssdef.h (renamed from drivers/staging/rtl8188eu/include/wlan_bssdef.h)149
-rw-r--r--drivers/staging/r8188eu/include/xmit_osdep.h51
-rw-r--r--drivers/staging/r8188eu/os_dep/ioctl_linux.c6649
-rw-r--r--drivers/staging/r8188eu/os_dep/mlme_linux.c216
-rw-r--r--drivers/staging/r8188eu/os_dep/os_intfs.c1199
-rw-r--r--drivers/staging/r8188eu/os_dep/osdep_service.c343
-rw-r--r--drivers/staging/r8188eu/os_dep/recv_linux.c (renamed from drivers/staging/rtl8188eu/os_dep/recv_linux.c)128
-rw-r--r--drivers/staging/r8188eu/os_dep/usb_intf.c781
-rw-r--r--drivers/staging/r8188eu/os_dep/usb_ops_linux.c253
-rw-r--r--drivers/staging/r8188eu/os_dep/xmit_linux.c (renamed from drivers/staging/rtl8188eu/os_dep/xmit_linux.c)130
-rw-r--r--drivers/staging/rtl8188eu/Makefile56
-rw-r--r--drivers/staging/rtl8188eu/TODO14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c1219
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c876
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c992
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c512
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_iol.c19
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_led.c460
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c5172
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_security.c869
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sreset.c21
-rw-r--r--drivers/staging/rtl8188eu/hal/fw.c202
-rw-r--r--drivers/staging/rtl8188eu/hal/hal_intf.c60
-rw-r--r--drivers/staging/rtl8188eu/hal/mac_cfg.c120
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c966
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_hwconfig.c397
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_rtl8188e.c335
-rw-r--r--drivers/staging/rtl8188eu/hal/phy.c1276
-rw-r--r--drivers/staging/rtl8188eu/hal/pwrseq.c88
-rw-r--r--drivers/staging/rtl8188eu/hal/pwrseqcmd.c80
-rw-r--r--drivers/staging/rtl8188eu/hal/rf.c289
-rw-r--r--drivers/staging/rtl8188eu/hal/rf_cfg.c247
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_dm.c217
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c523
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_led.c55
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c83
-rw-r--r--drivers/staging/rtl8188eu/include/HalVerDef.h37
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h176
-rw-r--r--drivers/staging/rtl8188eu/include/fw.h44
-rw-r--r--drivers/staging/rtl8188eu/include/hal8188e_phy_reg.h201
-rw-r--r--drivers/staging/rtl8188eu/include/hal8188e_rate_adaptive.h74
-rw-r--r--drivers/staging/rtl8188eu/include/hal_intf.h223
-rw-r--r--drivers/staging/rtl8188eu/include/mon.h28
-rw-r--r--drivers/staging/rtl8188eu/include/odm_rtl8188e.h39
-rw-r--r--drivers/staging/rtl8188eu/include/odm_types.h24
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_intf.h37
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h81
-rw-r--r--drivers/staging/rtl8188eu/include/phy.h26
-rw-r--r--drivers/staging/rtl8188eu/include/phydm_reg.h22
-rw-r--r--drivers/staging/rtl8188eu/include/phydm_regdefine11n.h53
-rw-r--r--drivers/staging/rtl8188eu/include/pwrseq.h242
-rw-r--r--drivers/staging/rtl8188eu/include/pwrseqcmd.h52
-rw-r--r--drivers/staging/rtl8188eu/include/recv_osdep.h26
-rw-r--r--drivers/staging/rtl8188eu/include/rf.h12
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_android.h51
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_cmd.h361
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_efuse.h67
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_event.h81
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ht.h26
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_ioctl_set.h28
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_iol.h14
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_led.h98
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme.h355
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_recv.h262
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_sreset.h30
-rw-r--r--drivers/staging/rtl8188eu/include/usb_ops_linux.h26
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h355
-rw-r--r--drivers/staging/rtl8188eu/include/xmit_osdep.h32
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c2777
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c167
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mon.c183
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c658
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c63
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c231
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c485
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c644
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c5
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_ccmp.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c57
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c3
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c18
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c49
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c3
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c2
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c92
-rw-r--r--drivers/staging/rtl8712/hal_init.c1
-rw-r--r--drivers/staging/rtl8712/os_intfs.c2
-rw-r--r--drivers/staging/rtl8712/osdep_service.h2
-rw-r--r--drivers/staging/rtl8712/wifi.h48
-rw-r--r--drivers/staging/rtl8723bs/Kconfig3
-rw-r--r--drivers/staging/rtl8723bs/Makefile1
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c135
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c54
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_debug.c19
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c154
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_io.c13
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ioctl_set.c103
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c263
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c297
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_recv.c6
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_rf.c1
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_security.c36
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_wlan_util.c147
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c464
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.h1
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c414
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.h1
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h8
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_BB.c17
-rw-r--r--drivers/staging/rtl8723bs/hal/HalHWImg8723B_RF.c86
-rw-r--r--drivers/staging/rtl8723bs/hal/HalPhyRf.c67
-rw-r--r--drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c191
-rw-r--r--drivers/staging/rtl8723bs/hal/Mp_Precomp.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_btcoex.c111
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c172
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com_phycfg.c447
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_sdio.c1
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.c56
-rw-r--r--drivers/staging/rtl8723bs/hal/odm.h25
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.c36
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_DIG.c5
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.c343
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_HWConfig.h29
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_NoiseMonitor.c23
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RTL8723B.c36
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RTL8723B.h14
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.c7
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegConfig8723B.h11
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_RegDefine11N.h2
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_precomp.h1
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_reg.h4
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c23
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_dm.c12
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c84
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c52
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c21
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_rxdesc.c1
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c3
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c1
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_halinit.c2
-rw-r--r--drivers/staging/rtl8723bs/include/Hal8192CPhyReg.h4
-rw-r--r--drivers/staging/rtl8723bs/include/HalVerDef.h18
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h9
-rw-r--r--drivers/staging/rtl8723bs/include/ethernet.h14
-rw-r--r--drivers/staging/rtl8723bs/include/hal_btcoex.h3
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com.h35
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com_phycfg.h20
-rw-r--r--drivers/staging/rtl8723bs/include/hal_com_reg.h19
-rw-r--r--drivers/staging/rtl8723bs/include/hal_data.h24
-rw-r--r--drivers/staging/rtl8723bs/include/hal_pg.h8
-rw-r--r--drivers/staging/rtl8723bs/include/hal_phy.h3
-rw-r--r--drivers/staging/rtl8723bs/include/ieee80211.h42
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_intf.h2
-rw-r--r--drivers/staging/rtl8723bs/include/osdep_service.h4
-rw-r--r--drivers/staging/rtl8723bs/include/rtl8723b_xmit.h8
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_ioctl_set.h1
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_mlme.h6
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_recv.h2
-rw-r--r--drivers/staging/rtl8723bs/include/rtw_rf.h10
-rw-r--r--drivers/staging/rtl8723bs/include/wifi.h8
-rw-r--r--drivers/staging/rtl8723bs/include/wlan_bssdef.h92
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c173
-rw-r--r--drivers/staging/rtl8723bs/os_dep/ioctl_linux.c3229
-rw-r--r--drivers/staging/rtl8723bs/os_dep/mlme_linux.c4
-rw-r--r--drivers/staging/rtl8723bs/os_dep/os_intfs.c32
-rw-r--r--drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c1
-rw-r--r--drivers/staging/rts5208/rtsx_scsi.c10
-rw-r--r--drivers/staging/sm750fb/sm750.c52
-rw-r--r--drivers/staging/sm750fb/sm750.h12
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.c4
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c62
-rw-r--r--drivers/staging/vc04_services/Kconfig28
-rw-r--r--drivers/staging/vc04_services/Makefile5
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.h2
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c564
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c2006
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h82
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c1440
-rw-r--r--drivers/staging/vt6655/baseband.c2
-rw-r--r--drivers/staging/vt6655/baseband.h2
-rw-r--r--drivers/staging/vt6655/card.c1
-rw-r--r--drivers/staging/vt6655/card.h2
-rw-r--r--drivers/staging/vt6655/channel.c2
-rw-r--r--drivers/staging/vt6655/channel.h1
-rw-r--r--drivers/staging/vt6655/desc.h2
-rw-r--r--drivers/staging/vt6655/device.h2
-rw-r--r--drivers/staging/vt6655/device_cfg.h6
-rw-r--r--drivers/staging/vt6655/device_main.c2
-rw-r--r--drivers/staging/vt6655/dpc.c2
-rw-r--r--drivers/staging/vt6655/dpc.h2
-rw-r--r--drivers/staging/vt6655/key.c2
-rw-r--r--drivers/staging/vt6655/key.h2
-rw-r--r--drivers/staging/vt6655/mac.c3
-rw-r--r--drivers/staging/vt6655/mac.h2
-rw-r--r--drivers/staging/vt6655/power.c2
-rw-r--r--drivers/staging/vt6655/power.h2
-rw-r--r--drivers/staging/vt6655/rf.c2
-rw-r--r--drivers/staging/vt6655/rf.h2
-rw-r--r--drivers/staging/vt6655/rxtx.c2
-rw-r--r--drivers/staging/vt6655/rxtx.h2
-rw-r--r--drivers/staging/vt6655/srom.c2
-rw-r--r--drivers/staging/vt6655/srom.h2
-rw-r--r--drivers/staging/vt6655/tmacro.h2
-rw-r--r--drivers/staging/vt6655/upc.h2
-rw-r--r--drivers/staging/vt6656/baseband.c2
-rw-r--r--drivers/staging/vt6656/baseband.h2
-rw-r--r--drivers/staging/vt6656/card.c1
-rw-r--r--drivers/staging/vt6656/card.h2
-rw-r--r--drivers/staging/vt6656/channel.c2
-rw-r--r--drivers/staging/vt6656/channel.h2
-rw-r--r--drivers/staging/vt6656/desc.h2
-rw-r--r--drivers/staging/vt6656/device.h4
-rw-r--r--drivers/staging/vt6656/key.c2
-rw-r--r--drivers/staging/vt6656/key.h2
-rw-r--r--drivers/staging/vt6656/mac.c2
-rw-r--r--drivers/staging/vt6656/mac.h2
-rw-r--r--drivers/staging/vt6656/main_usb.c2
-rw-r--r--drivers/staging/vt6656/power.c2
-rw-r--r--drivers/staging/vt6656/power.h2
-rw-r--r--drivers/staging/vt6656/rf.c2
-rw-r--r--drivers/staging/vt6656/rf.h2
-rw-r--r--drivers/staging/vt6656/rxtx.c2
-rw-r--r--drivers/staging/vt6656/rxtx.h2
-rw-r--r--drivers/staging/vt6656/usbpipe.c2
-rw-r--r--drivers/staging/vt6656/usbpipe.h2
-rw-r--r--drivers/staging/vt6656/wcmd.c2
-rw-r--r--drivers/staging/vt6656/wcmd.h2
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h19
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c13
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c48
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h2
-rw-r--r--drivers/staging/wlan-ng/p80211hdr.h30
-rw-r--r--drivers/staging/wlan-ng/p80211mgmt.h24
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c12
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.h2
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c8
-rw-r--r--drivers/staging/wlan-ng/prism2mib.c10
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c6
-rw-r--r--include/dt-bindings/iio/adc/ingenic,adc.h1
-rw-r--r--include/linux/counter.h32
-rw-r--r--include/linux/mfd/hi6421-spmi-pmic.h5
508 files changed, 69970 insertions, 37631 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40 b/Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
new file mode 100644
index 000000000000..469a7c00fad4
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
@@ -0,0 +1,31 @@
+What: /sys/bus/iio/devices/iio:deviceX/out_temp_raw
+Date: August 2021
+KernelVersion: 5.15
+Contact: Andreas Klinger <ak@it-klinger.de>
+Description:
+ Set the temperature. This value is sent to the sensor for
+ temperature compensation.
+ Default value: 25000 (25 °C)
+
+What: /sys/bus/iio/devices/iio:deviceX/out_humidityrelative_raw
+Date: August 2021
+KernelVersion: 5.15
+Contact: Andreas Klinger <ak@it-klinger.de>
+Description:
+ Set the relative humidity. This value is sent to the sensor for
+ humidity compensation.
+ Default value: 50000 (50 % relative humidity)
+
+What: /sys/bus/iio/devices/iio:deviceX/in_resistance_calibbias
+Date: August 2021
+KernelVersion: 5.15
+Contact: Andreas Klinger <ak@it-klinger.de>
+Description:
+ Set the bias value for the resistance which is used for
+ calculation of in_concentration_input as follows:
+
+ x = (in_resistance_raw - in_resistance_calibbias) * 0.65
+
+ in_concentration_input = 500 / (1 + e^x)
+
+ Default value: 30000
diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma180.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma180.yaml
deleted file mode 100644
index a7e84089cc3d..000000000000
--- a/Documentation/devicetree/bindings/iio/accel/bosch,bma180.yaml
+++ /dev/null
@@ -1,61 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/iio/accel/bosch,bma180.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Bosch BMA023 / BMA150/ BMA180 / BMA250 / SMB380 triaxial accelerometers
-
-maintainers:
- - Jonathan Cameron <jic23@kernel.org>
-
-description: |
- https://media.digikey.com/pdf/Data%20Sheets/Bosch/BMA150.pdf
- http://omapworld.com/BMA180_111_1002839.pdf
- http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf
-
-properties:
- compatible:
- enum:
- - bosch,bma023
- - bosch,bma150
- - bosch,bma180
- - bosch,bma250
- - bosch,smb380
-
- reg:
- maxItems: 1
-
- vdd-supply: true
-
- vddio-supply: true
-
- interrupts:
- minItems: 1
- maxItems: 2
- description: |
- Type should be either IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
- For the bma250 the first interrupt listed must be the one
- connected to the INT1 pin, the second (optional) interrupt
- listed must be the one connected to the INT2 pin.
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
-examples:
- - |
- #include <dt-bindings/interrupt-controller/irq.h>
- i2c {
- #address-cells = <1>;
- #size-cells = <0>;
- accel@40 {
- compatible = "bosch,bma180";
- reg = <0x40>;
- interrupt-parent = <&gpio6>;
- interrupts = <18 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>;
- };
- };
-...
diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml
index e830d5295b92..478e75ae0885 100644
--- a/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bma255.yaml
@@ -8,6 +8,7 @@ title: Bosch BMA255 and Similar Accelerometers
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
+ - Stephan Gerhold <stephan@gerhold.net>
description:
3 axis accelerometers with varying range and I2C or SPI
@@ -16,15 +17,24 @@ description:
properties:
compatible:
enum:
- - bosch,bmc150_accel
- - bosch,bmi055_accel
+ # bmc150-accel driver in Linux
+ - bosch,bma222
+ - bosch,bma222e
+ - bosch,bma250e
- bosch,bma253
- bosch,bma254
- bosch,bma255
- - bosch,bma250e
- - bosch,bma222
- - bosch,bma222e
- bosch,bma280
+ - bosch,bmc150_accel
+ - bosch,bmc156_accel
+ - bosch,bmi055_accel
+
+ # bma180 driver in Linux
+ - bosch,bma023
+ - bosch,bma150
+ - bosch,bma180
+ - bosch,bma250
+ - bosch,smb380
reg:
maxItems: 1
@@ -36,9 +46,21 @@ properties:
minItems: 1
maxItems: 2
description: |
- The first interrupt listed must be the one connected to the INT1 pin,
- the second (optional) interrupt listed must be the one connected to the
- INT2 pin (if available).
+ Without interrupt-names, the first interrupt listed must be the one
+ connected to the INT1 pin, the second (optional) interrupt listed must be
+ the one connected to the INT2 pin (if available). The type should be
+ IRQ_TYPE_EDGE_RISING.
+
+ BMC156 does not have an INT1 pin, therefore the first interrupt pin is
+ always treated as INT2.
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 2
+ items:
+ enum:
+ - INT1
+ - INT2
mount-matrix:
description: an optional 3x3 mounting rotation matrix.
@@ -63,7 +85,22 @@ examples:
reg = <0x08>;
vddio-supply = <&vddio>;
vdd-supply = <&vdd>;
- interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
+ interrupts = <57 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "INT1";
+ };
+ };
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ accelerometer@10 {
+ compatible = "bosch,bmc156_accel";
+ reg = <0x10>;
+ vddio-supply = <&vddio>;
+ vdd-supply = <&vdd>;
+ interrupts = <116 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "INT2";
};
};
- |
diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml
index 433a3fb55a2e..3eb7aa8822c3 100644
--- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.yaml
@@ -23,6 +23,8 @@ properties:
enum:
- ingenic,jz4725b-adc
- ingenic,jz4740-adc
+ - ingenic,jz4760-adc
+ - ingenic,jz4760b-adc
- ingenic,jz4770-adc
'#io-channel-cells':
@@ -43,6 +45,23 @@ properties:
interrupts:
maxItems: 1
+ ingenic,use-internal-divider:
+ description:
+ If present, battery voltage is read from the VBAT_IR pin, which has an
+ internal 1/4 divider. If absent, it is read through the VBAT_ER pin,
+ which does not have such a divider.
+ type: boolean
+
+if:
+ not:
+ properties:
+ compatible:
+ contains:
+ const: ingenic,jz4760b-adc
+then:
+ properties:
+ ingenic,use-internal-divider: false
+
required:
- compatible
- '#io-channel-cells'
diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
new file mode 100644
index 000000000000..c80201d6a716
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/renesas,rzg2l-adc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G2L ADC
+
+maintainers:
+ - Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+description: |
+ A/D Converter block is a successive approximation analog-to-digital converter
+ with a 12-bit accuracy. Up to eight analog input channels can be selected.
+ Conversions can be performed in single or repeat mode. Result of the ADC is
+ stored in a 32-bit data register corresponding to each channel.
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a07g044-adc # RZ/G2{L,LC}
+ - const: renesas,rzg2l-adc
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: converter clock
+ - description: peripheral clock
+
+ clock-names:
+ items:
+ - const: adclk
+ - const: pclk
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 2
+
+ reset-names:
+ items:
+ - const: presetn
+ - const: adrst-n
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - power-domains
+ - resets
+ - reset-names
+
+patternProperties:
+ "^channel@[0-7]$":
+ $ref: "adc.yaml"
+ type: object
+ description: |
+ Represents the external channels which are connected to the ADC.
+
+ properties:
+ reg:
+ description: |
+ The channel number. It can have up to 8 channels numbered from 0 to 7.
+ items:
+ - minimum: 0
+ maximum: 7
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/r9a07g044-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ adc: adc@10059000 {
+ compatible = "renesas,r9a07g044-adc", "renesas,rzg2l-adc";
+ reg = <0x10059000 0x400>;
+ interrupts = <GIC_SPI 347 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&cpg CPG_MOD R9A07G044_ADC_ADCLK>,
+ <&cpg CPG_MOD R9A07G044_ADC_PCLK>;
+ clock-names = "adclk", "pclk";
+ power-domains = <&cpg>;
+ resets = <&cpg R9A07G044_ADC_PRESETN>,
+ <&cpg R9A07G044_ADC_ADRST_N>;
+ reset-names = "presetn", "adrst-n";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0>;
+ };
+ channel@1 {
+ reg = <1>;
+ };
+ channel@2 {
+ reg = <2>;
+ };
+ channel@3 {
+ reg = <3>;
+ };
+ channel@4 {
+ reg = <4>;
+ };
+ channel@5 {
+ reg = <5>;
+ };
+ channel@6 {
+ reg = <6>;
+ };
+ channel@7 {
+ reg = <7>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml
index 1bb76197787b..e512a14e41b4 100644
--- a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.yaml
@@ -20,6 +20,7 @@ properties:
- rockchip,px30-saradc
- rockchip,rk3308-saradc
- rockchip,rk3328-saradc
+ - rockchip,rk3568-saradc
- rockchip,rv1108-saradc
- const: rockchip,rk3399-saradc
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5064.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5064.yaml
new file mode 100644
index 000000000000..05ed4e0ec364
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5064.yaml
@@ -0,0 +1,268 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5064.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5064 and similar DACs
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+description: |
+ A range of similar DAC devices with between 1 and 12 channels. Some parts
+ have internal references, others require a single shared external reference
+ and the remainder have a separate reference pin for each DAC.
+
+properties:
+ compatible:
+ oneOf:
+ - description: I2C devics
+ enum:
+ - adi,ad5024
+ - adi,ad5025
+ - adi,ad5044
+ - adi,ad5045
+ - adi,ad5064
+ - adi,ad5064-1
+ - adi,ad5065
+ - adi,ad5628-1
+ - adi,ad5628-2
+ - adi,ad5648-1
+ - adi,ad5648-2
+ - adi,ad5666-1
+ - adi,ad5666-2
+ - adi,ad5668-1
+ - adi,ad5668-2
+ - adi,ad5668-3
+ - description: SPI devices
+ enum:
+ - adi,ad5625
+ - adi,ad5625r-1v25
+ - adi,ad5625r-2v5
+ - adi,ad5627
+ - adi,ad5627r-1v25
+ - adi,ad5627r-2v5
+ - adi,ad5629-1
+ - adi,ad5629-2
+ - adi,ad5629-3
+ - adi,ad5645r-1v25
+ - adi,ad5645r-2v5
+ - adi,ad5665
+ - adi,ad5665r-1v25
+ - adi,ad5665r-2v5
+ - adi,ad5667
+ - adi,ad5667r-1v25
+ - adi,ad5667r-2v5
+ - adi,ad5669-1
+ - adi,ad5669-2
+ - adi,ad5669-3
+ - lltc,ltc2606
+ - lltc,ltc2607
+ - lltc,ltc2609
+ - lltc,ltc2616
+ - lltc,ltc2617
+ - lltc,ltc2619
+ - lltc,ltc2626
+ - lltc,ltc2627
+ - lltc,ltc2629
+ - lltc,ltc2631-l12
+ - lltc,ltc2631-h12
+ - lltc,ltc2631-l10
+ - lltc,ltc2631-h10
+ - lltc,ltc2631-l8
+ - lltc,ltc2631-h8
+ - lltc,ltc2633-l12
+ - lltc,ltc2633-h12
+ - lltc,ltc2633-l10
+ - lltc,ltc2633-h10
+ - lltc,ltc2633-l8
+ - lltc,ltc2633-h8
+ - lltc,ltc2635-l12
+ - lltc,ltc2635-h12
+ - lltc,ltc2635-l10
+ - lltc,ltc2635-h10
+ - lltc,ltc2635-l8
+ - lltc,ltc2635-h8
+
+ reg:
+ maxItems: 1
+
+ vrefA-supply: true
+ vrefB-supply: true
+ vrefC-supply: true
+ vrefD-supply: true
+ vref-supply: true
+
+ spi-max-frequency: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - # Shared external vref, no internal reference
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5064-1
+ - adi,ad5625
+ - adi,ad5627
+ - adi,ad5665
+ - adi,ad5667
+ - lltc,ltc2606
+ - lltc,ltc2607
+ - lltc,ltc2616
+ - lltc,ltc2617
+ - lltc,ltc2626
+ - lltc,ltc2627
+ then:
+ properties:
+ vref-supply: true
+ vrefA-supply: false
+ vrefB-supply: false
+ vrefC-supply: false
+ vrefD-supply: false
+ required:
+ - vref-supply
+ - # Shared external vref, internal reference available
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5625r-1v25
+ - adi,ad5625r-2v5
+ - adi,ad5627r-1v25
+ - adi,ad5627r-2v5
+ - adi,ad5628-1
+ - adi,ad5628-2
+ - adi,ad5629-1
+ - adi,ad5629-2
+ - adi,ad5629-3
+ - adi,ad5645r-1v25
+ - adi,ad5645r-2v5
+ - adi,ad5647r-1v25
+ - adi,ad5647r-2v5
+ - adi,ad5648-1
+ - adi,ad5648-2
+ - adi,ad5665r-1v25
+ - adi,ad5665r-2v5
+ - adi,ad5666-1
+ - adi,ad5666-2
+ - adi,ad5667r-1v25
+ - adi,ad5667r-2v5
+ - adi,ad5668-1
+ - adi,ad5668-2
+ - adi,ad5668-3
+ - adi,ad5669-1
+ - adi,ad5669-2
+ - adi,ad5669-3
+ - lltc,ltc2631-l12
+ - lltc,ltc2631-h12
+ - lltc,ltc2631-l10
+ - lltc,ltc2631-h10
+ - lltc,ltc2631-l8
+ - lltc,ltc2631-h8
+ - lltc,ltc2633-l12
+ - lltc,ltc2633-h12
+ - lltc,ltc2633-l10
+ - lltc,ltc2633-h10
+ - lltc,ltc2633-l8
+ - lltc,ltc2633-h8
+ - lltc,ltc2635-l12
+ - lltc,ltc2635-h12
+ - lltc,ltc2635-l10
+ - lltc,ltc2635-h10
+ - lltc,ltc2635-l8
+ - lltc,ltc2635-h8
+ then:
+ properties:
+ vref-supply: true
+ vrefA-supply: false
+ vrefB-supply: false
+ vrefC-supply: false
+ vrefD-supply: false
+ - # 4 input devices, separate vrefs, no internal reference
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5024
+ - adi,ad5044
+ - adi,ad5064
+ - lltc,ltc2609
+ - lltc,ltc2619
+ - lltc,ltc2629
+ then:
+ properties:
+ vrefA-supply: true
+ vrefB-supply: true
+ vrefC-supply: true
+ vrefD-supply: true
+ vref-supply: false
+ required:
+ - vrefA-supply
+ - vrefB-supply
+ - vrefC-supply
+ - vrefD-supply
+ - # 2 input devices, separate vrefs, no internal reference
+ if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5025
+ - adi,ad5045
+ - adi,ad5065
+ then:
+ properties:
+ vrefA-supply: true
+ vrefB-supply: true
+ vrefC-supply: false
+ vrefD-supply: false
+ vref-supply: false
+ required:
+ - vrefA-supply
+ - vrefB-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5625";
+ vref-supply = <&dac_vref>;
+ };
+ };
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5625r-1v25";
+ };
+ };
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@42 {
+ reg = <0x42>;
+ compatible = "adi,ad5024";
+ vrefA-supply = <&dac_vref>;
+ vrefB-supply = <&dac_vref>;
+ vrefC-supply = <&dac_vref2>;
+ vrefD-supply = <&dac_vref2>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5360.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5360.yaml
new file mode 100644
index 000000000000..0d8fb56f4b09
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5360.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5360.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5360 and similar DACs
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5360
+ - adi,ad5361
+ - adi,ad5363
+ - adi,ad5370
+ - adi,ad5371
+ - adi,ad5372
+ - adi,ad5373
+
+ reg:
+ maxItems: 1
+
+ vref0-supply: true
+ vref1-supply: true
+ vref2-supply: true
+
+ spi-max-frequency: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vref0-supply
+ - vref1-supply
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5360
+ - adi,ad5361
+ - adi,ad5363
+ - adi,ad5370
+ - adi,ad5372
+ - adi,ad5373
+ then:
+ properties:
+ vref2-supply: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5371
+ then:
+ required:
+ - vref2-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5371";
+ vref0-supply = <&dac_vref0>;
+ vref1-supply = <&dac_vref1>;
+ vref2-supply = <&dac_vref2>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml
new file mode 100644
index 000000000000..d599b418a020
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5380.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5380.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5380 and similar DACs
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+description: |
+ DAC devices supporting both SPI and I2C interfaces.
+properties:
+ compatible:
+ enum:
+ - adi,ad5380-3
+ - adi,ad5380-5
+ - adi,ad5381-3
+ - adi,ad5381-5
+ - adi,ad5382-3
+ - adi,ad5382-5
+ - adi,ad5383-3
+ - adi,ad5383-5
+ - adi,ad5384-3
+ - adi,ad5384-5
+ - adi,ad5390-3
+ - adi,ad5390-5
+ - adi,ad5391-3
+ - adi,ad5391-5
+ - adi,ad5392-3
+ - adi,ad5392-5
+
+ reg:
+ maxItems: 1
+
+ vref-supply:
+ description:
+ If not supplied devices will use internal regulators.
+
+ spi-max-frequency: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5390-5";
+ vref-supply = <&dacvref>;
+ };
+ };
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@42 {
+ reg = <0x42>;
+ compatible = "adi,ad5380-3";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5421.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5421.yaml
new file mode 100644
index 000000000000..188f656617e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5421.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5421.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5421 DAC
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+description: |
+ AD5421 is designed for us in loop-powered, 4 mA to 20 mA smart transmitter
+ applications. It provides a 16-bit DAC, current amplifier, voltage regulator
+ to drive the loop and a voltage reference.
+
+properties:
+ compatible:
+ const: adi,ad5421
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+ description: Fault signal.
+
+ spi-max-frequency: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5421";
+ reg = <0>;
+ spi-max-frequency = <30000000>;
+ interrupts = <55 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5449.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5449.yaml
new file mode 100644
index 000000000000..044332c97743
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5449.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5449.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5449 and similar DACs
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+description:
+ Family of multiplying DACs from Analog Devices
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5415
+ - adi,ad5426
+ - adi,ad5429
+ - adi,ad5432
+ - adi,ad5439
+ - adi,ad5443
+ - adi,ad5449
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ VREF-supply: true
+ VREFA-supply: true
+ VREFB-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5415
+ - adi,ad5426
+ - adi,ad5432
+ then:
+ properties:
+ VREF-supply: true
+ VREFA-supply: false
+ VREFB-supply: false
+ required:
+ - VREF-supply
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5429
+ - adi,ad5439
+ - adi,ad5449
+ then:
+ properties:
+ VREF-supply: false
+ VREFA-supply: true
+ VREFB-supply: true
+ required:
+ - VREFA-supply
+ - VREFB-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5415";
+ VREF-supply = <&dac_ref>;
+ };
+ };
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5429";
+ VREFA-supply = <&dac_refA>;
+ VREFB-supply = <&dac_refB>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5504.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5504.yaml
new file mode 100644
index 000000000000..9c2c038683b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5504.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5504.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5501 and AD5504 DACs
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+description:
+ High voltage (up to 60V) DACs with temperature sensor alarm function
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5501
+ - adi,ad5504
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ description: Used for temperature alarm.
+ maxItems: 1
+
+ vcc-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5504";
+ vcc-supply = <&dac_vcc>;
+ interrupts = <55 IRQ_TYPE_EDGE_FALLING>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5624r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5624r.yaml
new file mode 100644
index 000000000000..330383b85eeb
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5624r.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5624r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5624r and similar DACs
+
+maintainers:
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+ compatible:
+ enum:
+ - adi,ad5624r3
+ - adi,ad5644r3
+ - adi,ad5664r3
+ - adi,ad5624r5
+ - adi,ad5644r5
+ - adi,ad5664r5
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vref-supply:
+ description: If not present, internal reference will be used.
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5624r3";
+ vref-supply = <&vref>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml
new file mode 100644
index 000000000000..5c26441eae9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5686.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5686.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5360 and similar DACs
+
+maintainers:
+ - Michael Hennerich <michael.hennerich@analog.com>
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+ compatible:
+ oneOf:
+ - description: SPI devices
+ enum:
+ - adi,ad5310r
+ - adi,ad5672r
+ - adi,ad5674r
+ - adi,ad5676
+ - adi,ad5676r
+ - adi,ad5679r
+ - adi,ad5681r
+ - adi,ad5682r
+ - adi,ad5683
+ - adi,ad5683r
+ - adi,ad5684
+ - adi,ad5684r
+ - adi,ad5685r
+ - adi,ad5686
+ - adi,ad5686r
+ - description: I2C devices
+ enum:
+ - adi,ad5311r
+ - adi,ad5338r
+ - adi,ad5671r
+ - adi,ad5675r
+ - adi,ad5691r
+ - adi,ad5692r
+ - adi,ad5693
+ - adi,ad5693r
+ - adi,ad5694
+ - adi,ad5694r
+ - adi,ad5695r
+ - adi,ad5696
+ - adi,ad5696r
+
+
+ reg:
+ maxItems: 1
+
+ vcc-supply:
+ description: If not supplied the internal reference is used.
+
+ spi-max-frequency: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ dac@0 {
+ reg = <0>;
+ compatible = "adi,ad5310r";
+ vcc-supply = <&dac_vref0>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5761.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5761.yaml
new file mode 100644
index 000000000000..7f95a9ed55fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5761.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5761.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5761 and similar DACs
+
+maintainers:
+ - Ricardo Ribalda <ribalda@kernel.org>
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+
+ compatible:
+ enum:
+ - adi,ad5721
+ - adi,ad5721r
+ - adi,ad5761
+ - adi,ad5761r
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vref-supply:
+ description: If not supplied, internal reference will be used.
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5721
+ - adi,ad5761
+ then:
+ required:
+ - vref-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5721";
+ reg = <0>;
+ vref-supply = <&dac_vref>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5764.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5764.yaml
new file mode 100644
index 000000000000..8e893d52bfb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5764.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5764.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5744 and AD5764 DAC families
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+
+ compatible:
+ enum:
+ - adi,ad5744
+ - adi,ad5744r
+ - adi,ad5764
+ - adi,ad5764r
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vrefAB-supply: true
+ vrefCD-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad5744
+ - adi,ad5764
+ then:
+ required:
+ - vrefAB-supply
+ - vrefCD-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5744";
+ reg = <0>;
+ vrefAB-supply = <&dac_vref>;
+ vrefCD-supply = <&dac_vref>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml
new file mode 100644
index 000000000000..650d1ebdcec3
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5791.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5791 and similar DACs
+
+maintainers:
+ - Michael Hennerich <michael.hennerich@analog.com>
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+
+ compatible:
+ enum:
+ - adi,ad5760
+ - adi,ad5780
+ - adi,ad5781
+ - adi,ad5790
+ - adi,ad5791
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vdd-supply: true
+ vss-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vss-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad5791";
+ reg = <0>;
+ vss-supply = <&dac_vss>;
+ vdd-supply = <&dac_vdd>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad8801.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad8801.yaml
new file mode 100644
index 000000000000..6a3990a8d0ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad8801.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad8801.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD8801 and AD8803 DACs
+
+maintainers:
+ - Jonathan Cameron <jic23@kernel.org>
+
+properties:
+
+ compatible:
+ enum:
+ - adi,ad8801
+ - adi,ad8803
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vrefh-supply: true
+ vrefl-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vrefh-supply
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: adi,ad8803
+ then:
+ required:
+ - vrefl-supply
+ else:
+ properties:
+ vrefl-supply: false
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "adi,ad8803";
+ reg = <0>;
+ vrefl-supply = <&dac_vrefl>;
+ vrefh-supply = <&dac_vrefh>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp4922.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4922.yaml
new file mode 100644
index 000000000000..12a14b3f36cb
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4922.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/microchip,mcp4922.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip MCP4902, MCP4912 and MPC4922 dual output SPI DACs
+
+maintainers:
+ - Jonathan Cameron <jic23@kernel.org>
+ - Michael Welling <mwelling@ieee.org>
+
+properties:
+ compatible:
+ enum:
+ - microchip,mcp4902
+ - microchip,mcp4912
+ - microchip,mcp4922
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency: true
+
+ vref-supply: true
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - vref-supply
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "microchip,mcp4912";
+ reg = <0>;
+ vref-supply = <&dac_vref>;
+ };
+ };
+...
diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
index 8e355cddd437..22edcb4b212f 100644
--- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -34,13 +34,14 @@ properties:
interrupt-controller: true
- gpios:
+ interrupts:
maxItems: 1
- description: GPIO used for IRQs
regulators:
type: object
+ additionalProperties: false
+
properties:
'#address-cells':
const: 1
@@ -49,11 +50,13 @@ properties:
const: 0
patternProperties:
- '^ldo[0-9]+@[0-9a-f]$':
+ '^ldo[0-9]+$':
type: object
$ref: "/schemas/regulator/regulator.yaml#"
+ unevaluatedProperties: false
+
required:
- compatible
- reg
@@ -63,69 +66,69 @@ additionalProperties: false
examples:
- |
- /* pmic properties */
pmic: pmic@0 {
- compatible = "hisilicon,hi6421-spmi";
+ compatible = "hisilicon,hi6421v600-spmi";
reg = <0 0>;
#interrupt-cells = <2>;
interrupt-controller;
- gpios = <&gpio28 0 0>;
+ interrupt-parent = <&gpio28>;
+ interrupts = <0 0>;
regulators {
#address-cells = <1>;
#size-cells = <0>;
- ldo3: LDO3 {
+ ldo3: ldo3 {
regulator-name = "ldo3";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <2000000>;
regulator-boot-on;
};
- ldo4: LDO4 {
+ ldo4: ldo4 {
regulator-name = "ldo4";
regulator-min-microvolt = <1725000>;
regulator-max-microvolt = <1900000>;
regulator-boot-on;
};
- ldo9: LDO9 {
+ ldo9: ldo9 {
regulator-name = "ldo9";
regulator-min-microvolt = <1750000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
};
- ldo15: LDO15 {
+ ldo15: ldo15 {
regulator-name = "ldo15";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3000000>;
regulator-always-on;
};
- ldo16: LDO16 {
+ ldo16: ldo16 {
regulator-name = "ldo16";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3000000>;
regulator-boot-on;
};
- ldo17: LDO17 {
+ ldo17: ldo17 {
regulator-name = "ldo17";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
- ldo33: LDO33 {
+ ldo33: ldo33 {
regulator-name = "ldo33";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
};
- ldo34: LDO34 {
+ ldo34: ldo34 {
regulator-name = "ldo34";
regulator-min-microvolt = <2600000>;
regulator-max-microvolt = <3300000>;
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 919a4bf03a5a..fb03febc6616 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -33,6 +33,8 @@ properties:
- ad,ad7414
# ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems
- ad,adm9240
+ # AD5110 - Nonvolatile Digital Potentiometer
+ - adi,ad5110
# Analog Devices ADP5585 Keypad Decoder and I/O Expansion
- adi,adp5585
# Analog Devices ADP5585 Keypad Decoder and I/O Expansion with support for Row5
@@ -61,6 +63,8 @@ properties:
- capella,cm32181
# CM3232: Ambient Light Sensor
- capella,cm3232
+ # CM3323: Ambient Light Sensor
+ - capella,cm3323
# High-Precision Digital Thermometer
- dallas,ds1631
# Total-Elapsed-Time Recorder with Alarm
@@ -269,6 +273,8 @@ properties:
- sensirion,sgpc3
# Sensirion multi-pixel gas sensor with I2C interface
- sensirion,sgp30
+ # Sensirion gas sensor with I2C interface
+ - sensirion,sgp40
# Sensortek 3 axis accelerometer
- sensortek,stk8312
# Sensortek 3 axis accelerometer
diff --git a/MAINTAINERS b/MAINTAINERS
index f6914e5206fd..db76855aa3c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -459,6 +459,12 @@ S: Maintained
W: https://parisc.wiki.kernel.org/index.php/AD1889
F: sound/pci/ad1889.*
+AD5110 ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
+M: Mugilraj Dhavachelvan <dmugil2000@gmail.com>
+L: linux-iio@vger.kernel.org
+S: Supported
+F: drivers/iio/potentiometer/ad5110.c
+
AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
@@ -8462,10 +8468,12 @@ S: Maintained
F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
F: drivers/spmi/hisi-spmi-controller.c
-HISILICON STAGING DRIVERS FOR HIKEY 960/970
+HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+L: linux-kernel@vger.kernel.org
S: Maintained
-F: drivers/staging/hikey9xx/
+F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+F: drivers/mfd/hi6421-spmi-pmic.c
HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
M: Zaibo Xu <xuzaibo@huawei.com>
@@ -15899,6 +15907,14 @@ L: linux-renesas-soc@vger.kernel.org
S: Maintained
F: drivers/phy/renesas/phy-rcar-gen3-usb*.c
+RENESAS RZ/G2L A/D DRIVER
+M: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+L: linux-iio@vger.kernel.org
+L: linux-renesas-soc@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
+F: drivers/iio/adc/rzg2l_adc.c
+
RESET CONTROLLER FRAMEWORK
M: Philipp Zabel <p.zabel@pengutronix.de>
S: Maintained
@@ -16766,6 +16782,12 @@ F: drivers/iio/chemical/scd30_core.c
F: drivers/iio/chemical/scd30_i2c.c
F: drivers/iio/chemical/scd30_serial.c
+SENSIRION SGP40 GAS SENSOR DRIVER
+M: Andreas Klinger <ak@it-klinger.de>
+S: Maintained
+F: Documentation/ABI/testing/sysfs-bus-iio-chemical-sgp40
+F: drivers/iio/chemical/sgp40.c
+
SENSIRION SPS30 AIR POLLUTION SENSOR DRIVER
M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained
@@ -17670,8 +17692,9 @@ F: drivers/staging/olpc_dcon/
STAGING - REALTEK RTL8188EU DRIVERS
M: Larry Finger <Larry.Finger@lwfinger.net>
-S: Odd Fixes
-F: drivers/staging/rtl8188eu/
+M: Phillip Potter <phil@philpotter.co.uk>
+S: Supported
+F: drivers/staging/r8188eu/
STAGING - REALTEK RTL8712U DRIVERS
M: Larry Finger <Larry.Finger@lwfinger.net>
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 09a9a77cce06..0caa60537b14 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -28,6 +28,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
/**
* struct quad8 - device private data structure
+ * @lock: lock to prevent clobbering device states during R/W ops
* @counter: instance of the counter_device
* @fck_prescaler: array of filter clock prescaler configurations
* @preset: array of preset values
@@ -97,7 +98,8 @@ struct quad8 {
#define QUAD8_CMR_QUADRATURE_X4 0x18
static int quad8_signal_read(struct counter_device *counter,
- struct counter_signal *signal, enum counter_signal_value *val)
+ struct counter_signal *signal,
+ enum counter_signal_level *level)
{
const struct quad8 *const priv = counter->priv;
unsigned int state;
@@ -109,7 +111,7 @@ static int quad8_signal_read(struct counter_device *counter,
state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
& BIT(signal->id - 16);
- *val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
+ *level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
return 0;
}
@@ -154,7 +156,7 @@ static int quad8_count_write(struct counter_device *counter,
/* Only 24-bit values are supported */
if (val > 0xFFFFFF)
- return -EINVAL;
+ return -ERANGE;
mutex_lock(&priv->lock);
@@ -193,11 +195,11 @@ enum quad8_count_function {
QUAD8_COUNT_FUNCTION_QUADRATURE_X4
};
-static const enum counter_count_function quad8_count_functions_list[] = {
- [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
- [QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
- [QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
- [QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
+static const enum counter_function quad8_count_functions_list[] = {
+ [QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_FUNCTION_PULSE_DIRECTION,
+ [QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_FUNCTION_QUADRATURE_X1_A,
+ [QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_FUNCTION_QUADRATURE_X2_A,
+ [QUAD8_COUNT_FUNCTION_QUADRATURE_X4] = COUNTER_FUNCTION_QUADRATURE_X4
};
static int quad8_function_get(struct counter_device *counter,
@@ -273,6 +275,10 @@ static int quad8_function_set(struct counter_device *counter,
*scale = 2;
mode_cfg |= QUAD8_CMR_QUADRATURE_X4;
break;
+ default:
+ /* should never reach this path */
+ mutex_unlock(&priv->lock);
+ return -EINVAL;
}
}
@@ -349,7 +355,7 @@ static int quad8_action_get(struct counter_device *counter,
case QUAD8_COUNT_FUNCTION_PULSE_DIRECTION:
if (synapse->signal->id == signal_a_id)
*action = QUAD8_SYNAPSE_ACTION_RISING_EDGE;
- break;
+ return 0;
case QUAD8_COUNT_FUNCTION_QUADRATURE_X1:
if (synapse->signal->id == signal_a_id) {
quad8_direction_get(counter, count, &direction);
@@ -359,17 +365,18 @@ static int quad8_action_get(struct counter_device *counter,
else
*action = QUAD8_SYNAPSE_ACTION_FALLING_EDGE;
}
- break;
+ return 0;
case QUAD8_COUNT_FUNCTION_QUADRATURE_X2:
if (synapse->signal->id == signal_a_id)
*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
- break;
+ return 0;
case QUAD8_COUNT_FUNCTION_QUADRATURE_X4:
*action = QUAD8_SYNAPSE_ACTION_BOTH_EDGES;
- break;
+ return 0;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
-
- return 0;
}
static const struct counter_ops quad8_ops = {
@@ -529,6 +536,9 @@ static int quad8_count_mode_set(struct counter_device *counter,
case COUNTER_COUNT_MODE_MODULO_N:
cnt_mode = 3;
break;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
mutex_lock(&priv->lock);
@@ -661,7 +671,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,
/* Only 24-bit values are supported */
if (preset > 0xFFFFFF)
- return -EINVAL;
+ return -ERANGE;
mutex_lock(&priv->lock);
@@ -706,7 +716,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
/* Only 24-bit values are supported */
if (ceiling > 0xFFFFFF)
- return -EINVAL;
+ return -ERANGE;
mutex_lock(&priv->lock);
@@ -715,12 +725,13 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,
case 1:
case 3:
quad8_preset_register_set(priv, count->id, ceiling);
- break;
+ mutex_unlock(&priv->lock);
+ return len;
}
mutex_unlock(&priv->lock);
- return len;
+ return -EINVAL;
}
static ssize_t quad8_count_preset_enable_read(struct counter_device *counter,
diff --git a/drivers/counter/counter.c b/drivers/counter/counter.c
index 6a683d086008..de921e8a3f72 100644
--- a/drivers/counter/counter.c
+++ b/drivers/counter/counter.c
@@ -289,9 +289,9 @@ struct counter_signal_unit {
struct counter_signal *signal;
};
-static const char *const counter_signal_value_str[] = {
- [COUNTER_SIGNAL_LOW] = "low",
- [COUNTER_SIGNAL_HIGH] = "high"
+static const char *const counter_signal_level_str[] = {
+ [COUNTER_SIGNAL_LEVEL_LOW] = "low",
+ [COUNTER_SIGNAL_LEVEL_HIGH] = "high"
};
static ssize_t counter_signal_show(struct device *dev,
@@ -302,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev,
const struct counter_signal_unit *const component = devattr->component;
struct counter_signal *const signal = component->signal;
int err;
- enum counter_signal_value val;
+ enum counter_signal_level level;
- err = counter->ops->signal_read(counter, signal, &val);
+ err = counter->ops->signal_read(counter, signal, &level);
if (err)
return err;
- return sprintf(buf, "%s\n", counter_signal_value_str[val]);
+ return sprintf(buf, "%s\n", counter_signal_level_str[level]);
}
struct counter_name_unit {
@@ -744,15 +744,15 @@ static ssize_t counter_count_store(struct device *dev,
return len;
}
-static const char *const counter_count_function_str[] = {
- [COUNTER_COUNT_FUNCTION_INCREASE] = "increase",
- [COUNTER_COUNT_FUNCTION_DECREASE] = "decrease",
- [COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
- [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
- [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
- [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
- [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
- [COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4"
+static const char *const counter_function_str[] = {
+ [COUNTER_FUNCTION_INCREASE] = "increase",
+ [COUNTER_FUNCTION_DECREASE] = "decrease",
+ [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
+ [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
+ [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
+ [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
+ [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
+ [COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
};
static ssize_t counter_function_show(struct device *dev,
@@ -764,7 +764,7 @@ static ssize_t counter_function_show(struct device *dev,
const struct counter_count_unit *const component = devattr->component;
struct counter_count *const count = component->count;
size_t func_index;
- enum counter_count_function function;
+ enum counter_function function;
err = counter->ops->function_get(counter, count, &func_index);
if (err)
@@ -773,7 +773,7 @@ static ssize_t counter_function_show(struct device *dev,
count->function = func_index;
function = count->functions_list[func_index];
- return sprintf(buf, "%s\n", counter_count_function_str[function]);
+ return sprintf(buf, "%s\n", counter_function_str[function]);
}
static ssize_t counter_function_store(struct device *dev,
@@ -785,14 +785,14 @@ static ssize_t counter_function_store(struct device *dev,
struct counter_count *const count = component->count;
const size_t num_functions = count->num_functions;
size_t func_index;
- enum counter_count_function function;
+ enum counter_function function;
int err;
struct counter_device *const counter = dev_get_drvdata(dev);
/* Find requested Count function mode */
for (func_index = 0; func_index < num_functions; func_index++) {
function = count->functions_list[func_index];
- if (sysfs_streq(buf, counter_count_function_str[function]))
+ if (sysfs_streq(buf, counter_function_str[function]))
break;
}
/* Return error if requested Count function mode not found */
@@ -880,25 +880,25 @@ err_free_attr_list:
}
struct counter_func_avail_unit {
- const enum counter_count_function *functions_list;
+ const enum counter_function *functions_list;
size_t num_functions;
};
-static ssize_t counter_count_function_available_show(struct device *dev,
+static ssize_t counter_function_available_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct counter_device_attr *const devattr = to_counter_attr(attr);
const struct counter_func_avail_unit *const component = devattr->component;
- const enum counter_count_function *const func_list = component->functions_list;
+ const enum counter_function *const func_list = component->functions_list;
const size_t num_functions = component->num_functions;
size_t i;
- enum counter_count_function function;
+ enum counter_function function;
ssize_t len = 0;
for (i = 0; i < num_functions; i++) {
function = func_list[i];
len += sprintf(buf + len, "%s\n",
- counter_count_function_str[function]);
+ counter_function_str[function]);
}
return len;
@@ -968,7 +968,7 @@ static int counter_count_attributes_create(
parm.group = group;
parm.prefix = "";
parm.name = "function_available";
- parm.show = counter_count_function_available_show;
+ parm.show = counter_function_available_show;
parm.store = NULL;
parm.component = avail_comp;
err = counter_attribute_create(&parm);
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
index 9371532406ca..53c15f84909b 100644
--- a/drivers/counter/ftm-quaddec.c
+++ b/drivers/counter/ftm-quaddec.c
@@ -171,9 +171,8 @@ enum ftm_quaddec_count_function {
FTM_QUADDEC_COUNT_ENCODER_MODE_1,
};
-static const enum counter_count_function ftm_quaddec_count_functions[] = {
- [FTM_QUADDEC_COUNT_ENCODER_MODE_1] =
- COUNTER_COUNT_FUNCTION_QUADRATURE_X4
+static const enum counter_function ftm_quaddec_count_functions[] = {
+ [FTM_QUADDEC_COUNT_ENCODER_MODE_1] = COUNTER_FUNCTION_QUADRATURE_X4
};
static int ftm_quaddec_count_read(struct counter_device *counter,
diff --git a/drivers/counter/intel-qep.c b/drivers/counter/intel-qep.c
index 8d7ae28fbd67..8a6847d5fb2b 100644
--- a/drivers/counter/intel-qep.c
+++ b/drivers/counter/intel-qep.c
@@ -8,7 +8,6 @@
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
* Author: Raymond Tan <raymond.tan@intel.com>
*/
-#include <linux/bitops.h>
#include <linux/counter.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -127,8 +126,8 @@ static int intel_qep_count_read(struct counter_device *counter,
return 0;
}
-static const enum counter_count_function intel_qep_count_functions[] = {
- COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
+static const enum counter_function intel_qep_count_functions[] = {
+ COUNTER_FUNCTION_QUADRATURE_X4,
};
static int intel_qep_function_get(struct counter_device *counter,
@@ -320,7 +319,7 @@ static ssize_t spike_filter_ns_write(struct counter_device *counter,
}
if (length > INTEL_QEPFLT_MAX_COUNT(length))
- return -EINVAL;
+ return -ERANGE;
mutex_lock(&qep->lock);
if (qep->enabled) {
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
index 5df7cd13d4c7..1de4243db488 100644
--- a/drivers/counter/interrupt-cnt.c
+++ b/drivers/counter/interrupt-cnt.c
@@ -107,13 +107,16 @@ static int interrupt_cnt_write(struct counter_device *counter,
{
struct interrupt_cnt_priv *priv = counter->priv;
+ if (val != (typeof(priv->count.counter))val)
+ return -ERANGE;
+
atomic_set(&priv->count, val);
return 0;
}
-static const enum counter_count_function interrupt_cnt_functions[] = {
- COUNTER_COUNT_FUNCTION_INCREASE,
+static const enum counter_function interrupt_cnt_functions[] = {
+ COUNTER_FUNCTION_INCREASE,
};
static int interrupt_cnt_function_get(struct counter_device *counter,
@@ -127,7 +130,7 @@ static int interrupt_cnt_function_get(struct counter_device *counter,
static int interrupt_cnt_signal_read(struct counter_device *counter,
struct counter_signal *signal,
- enum counter_signal_value *val)
+ enum counter_signal_level *level)
{
struct interrupt_cnt_priv *priv = counter->priv;
int ret;
@@ -139,7 +142,7 @@ static int interrupt_cnt_signal_read(struct counter_device *counter,
if (ret < 0)
return ret;
- *val = ret ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
+ *level = ret ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
return 0;
}
diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
index 51b8af80f98b..1aa70b9c4833 100644
--- a/drivers/counter/microchip-tcb-capture.c
+++ b/drivers/counter/microchip-tcb-capture.c
@@ -37,9 +37,9 @@ enum mchp_tc_count_function {
MCHP_TC_FUNCTION_QUADRATURE,
};
-static const enum counter_count_function mchp_tc_count_functions[] = {
- [MCHP_TC_FUNCTION_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
- [MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
+static const enum counter_function mchp_tc_count_functions[] = {
+ [MCHP_TC_FUNCTION_INCREASE] = COUNTER_FUNCTION_INCREASE,
+ [MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_FUNCTION_QUADRATURE_X4,
};
enum mchp_tc_synapse_action {
@@ -133,6 +133,9 @@ static int mchp_tc_count_function_set(struct counter_device *counter,
bmr |= ATMEL_TC_QDEN | ATMEL_TC_POSEN;
cmr |= ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_ABETRG | ATMEL_TC_XC0;
break;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
regmap_write(priv->regmap, ATMEL_TC_BMR, bmr);
@@ -155,7 +158,7 @@ static int mchp_tc_count_function_set(struct counter_device *counter,
static int mchp_tc_count_signal_read(struct counter_device *counter,
struct counter_signal *signal,
- enum counter_signal_value *val)
+ enum counter_signal_level *lvl)
{
struct mchp_tc_data *const priv = counter->priv;
bool sigstatus;
@@ -168,7 +171,7 @@ static int mchp_tc_count_signal_read(struct counter_device *counter,
else
sigstatus = (sr & ATMEL_TC_MTIOA);
- *val = sigstatus ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
+ *lvl = sigstatus ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
return 0;
}
@@ -226,6 +229,9 @@ static int mchp_tc_count_action_set(struct counter_device *counter,
case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:
edge = ATMEL_TC_ETRGEDG_BOTH;
break;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
return regmap_write_bits(priv->regmap,
diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c
index c19d998df5ba..13656957c45f 100644
--- a/drivers/counter/stm32-lptimer-cnt.c
+++ b/drivers/counter/stm32-lptimer-cnt.c
@@ -134,9 +134,9 @@ enum stm32_lptim_cnt_function {
STM32_LPTIM_ENCODER_BOTH_EDGE,
};
-static const enum counter_count_function stm32_lptim_cnt_functions[] = {
- [STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
- [STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
+static const enum counter_function stm32_lptim_cnt_functions[] = {
+ [STM32_LPTIM_COUNTER_INCREASE] = COUNTER_FUNCTION_INCREASE,
+ [STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_FUNCTION_QUADRATURE_X4,
};
enum stm32_lptim_synapse_action {
@@ -206,9 +206,10 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,
priv->quadrature_mode = 1;
priv->polarity = STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES;
return 0;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
-
- return -EINVAL;
}
static ssize_t stm32_lptim_cnt_enable_read(struct counter_device *counter,
@@ -282,7 +283,7 @@ static ssize_t stm32_lptim_cnt_ceiling_write(struct counter_device *counter,
return ret;
if (ceiling > STM32_LPTIM_MAX_ARR)
- return -EINVAL;
+ return -ERANGE;
priv->ceiling = ceiling;
@@ -326,9 +327,10 @@ static int stm32_lptim_cnt_action_get(struct counter_device *counter,
case STM32_LPTIM_ENCODER_BOTH_EDGE:
*action = priv->polarity;
return 0;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
-
- return -EINVAL;
}
static int stm32_lptim_cnt_action_set(struct counter_device *counter,
diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c
index 603b30ada839..3fb0debd7425 100644
--- a/drivers/counter/stm32-timer-cnt.c
+++ b/drivers/counter/stm32-timer-cnt.c
@@ -50,11 +50,11 @@ enum stm32_count_function {
STM32_COUNT_ENCODER_MODE_3,
};
-static const enum counter_count_function stm32_count_functions[] = {
- [STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
- [STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
- [STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
- [STM32_COUNT_ENCODER_MODE_3] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
+static const enum counter_function stm32_count_functions[] = {
+ [STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_FUNCTION_INCREASE,
+ [STM32_COUNT_ENCODER_MODE_1] = COUNTER_FUNCTION_QUADRATURE_X2_A,
+ [STM32_COUNT_ENCODER_MODE_2] = COUNTER_FUNCTION_QUADRATURE_X2_B,
+ [STM32_COUNT_ENCODER_MODE_3] = COUNTER_FUNCTION_QUADRATURE_X4,
};
static int stm32_count_read(struct counter_device *counter,
diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c
index 65df9ef5b5bc..94fe58bb3eab 100644
--- a/drivers/counter/ti-eqep.c
+++ b/drivers/counter/ti-eqep.c
@@ -157,7 +157,7 @@ static int ti_eqep_action_get(struct counter_device *counter,
* QEPA and QEPB trigger QCLK.
*/
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
- break;
+ return 0;
case TI_EQEP_COUNT_FUNC_DIR_COUNT:
/* In direction-count mode only rising edge of QEPA is counted
* and QEPB gives direction.
@@ -165,12 +165,14 @@ static int ti_eqep_action_get(struct counter_device *counter,
switch (synapse->signal->id) {
case TI_EQEP_SIGNAL_QEPA:
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
- break;
- default:
+ return 0;
+ case TI_EQEP_SIGNAL_QEPB:
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
- break;
+ return 0;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
- break;
case TI_EQEP_COUNT_FUNC_UP_COUNT:
case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
/* In up/down-count modes only QEPA is counted and QEPB is not
@@ -186,15 +188,18 @@ static int ti_eqep_action_get(struct counter_device *counter,
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
else
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
- break;
- default:
+ return 0;
+ case TI_EQEP_SIGNAL_QEPB:
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
- break;
+ return 0;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
- break;
+ default:
+ /* should never reach this path */
+ return -EINVAL;
}
-
- return 0;
}
static const struct counter_ops ti_eqep_counter_ops = {
@@ -289,11 +294,11 @@ static struct counter_signal ti_eqep_signals[] = {
},
};
-static const enum counter_count_function ti_eqep_position_functions[] = {
- [TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
- [TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
- [TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_COUNT_FUNCTION_INCREASE,
- [TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_COUNT_FUNCTION_DECREASE,
+static const enum counter_function ti_eqep_position_functions[] = {
+ [TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_FUNCTION_QUADRATURE_X4,
+ [TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_FUNCTION_PULSE_DIRECTION,
+ [TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_FUNCTION_INCREASE,
+ [TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_FUNCTION_DECREASE,
};
static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8d8b1ba42ff8..a0e9061f6d6b 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -143,10 +143,11 @@ config BMC150_ACCEL
select BMC150_ACCEL_SPI if SPI
help
Say yes here to build support for the following Bosch accelerometers:
- BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMI055.
+ BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMC156
+ BMI055.
Note that some of these are combo modules:
- - BMC150: accelerometer and magnetometer
+ - BMC150/BMC156: accelerometer and magnetometer
- BMI055: accelerometer and gyroscope
This driver is only implementing accelerometer part, which has
diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
index 384497776b67..af0fdd02c4f2 100644
--- a/drivers/iio/accel/adxl345.h
+++ b/drivers/iio/accel/adxl345.h
@@ -15,6 +15,5 @@ enum adxl345_device_type {
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
enum adxl345_device_type type, const char *name);
-int adxl345_core_remove(struct device *dev);
#endif /* _ADXL345_H_ */
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 312866530065..4b275051ef61 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -208,6 +208,11 @@ static const struct iio_info adxl345_info = {
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
};
+static void adxl345_powerdown(void *regmap)
+{
+ regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
+}
+
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
enum adxl345_device_type type, const char *name)
{
@@ -233,7 +238,6 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
return -ENOMEM;
data = iio_priv(indio_dev);
- dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
data->type = type;
/* Enable full-resolution mode */
@@ -260,29 +264,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
return ret;
}
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(dev, "iio_device_register failed: %d\n", ret);
- regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
- ADXL345_POWER_CTL_STANDBY);
- }
+ ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
+ if (ret < 0)
+ return ret;
- return ret;
+ return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(adxl345_core_probe);
-int adxl345_core_remove(struct device *dev)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct adxl345_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- return regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
- ADXL345_POWER_CTL_STANDBY);
-}
-EXPORT_SYMBOL_GPL(adxl345_core_remove);
-
MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index 1561364ae296..a431cba216e6 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -38,11 +38,6 @@ static int adxl345_i2c_probe(struct i2c_client *client,
id->name);
}
-static int adxl345_i2c_remove(struct i2c_client *client)
-{
- return adxl345_core_remove(&client->dev);
-}
-
static const struct i2c_device_id adxl345_i2c_id[] = {
{ "adxl345", ADXL345 },
{ "adxl375", ADXL375 },
@@ -65,7 +60,6 @@ static struct i2c_driver adxl345_i2c_driver = {
.of_match_table = adxl345_of_match,
},
.probe = adxl345_i2c_probe,
- .remove = adxl345_i2c_remove,
.id_table = adxl345_i2c_id,
};
diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
index da4591c7ef23..ea559ac2e87d 100644
--- a/drivers/iio/accel/adxl345_spi.c
+++ b/drivers/iio/accel/adxl345_spi.c
@@ -42,11 +42,6 @@ static int adxl345_spi_probe(struct spi_device *spi)
return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name);
}
-static int adxl345_spi_remove(struct spi_device *spi)
-{
- return adxl345_core_remove(&spi->dev);
-}
-
static const struct spi_device_id adxl345_spi_id[] = {
{ "adxl345", ADXL345 },
{ "adxl375", ADXL375 },
@@ -69,7 +64,6 @@ static struct spi_driver adxl345_spi_driver = {
.of_match_table = adxl345_of_match,
},
.probe = adxl345_spi_probe,
- .remove = adxl345_spi_remove,
.id_table = adxl345_spi_id,
};
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 0622c7936499..bc4c626e454d 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -218,20 +218,33 @@ static int bma220_init(struct spi_device *spi)
return 0;
}
-static int bma220_deinit(struct spi_device *spi)
+static int bma220_power(struct spi_device *spi, bool up)
{
- int ret;
-
- /* Make sure the chip is powered off */
- ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
- if (ret == BMA220_SUSPEND_SLEEP)
+ int i, ret;
+
+ /**
+ * The chip can be suspended/woken up by a simple register read.
+ * So, we need up to 2 register reads of the suspend register
+ * to make sure that the device is in the desired state.
+ */
+ for (i = 0; i < 2; i++) {
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
- if (ret < 0)
- return ret;
- if (ret == BMA220_SUSPEND_SLEEP)
- return -EBUSY;
+ if (ret < 0)
+ return ret;
- return 0;
+ if (up && ret == BMA220_SUSPEND_SLEEP)
+ return 0;
+
+ if (!up && ret == BMA220_SUSPEND_WAKE)
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+static void bma220_deinit(void *spi)
+{
+ bma220_power(spi, false);
}
static int bma220_probe(struct spi_device *spi)
@@ -248,7 +261,6 @@ static int bma220_probe(struct spi_device *spi)
data = iio_priv(indio_dev);
data->spi_device = spi;
- spi_set_drvdata(spi, indio_dev);
mutex_init(&data->lock);
indio_dev->info = &bma220_info;
@@ -262,49 +274,33 @@ static int bma220_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
- bma220_trigger_handler, NULL);
- if (ret < 0) {
- dev_err(&spi->dev, "iio triggered buffer setup failed\n");
- goto err_suspend;
- }
+ ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi);
+ if (ret)
+ return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ iio_pollfunc_store_time,
+ bma220_trigger_handler, NULL);
if (ret < 0) {
- dev_err(&spi->dev, "iio_device_register failed\n");
- iio_triggered_buffer_cleanup(indio_dev);
- goto err_suspend;
+ dev_err(&spi->dev, "iio triggered buffer setup failed\n");
+ return ret;
}
- return 0;
-
-err_suspend:
- return bma220_deinit(spi);
-}
-
-static int bma220_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
-
- return bma220_deinit(spi);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static __maybe_unused int bma220_suspend(struct device *dev)
{
- struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
+ struct spi_device *spi = to_spi_device(dev);
- /* The chip can be suspended/woken up by a simple register read. */
- return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
+ return bma220_power(spi, false);
}
static __maybe_unused int bma220_resume(struct device *dev)
{
- struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
+ struct spi_device *spi = to_spi_device(dev);
- return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
+ return bma220_power(spi, true);
}
static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
@@ -326,7 +322,6 @@ static struct spi_driver bma220_driver = {
.acpi_match_table = bma220_acpi_id,
},
.probe = bma220_probe,
- .remove = bma220_remove,
.id_table = bma220_spi_id,
};
module_spi_driver(bma220_driver);
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index 5ce384ebe6c7..e8693a42ad46 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/of_irq.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
@@ -57,12 +58,18 @@
#define BMC150_ACCEL_RESET_VAL 0xB6
#define BMC150_ACCEL_REG_INT_MAP_0 0x19
-#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2)
+#define BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE BIT(2)
#define BMC150_ACCEL_REG_INT_MAP_1 0x1A
-#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0)
-#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1)
-#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA BIT(0)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM BIT(1)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT1_FFULL BIT(2)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FFULL BIT(5)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM BIT(6)
+#define BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA BIT(7)
+
+#define BMC150_ACCEL_REG_INT_MAP_2 0x1B
+#define BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE BIT(2)
#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21
#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80
@@ -81,6 +88,7 @@
#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20
#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0)
+#define BMC150_ACCEL_INT_OUT_CTRL_INT2_LVL BIT(2)
#define BMC150_ACCEL_REG_INT_5 0x27
#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03
@@ -476,21 +484,24 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
}
#endif
-static const struct bmc150_accel_interrupt_info {
+struct bmc150_accel_interrupt_info {
u8 map_reg;
u8 map_bitmask;
u8 en_reg;
u8 en_bitmask;
-} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = {
+};
+
+static const struct bmc150_accel_interrupt_info
+bmc150_accel_interrupts_int1[BMC150_ACCEL_INTERRUPTS] = {
{ /* data ready interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
- .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_DATA,
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
},
{ /* motion interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_0,
- .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_INT1_SLOPE,
.en_reg = BMC150_ACCEL_REG_INT_EN_0,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
@@ -498,19 +509,56 @@ static const struct bmc150_accel_interrupt_info {
},
{ /* fifo watermark interrupt */
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
- .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT1_FWM,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_1,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
+ },
+};
+
+static const struct bmc150_accel_interrupt_info
+bmc150_accel_interrupts_int2[BMC150_ACCEL_INTERRUPTS] = {
+ { /* data ready interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_DATA,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_1,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN,
+ },
+ { /* motion interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_2,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_2_BIT_INT2_SLOPE,
+ .en_reg = BMC150_ACCEL_REG_INT_EN_0,
+ .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X |
+ BMC150_ACCEL_INT_EN_BIT_SLP_Y |
+ BMC150_ACCEL_INT_EN_BIT_SLP_Z
+ },
+ { /* fifo watermark interrupt */
+ .map_reg = BMC150_ACCEL_REG_INT_MAP_1,
+ .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_INT2_FWM,
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
},
};
static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
- struct bmc150_accel_data *data)
+ struct bmc150_accel_data *data, int irq)
{
+ const struct bmc150_accel_interrupt_info *irq_info = NULL;
+ struct device *dev = regmap_get_device(data->regmap);
int i;
+ /*
+ * For now we map all interrupts to the same output pin.
+ * However, some boards may have just INT2 (and not INT1) connected,
+ * so we try to detect which IRQ it is based on the interrupt-names.
+ * Without interrupt-names, we assume the irq belongs to INT1.
+ */
+ irq_info = bmc150_accel_interrupts_int1;
+ if (data->type == BOSCH_BMC156 ||
+ irq == of_irq_get_byname(dev->of_node, "INT2"))
+ irq_info = bmc150_accel_interrupts_int2;
+
for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++)
- data->interrupts[i].info = &bmc150_accel_interrupts[i];
+ data->interrupts[i].info = &irq_info[i];
}
static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
@@ -1127,7 +1175,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{306458, BMC150_ACCEL_DEF_RANGE_16G} },
},
{
- .name = "BMA253/BMA254/BMA255/BMC150/BMI055",
+ .name = "BMA253/BMA254/BMA255/BMC150/BMC156/BMI055",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@@ -1614,7 +1662,8 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
}
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
- const char *name, bool block_supported)
+ enum bmc150_type type, const char *name,
+ bool block_supported)
{
const struct attribute **fifo_attrs;
struct bmc150_accel_data *data;
@@ -1629,6 +1678,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
+ data->type = type;
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
ret = iio_read_mount_matrix(dev, &data->orientation);
@@ -1714,7 +1764,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
goto err_buffer_cleanup;
}
- bmc150_accel_interrupts_setup(indio_dev, data);
+ bmc150_accel_interrupts_setup(indio_dev, data, irq);
ret = bmc150_accel_triggers_setup(indio_dev, data);
if (ret)
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index 999495f0669d..88bd8a25f142 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -176,6 +176,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
{
struct regmap *regmap;
const char *name = NULL;
+ enum bmc150_type type = BOSCH_UNKNOWN;
bool block_supported =
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
i2c_check_functionality(client->adapter,
@@ -188,10 +189,13 @@ static int bmc150_accel_probe(struct i2c_client *client,
return PTR_ERR(regmap);
}
- if (id)
+ if (id) {
name = id->name;
+ type = id->driver_data;
+ }
- ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, block_supported);
+ ret = bmc150_accel_core_probe(&client->dev, regmap, client->irq,
+ type, name, block_supported);
if (ret)
return ret;
@@ -236,6 +240,7 @@ static const struct i2c_device_id bmc150_accel_id[] = {
{"bma255"},
{"bma280"},
{"bmc150_accel"},
+ {"bmc156_accel", BOSCH_BMC156},
{"bmi055_accel"},
{}
};
@@ -251,6 +256,7 @@ static const struct of_device_id bmc150_accel_of_match[] = {
{ .compatible = "bosch,bma255" },
{ .compatible = "bosch,bma280" },
{ .compatible = "bosch,bmc150_accel" },
+ { .compatible = "bosch,bmc156_accel" },
{ .compatible = "bosch,bmi055_accel" },
{ },
};
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 54b8c9c8068b..191e312dc91a 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -16,6 +16,8 @@
static int bmc150_accel_probe(struct spi_device *spi)
{
struct regmap *regmap;
+ const char *name = NULL;
+ enum bmc150_type type = BOSCH_UNKNOWN;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf);
@@ -24,7 +26,12 @@ static int bmc150_accel_probe(struct spi_device *spi)
return PTR_ERR(regmap);
}
- return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
+ if (id) {
+ name = id->name;
+ type = id->driver_data;
+ }
+
+ return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, type, name,
true);
}
@@ -54,6 +61,7 @@ static const struct spi_device_id bmc150_accel_id[] = {
{"bma255"},
{"bma280"},
{"bmc150_accel"},
+ {"bmc156_accel", BOSCH_BMC156},
{"bmi055_accel"},
{}
};
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
index 47121f070fe9..1bb5023e8ed9 100644
--- a/drivers/iio/accel/bmc150-accel.h
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -13,6 +13,22 @@ struct i2c_client;
struct bmc150_accel_chip_info;
struct bmc150_accel_interrupt_info;
+/*
+ * We can often guess better than "UNKNOWN" based on the device IDs
+ * but unfortunately this information is not always accurate. There are some
+ * devices where ACPI firmware specifies an ID like "BMA250E" when the device
+ * actually has a BMA222E. The driver attempts to detect those by reading the
+ * chip ID from the registers but this information is not always enough either.
+ *
+ * Therefore, this enum should be only used when the chip ID detection is not
+ * enough and we can be reasonably sure that the device IDs are reliable
+ * in practice (e.g. for device tree platforms).
+ */
+enum bmc150_type {
+ BOSCH_UNKNOWN,
+ BOSCH_BMC156,
+};
+
struct bmc150_accel_interrupt {
const struct bmc150_accel_interrupt_info *info;
atomic_t users;
@@ -62,6 +78,7 @@ struct bmc150_accel_data {
int ev_enable_state;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
const struct bmc150_accel_chip_info *chip_info;
+ enum bmc150_type type;
struct i2c_client *second_device;
void (*resume_callback)(struct device *dev);
struct delayed_work resume_work;
@@ -69,7 +86,8 @@ struct bmc150_accel_data {
};
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
- const char *name, bool block_supported);
+ enum bmc150_type type, const char *name,
+ bool block_supported);
int bmc150_accel_core_remove(struct device *dev);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c
index 5edff9ba72da..9633bdae5fd4 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -100,6 +100,11 @@ static enum da280_chipset da280_match_acpi_device(struct device *dev)
return (enum da280_chipset) id->driver_data;
}
+static void da280_disable(void *client)
+{
+ da280_enable(client, false);
+}
+
static int da280_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -118,7 +123,6 @@ static int da280_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->client = client;
- i2c_set_clientdata(client, indio_dev);
indio_dev->info = &da280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -142,22 +146,11 @@ static int da280_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "device_register failed\n");
- da280_enable(client, false);
- }
-
- return ret;
-}
-
-static int da280_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action_or_reset(&client->dev, da280_disable, client);
+ if (ret)
+ return ret;
- return da280_enable(client, false);
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -194,7 +187,6 @@ static struct i2c_driver da280_driver = {
.pm = &da280_pm_ops,
},
.probe = da280_probe,
- .remove = da280_remove,
.id_table = da280_i2c_id,
};
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index 92593a1cd1aa..04e13487e706 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -212,6 +212,11 @@ static const struct iio_info da311_info = {
.read_raw = da311_read_raw,
};
+static void da311_disable(void *client)
+{
+ da311_enable(client, false);
+}
+
static int da311_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -229,7 +234,6 @@ static int da311_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->client = client;
- i2c_set_clientdata(client, indio_dev);
indio_dev->info = &da311_info;
indio_dev->name = "da311";
@@ -245,22 +249,11 @@ static int da311_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "device_register failed\n");
- da311_enable(client, false);
- }
-
- return ret;
-}
-
-static int da311_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action_or_reset(&client->dev, da311_disable, client);
+ if (ret)
+ return ret;
- return da311_enable(client, false);
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -289,7 +282,6 @@ static struct i2c_driver da311_driver = {
.pm = &da311_pm_ops,
},
.probe = da311_probe,
- .remove = da311_remove,
.id_table = da311_i2c_id,
};
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index e84bf8db1e89..f9f173eec202 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -170,6 +170,11 @@ static const struct iio_info dmard10_info = {
.read_raw = dmard10_read_raw,
};
+static void dmard10_shutdown_cleanup(void *client)
+{
+ dmard10_shutdown(client);
+}
+
static int dmard10_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -194,7 +199,6 @@ static int dmard10_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->client = client;
- i2c_set_clientdata(client, indio_dev);
indio_dev->info = &dmard10_info;
indio_dev->name = "dmard10";
@@ -206,22 +210,12 @@ static int dmard10_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0) {
- dev_err(&client->dev, "device_register failed\n");
- dmard10_shutdown(client);
- }
-
- return ret;
-}
-
-static int dmard10_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action_or_reset(&client->dev, dmard10_shutdown_cleanup,
+ client);
+ if (ret)
+ return ret;
- return dmard10_shutdown(client);
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -250,7 +244,6 @@ static struct i2c_driver dmard10_driver = {
.pm = &dmard10_pm_ops,
},
.probe = dmard10_probe,
- .remove = dmard10_remove,
.id_table = dmard10_i2c_id,
};
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 55cdca818b3b..a2def6f9380a 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -367,7 +367,8 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
- indio_dev->channels = kmemdup(channel_spec, channel_size, GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, channel_spec,
+ channel_size, GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
@@ -378,7 +379,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
hsdev->usage, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->info = &accel_3d_info;
@@ -391,7 +392,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
&accel_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -416,8 +417,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -431,7 +430,6 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index f5b0b8bbaff7..8750dea56fcb 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -64,7 +64,6 @@ enum st_accel_type {
#ifdef CONFIG_IIO_BUFFER
int st_accel_allocate_ring(struct iio_dev *indio_dev);
-void st_accel_deallocate_ring(struct iio_dev *indio_dev);
int st_accel_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_ACCEL_TRIGGER_SET_STATE (&st_accel_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
@@ -72,9 +71,6 @@ static inline int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
-static inline void st_accel_deallocate_ring(struct iio_dev *indio_dev)
-{
-}
#define ST_ACCEL_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c
index 492263589e04..fc82fa83f1fb 100644
--- a/drivers/iio/accel/st_accel_buffer.c
+++ b/drivers/iio/accel/st_accel_buffer.c
@@ -9,14 +9,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
@@ -67,13 +62,8 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
- return iio_triggered_buffer_setup(indio_dev, NULL,
- &st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
-}
-
-void st_accel_deallocate_ring(struct iio_dev *indio_dev)
-{
- iio_triggered_buffer_cleanup(indio_dev);
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 28fceac9f2f6..f1e6ec380667 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -9,17 +9,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/acpi.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/common/st_sensors.h>
#include "st_accel.h"
@@ -1381,7 +1377,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
err = st_sensors_allocate_trigger(indio_dev,
ST_ACCEL_TRIGGER_OPS);
if (err < 0)
- goto st_accel_probe_trigger_error;
+ return err;
}
err = iio_device_register(indio_dev);
@@ -1396,8 +1392,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
st_accel_device_register_error:
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-st_accel_probe_trigger_error:
- st_accel_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_accel_common_probe);
@@ -1409,8 +1403,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
iio_device_unregister(indio_dev);
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-
- st_accel_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_accel_common_remove);
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index 95e305b88d5e..f711756e41e3 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -9,11 +9,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
-#include <linux/property.h>
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_accel.h"
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 83d3308ce5cc..bb45d9ff95b8 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index db0c8fb60515..af168e1c9fdb 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -887,6 +887,16 @@ config ROCKCHIP_SARADC
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
+config RZG2L_ADC
+ tristate "Renesas RZ/G2L ADC driver"
+ depends on ARCH_R9A07G044 || COMPILE_TEST
+ help
+ Say yes here to build support for the ADC found in Renesas
+ RZ/G2L family.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rzg2l_adc.
+
config SC27XX_ADC
tristate "Spreadtrum SC27xx series PMICs ADC"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index f70d877c555a..d68550f493e3 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
+obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
obj-$(CONFIG_STX104) += stx104.o
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
index a10a4e8d94fd..8edd6407b7c3 100644
--- a/drivers/iio/adc/ep93xx_adc.c
+++ b/drivers/iio/adc/ep93xx_adc.c
@@ -205,7 +205,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
*/
}
- ret = clk_enable(priv->clk);
+ ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(&pdev->dev, "Cannot enable clock\n");
return ret;
@@ -213,7 +213,7 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
ret = iio_device_register(iiodev);
if (ret)
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return ret;
}
@@ -224,7 +224,7 @@ static int ep93xx_adc_remove(struct platform_device *pdev)
struct ep93xx_adc_priv *priv = iio_priv(iiodev);
iio_device_unregister(iiodev);
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return 0;
}
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index ab5139e911c3..329c555b55cc 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -201,11 +201,11 @@ static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
*/
priv->vref[MX25_ADC_REFP_INT] = NULL;
priv->vref[MX25_ADC_REFP_EXT] =
- devm_regulator_get_optional(&pdev->dev, "vref-ext");
+ devm_regulator_get_optional(dev, "vref-ext");
priv->vref[MX25_ADC_REFP_XP] =
- devm_regulator_get_optional(&pdev->dev, "vref-xp");
+ devm_regulator_get_optional(dev, "vref-xp");
priv->vref[MX25_ADC_REFP_YP] =
- devm_regulator_get_optional(&pdev->dev, "vref-yp");
+ devm_regulator_get_optional(dev, "vref-yp");
for_each_child_of_node(np, child) {
u32 reg;
@@ -307,7 +307,7 @@ static int mx25_gcq_probe(struct platform_device *pdev)
int ret;
int i;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
@@ -347,14 +347,11 @@ static int mx25_gcq_probe(struct platform_device *pdev)
goto err_vref_disable;
}
- priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq <= 0) {
- ret = priv->irq;
- if (!ret)
- ret = -ENXIO;
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
goto err_clk_unprepare;
- }
+ priv->irq = ret;
ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv);
if (ret) {
dev_err(dev, "Failed requesting IRQ\n");
diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
index 34c03a264f74..2b3912c6ca6b 100644
--- a/drivers/iio/adc/ingenic-adc.c
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -37,6 +37,7 @@
#define JZ_ADC_REG_CFG_SAMPLE_NUM(n) ((n) << 10)
#define JZ_ADC_REG_CFG_PULL_UP(n) ((n) << 16)
#define JZ_ADC_REG_CFG_CMD_SEL BIT(22)
+#define JZ_ADC_REG_CFG_VBAT_SEL BIT(30)
#define JZ_ADC_REG_CFG_TOUCH_OPS_MASK (BIT(31) | GENMASK(23, 10))
#define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0
#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16
@@ -71,6 +72,7 @@
#define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
#define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
#define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
+#define JZ4760_ADC_BATTERY_VREF 2500
#define JZ4770_ADC_BATTERY_VREF 1200
#define JZ4770_ADC_BATTERY_VREF_BITS 12
@@ -92,7 +94,7 @@ struct ingenic_adc_soc_data {
const int *battery_scale_avail;
size_t battery_scale_avail_size;
unsigned int battery_vref_mode: 1;
- unsigned int has_aux2: 1;
+ unsigned int has_aux_md: 1;
const struct iio_chan_spec *channels;
unsigned int num_channels;
int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
@@ -295,6 +297,10 @@ static const int jz4740_adc_battery_scale_avail[] = {
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
+static const int jz4760_adc_battery_scale_avail[] = {
+ JZ4760_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
+};
+
static const int jz4770_adc_battery_raw_avail[] = {
0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
};
@@ -400,6 +406,47 @@ static const struct iio_chan_spec jz4740_channels[] = {
},
};
+static const struct iio_chan_spec jz4760_channels[] = {
+ {
+ .extend_name = "aux",
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+ .channel = INGENIC_ADC_AUX0,
+ .scan_index = -1,
+ },
+ {
+ .extend_name = "aux1",
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+ .channel = INGENIC_ADC_AUX,
+ .scan_index = -1,
+ },
+ {
+ .extend_name = "aux2",
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+ .channel = INGENIC_ADC_AUX2,
+ .scan_index = -1,
+ },
+ {
+ .extend_name = "battery",
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+ .channel = INGENIC_ADC_BATTERY,
+ .scan_index = -1,
+ },
+};
+
static const struct iio_chan_spec jz4770_channels[] = {
{
.type = IIO_VOLTAGE,
@@ -506,7 +553,7 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
.battery_scale_avail = jz4725b_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
.battery_vref_mode = true,
- .has_aux2 = false,
+ .has_aux_md = false,
.channels = jz4740_channels,
.num_channels = ARRAY_SIZE(jz4740_channels),
.init_clk_div = jz4725b_adc_init_clk_div,
@@ -520,12 +567,26 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
.battery_scale_avail = jz4740_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
.battery_vref_mode = true,
- .has_aux2 = false,
+ .has_aux_md = false,
.channels = jz4740_channels,
.num_channels = ARRAY_SIZE(jz4740_channels),
.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
};
+static const struct ingenic_adc_soc_data jz4760_adc_soc_data = {
+ .battery_high_vref = JZ4760_ADC_BATTERY_VREF,
+ .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
+ .battery_raw_avail = jz4770_adc_battery_raw_avail,
+ .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
+ .battery_scale_avail = jz4760_adc_battery_scale_avail,
+ .battery_scale_avail_size = ARRAY_SIZE(jz4760_adc_battery_scale_avail),
+ .battery_vref_mode = false,
+ .has_aux_md = true,
+ .channels = jz4760_channels,
+ .num_channels = ARRAY_SIZE(jz4760_channels),
+ .init_clk_div = jz4770_adc_init_clk_div,
+};
+
static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
@@ -534,7 +595,7 @@ static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
.battery_scale_avail = jz4770_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
.battery_vref_mode = false,
- .has_aux2 = true,
+ .has_aux_md = true,
.channels = jz4770_channels,
.num_channels = ARRAY_SIZE(jz4770_channels),
.init_clk_div = jz4770_adc_init_clk_div,
@@ -569,7 +630,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val)
{
- int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
+ int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
struct ingenic_adc *adc = iio_priv(iio_dev);
ret = clk_enable(adc->clk);
@@ -579,11 +640,22 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
return ret;
}
- /* We cannot sample AUX/AUX2 in parallel. */
+ /* We cannot sample the aux channels in parallel. */
mutex_lock(&adc->aux_lock);
- if (adc->soc_data->has_aux2 && engine == 0) {
- bit = BIT(chan->channel == INGENIC_ADC_AUX2);
- ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
+ if (adc->soc_data->has_aux_md && engine == 0) {
+ switch (chan->channel) {
+ case INGENIC_ADC_AUX0:
+ cmd = 0;
+ break;
+ case INGENIC_ADC_AUX:
+ cmd = 1;
+ break;
+ case INGENIC_ADC_AUX2:
+ cmd = 2;
+ break;
+ }
+
+ ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, cmd);
}
ret = ingenic_adc_capture(adc, engine);
@@ -591,6 +663,7 @@ static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev,
goto out;
switch (chan->channel) {
+ case INGENIC_ADC_AUX0:
case INGENIC_ADC_AUX:
case INGENIC_ADC_AUX2:
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
@@ -621,6 +694,7 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
return ingenic_adc_read_chan_info_raw(iio_dev, chan, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
+ case INGENIC_ADC_AUX0:
case INGENIC_ADC_AUX:
case INGENIC_ADC_AUX2:
*val = JZ_ADC_AUX_VREF;
@@ -806,6 +880,14 @@ static int ingenic_adc_probe(struct platform_device *pdev)
/* Put hardware in a known passive state. */
writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
+
+ /* JZ4760B specific */
+ if (device_property_present(dev, "ingenic,use-internal-divider"))
+ ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL,
+ JZ_ADC_REG_CFG_VBAT_SEL);
+ else
+ ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, 0);
+
usleep_range(2000, 3000); /* Must wait at least 2ms. */
clk_disable(adc->clk);
@@ -832,6 +914,8 @@ static int ingenic_adc_probe(struct platform_device *pdev)
static const struct of_device_id ingenic_adc_of_match[] = {
{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
+ { .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, },
+ { .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, },
{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
{ },
};
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 66dc452d643a..705d5e11a54b 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -347,7 +347,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
int regval, fifo_chan, fifo_val, count;
- if(!wait_for_completion_timeout(&priv->done,
+ if (!wait_for_completion_timeout(&priv->done,
msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT)))
return -ETIMEDOUT;
@@ -497,8 +497,8 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration) {
/* prevent BL30 from using the SAR ADC while we are using it */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
/*
* wait until BL30 releases it's lock (so we can use the SAR
@@ -525,7 +525,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
if (priv->param->has_bl30_integration)
/* allow BL30 to use the SAR ADC again */
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
- MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
mutex_unlock(&indio_dev->mlock);
}
@@ -791,7 +791,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
* on the vendor driver), which we don't support at the moment.
*/
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
- MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
/* disable all channels by default */
regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
@@ -1104,6 +1104,14 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
.resolution = 12,
};
+static const struct meson_sar_adc_param meson_sar_adc_g12a_param = {
+ .has_bl30_integration = false,
+ .clock_rate = 1200000,
+ .bandgap_reg = MESON_SAR_ADC_REG11,
+ .regmap_config = &meson_sar_adc_regmap_config_gxbb,
+ .resolution = 12,
+};
+
static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
.param = &meson_sar_adc_meson8_param,
.name = "meson-meson8-saradc",
@@ -1140,7 +1148,7 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
};
static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
- .param = &meson_sar_adc_gxl_param,
+ .param = &meson_sar_adc_g12a_param,
.name = "meson-g12a-saradc",
};
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 12584f1631d8..a237fe469a30 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -35,7 +35,7 @@
#define SARADC_DLY_PU_SOC_MASK 0x3f
#define SARADC_TIMEOUT msecs_to_jiffies(100)
-#define SARADC_MAX_CHANNELS 6
+#define SARADC_MAX_CHANNELS 8
struct rockchip_saradc_data {
const struct iio_chan_spec *channels;
@@ -49,10 +49,12 @@ struct rockchip_saradc {
struct clk *clk;
struct completion completion;
struct regulator *vref;
+ int uv_vref;
struct reset_control *reset;
const struct rockchip_saradc_data *data;
u16 last_val;
const struct iio_chan_spec *last_chan;
+ struct notifier_block nb;
};
static void rockchip_saradc_power_down(struct rockchip_saradc *info)
@@ -105,13 +107,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = regulator_get_voltage(info->vref);
- if (ret < 0) {
- dev_err(&indio_dev->dev, "failed to get voltage\n");
- return ret;
- }
-
- *val = ret / 1000;
+ *val = info->uv_vref / 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
@@ -192,6 +188,23 @@ static const struct rockchip_saradc_data rk3399_saradc_data = {
.clk_rate = 1000000,
};
+static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = {
+ SARADC_CHANNEL(0, "adc0", 10),
+ SARADC_CHANNEL(1, "adc1", 10),
+ SARADC_CHANNEL(2, "adc2", 10),
+ SARADC_CHANNEL(3, "adc3", 10),
+ SARADC_CHANNEL(4, "adc4", 10),
+ SARADC_CHANNEL(5, "adc5", 10),
+ SARADC_CHANNEL(6, "adc6", 10),
+ SARADC_CHANNEL(7, "adc7", 10),
+};
+
+static const struct rockchip_saradc_data rk3568_saradc_data = {
+ .channels = rockchip_rk3568_saradc_iio_channels,
+ .num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels),
+ .clk_rate = 1000000,
+};
+
static const struct of_device_id rockchip_saradc_match[] = {
{
.compatible = "rockchip,saradc",
@@ -202,6 +215,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
}, {
.compatible = "rockchip,rk3399-saradc",
.data = &rk3399_saradc_data,
+ }, {
+ .compatible = "rockchip,rk3568-saradc",
+ .data = &rk3568_saradc_data,
},
{},
};
@@ -278,6 +294,26 @@ out:
return IRQ_HANDLED;
}
+static int rockchip_saradc_volt_notify(struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ struct rockchip_saradc *info =
+ container_of(nb, struct rockchip_saradc, nb);
+
+ if (event & REGULATOR_EVENT_VOLTAGE_CHANGE)
+ info->uv_vref = (unsigned long)data;
+
+ return NOTIFY_OK;
+}
+
+static void rockchip_saradc_regulator_unreg_notifier(void *data)
+{
+ struct rockchip_saradc *info = data;
+
+ regulator_unregister_notifier(info->vref, &info->nb);
+}
+
static int rockchip_saradc_probe(struct platform_device *pdev)
{
struct rockchip_saradc *info = NULL;
@@ -390,6 +426,12 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
return ret;
}
+ ret = regulator_get_voltage(info->vref);
+ if (ret < 0)
+ return ret;
+
+ info->uv_vref = ret;
+
ret = clk_prepare_enable(info->pclk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable pclk\n");
@@ -430,6 +472,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (ret)
return ret;
+ info->nb.notifier_call = rockchip_saradc_volt_notify;
+ ret = regulator_register_notifier(info->vref, &info->nb);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&pdev->dev,
+ rockchip_saradc_regulator_unreg_notifier,
+ info);
+ if (ret)
+ return ret;
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
new file mode 100644
index 000000000000..9996d5eef289
--- /dev/null
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G2L A/D Converter driver
+ *
+ * Copyright (c) 2021 Renesas Electronics Europe GmbH
+ *
+ * Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#define DRIVER_NAME "rzg2l-adc"
+
+#define RZG2L_ADM(n) ((n) * 0x4)
+#define RZG2L_ADM0_ADCE BIT(0)
+#define RZG2L_ADM0_ADBSY BIT(1)
+#define RZG2L_ADM0_PWDWNB BIT(2)
+#define RZG2L_ADM0_SRESB BIT(15)
+#define RZG2L_ADM1_TRG BIT(0)
+#define RZG2L_ADM1_MS BIT(2)
+#define RZG2L_ADM1_BS BIT(4)
+#define RZG2L_ADM1_EGA_MASK GENMASK(13, 12)
+#define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0)
+#define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24)
+#define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16)
+#define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe)
+#define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0)
+
+#define RZG2L_ADINT 0x20
+#define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0)
+#define RZG2L_ADINT_CSEEN BIT(16)
+#define RZG2L_ADINT_INTS BIT(31)
+
+#define RZG2L_ADSTS 0x24
+#define RZG2L_ADSTS_CSEST BIT(16)
+#define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0)
+
+#define RZG2L_ADIVC 0x28
+#define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0)
+#define RZG2L_ADIVC_DIVADC_4 FIELD_PREP(RZG2L_ADIVC_DIVADC_MASK, 0x4)
+
+#define RZG2L_ADFIL 0x2c
+
+#define RZG2L_ADCR(n) (0x30 + ((n) * 0x4))
+#define RZG2L_ADCR_AD_MASK GENMASK(11, 0)
+
+#define RZG2L_ADSMP_DEFUALT_SAMPLING 0x578
+
+#define RZG2L_ADC_MAX_CHANNELS 8
+#define RZG2L_ADC_CHN_MASK 0x7
+#define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4)
+
+struct rzg2l_adc_data {
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+};
+
+struct rzg2l_adc {
+ void __iomem *base;
+ struct clk *pclk;
+ struct clk *adclk;
+ struct reset_control *presetn;
+ struct reset_control *adrstn;
+ struct completion completion;
+ const struct rzg2l_adc_data *data;
+ struct mutex lock;
+ u16 last_val[RZG2L_ADC_MAX_CHANNELS];
+};
+
+static const char * const rzg2l_adc_channel_name[] = {
+ "adc0",
+ "adc1",
+ "adc2",
+ "adc3",
+ "adc4",
+ "adc5",
+ "adc6",
+ "adc7",
+};
+
+static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg)
+{
+ return readl(adc->base + reg);
+}
+
+static void rzg2l_adc_writel(struct rzg2l_adc *adc, unsigned int reg, u32 val)
+{
+ writel(val, adc->base + reg);
+}
+
+static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on)
+{
+ u32 reg;
+
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
+ if (on)
+ reg |= RZG2L_ADM0_PWDWNB;
+ else
+ reg &= ~RZG2L_ADM0_PWDWNB;
+ rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
+ udelay(2);
+}
+
+static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
+{
+ int timeout = 5;
+ u32 reg;
+
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
+ if (start)
+ reg |= RZG2L_ADM0_ADCE;
+ else
+ reg &= ~RZG2L_ADM0_ADCE;
+ rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
+
+ if (start)
+ return;
+
+ do {
+ usleep_range(100, 200);
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
+ timeout--;
+ if (!timeout) {
+ pr_err("%s stopping ADC timed out\n", __func__);
+ break;
+ }
+ } while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE)));
+}
+
+static void rzg2l_set_trigger(struct rzg2l_adc *adc)
+{
+ u32 reg;
+
+ /*
+ * Setup ADM1 for SW trigger
+ * EGA[13:12] - Set 00 to indicate hardware trigger is invalid
+ * BS[4] - Enable 1-buffer mode
+ * MS[1] - Enable Select mode
+ * TRG[0] - Enable software trigger mode
+ */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(1));
+ reg &= ~RZG2L_ADM1_EGA_MASK;
+ reg &= ~RZG2L_ADM1_BS;
+ reg &= ~RZG2L_ADM1_TRG;
+ reg |= RZG2L_ADM1_MS;
+ rzg2l_adc_writel(adc, RZG2L_ADM(1), reg);
+}
+
+static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
+{
+ u32 reg;
+
+ if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY)
+ return -EBUSY;
+
+ rzg2l_set_trigger(adc);
+
+ /* Select analog input channel subjected to conversion. */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
+ reg &= ~RZG2L_ADM2_CHSEL_MASK;
+ reg |= BIT(ch);
+ rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
+
+ /*
+ * Setup ADINT
+ * INTS[31] - Select pulse signal
+ * CSEEN[16] - Enable channel select error interrupt
+ * INTEN[7:0] - Select channel interrupt
+ */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADINT);
+ reg &= ~RZG2L_ADINT_INTS;
+ reg &= ~RZG2L_ADINT_INTEN_MASK;
+ reg |= (RZG2L_ADINT_CSEEN | BIT(ch));
+ rzg2l_adc_writel(adc, RZG2L_ADINT, reg);
+
+ return 0;
+}
+
+static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on)
+{
+ struct device *dev = indio_dev->dev.parent;
+
+ if (on)
+ return pm_runtime_resume_and_get(dev);
+
+ return pm_runtime_put_sync(dev);
+}
+
+static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch)
+{
+ int ret;
+
+ ret = rzg2l_adc_set_power(indio_dev, true);
+ if (ret)
+ return ret;
+
+ ret = rzg2l_adc_conversion_setup(adc, ch);
+ if (ret) {
+ rzg2l_adc_set_power(indio_dev, false);
+ return ret;
+ }
+
+ reinit_completion(&adc->completion);
+
+ rzg2l_adc_start_stop(adc, true);
+
+ if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) {
+ rzg2l_adc_writel(adc, RZG2L_ADINT,
+ rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK);
+ rzg2l_adc_start_stop(adc, false);
+ rzg2l_adc_set_power(indio_dev, false);
+ return -ETIMEDOUT;
+ }
+
+ return rzg2l_adc_set_power(indio_dev, false);
+}
+
+static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct rzg2l_adc *adc = iio_priv(indio_dev);
+ int ret;
+ u8 ch;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_VOLTAGE)
+ return -EINVAL;
+
+ mutex_lock(&adc->lock);
+ ch = chan->channel & RZG2L_ADC_CHN_MASK;
+ ret = rzg2l_adc_conversion(indio_dev, adc, ch);
+ if (ret) {
+ mutex_unlock(&adc->lock);
+ return ret;
+ }
+ *val = adc->last_val[ch];
+ mutex_unlock(&adc->lock);
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rzg2l_adc_read_label(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ char *label)
+{
+ if (chan->channel >= RZG2L_ADC_MAX_CHANNELS)
+ return -EINVAL;
+
+ return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]);
+}
+
+static const struct iio_info rzg2l_adc_iio_info = {
+ .read_raw = rzg2l_adc_read_raw,
+ .read_label = rzg2l_adc_read_label,
+};
+
+static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
+{
+ struct rzg2l_adc *adc = dev_id;
+ unsigned long intst;
+ u32 reg;
+ int ch;
+
+ reg = rzg2l_adc_readl(adc, RZG2L_ADSTS);
+
+ /* A/D conversion channel select error interrupt */
+ if (reg & RZG2L_ADSTS_CSEST) {
+ rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
+ return IRQ_HANDLED;
+ }
+
+ intst = reg & RZG2L_ADSTS_INTST_MASK;
+ if (!intst)
+ return IRQ_NONE;
+
+ for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS)
+ adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
+
+ /* clear the channel interrupt */
+ rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
+
+ complete(&adc->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
+{
+ struct iio_chan_spec *chan_array;
+ struct fwnode_handle *fwnode;
+ struct rzg2l_adc_data *data;
+ unsigned int channel;
+ int num_channels;
+ int ret;
+ u8 i;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ num_channels = device_get_child_node_count(&pdev->dev);
+ if (!num_channels) {
+ dev_err(&pdev->dev, "no channel children\n");
+ return -ENODEV;
+ }
+
+ if (num_channels > RZG2L_ADC_MAX_CHANNELS) {
+ dev_err(&pdev->dev, "num of channel children out of range\n");
+ return -EINVAL;
+ }
+
+ chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
+ GFP_KERNEL);
+ if (!chan_array)
+ return -ENOMEM;
+
+ i = 0;
+ device_for_each_child_node(&pdev->dev, fwnode) {
+ ret = fwnode_property_read_u32(fwnode, "reg", &channel);
+ if (ret)
+ return ret;
+
+ if (channel >= RZG2L_ADC_MAX_CHANNELS)
+ return -EINVAL;
+
+ chan_array[i].type = IIO_VOLTAGE;
+ chan_array[i].indexed = 1;
+ chan_array[i].channel = channel;
+ chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel];
+ i++;
+ }
+
+ data->num_channels = num_channels;
+ data->channels = chan_array;
+ adc->data = data;
+
+ return 0;
+}
+
+static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
+{
+ int timeout = 5;
+ u32 reg;
+ int ret;
+
+ ret = clk_prepare_enable(adc->pclk);
+ if (ret)
+ return ret;
+
+ /* SW reset */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
+ reg |= RZG2L_ADM0_SRESB;
+ rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
+
+ while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) {
+ if (!timeout) {
+ ret = -EBUSY;
+ goto exit_hw_init;
+ }
+ timeout--;
+ usleep_range(100, 200);
+ }
+
+ /* Only division by 4 can be set */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
+ reg &= ~RZG2L_ADIVC_DIVADC_MASK;
+ reg |= RZG2L_ADIVC_DIVADC_4;
+ rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
+
+ /*
+ * Setup AMD3
+ * ADIL[31:24] - Should be always set to 0
+ * ADCMP[23:16] - Should be always set to 0xe
+ * ADSMP[15:0] - Set default (0x578) sampling period
+ */
+ reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
+ reg &= ~RZG2L_ADM3_ADIL_MASK;
+ reg &= ~RZG2L_ADM3_ADCMP_MASK;
+ reg &= ~RZG2L_ADM3_ADSMP_MASK;
+ reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFUALT_SAMPLING);
+ rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
+
+exit_hw_init:
+ clk_disable_unprepare(adc->pclk);
+
+ return 0;
+}
+
+static void rzg2l_adc_pm_runtime_disable(void *data)
+{
+ struct device *dev = data;
+
+ pm_runtime_disable(dev->parent);
+}
+
+static void rzg2l_adc_pm_runtime_set_suspended(void *data)
+{
+ struct device *dev = data;
+
+ pm_runtime_set_suspended(dev->parent);
+}
+
+static void rzg2l_adc_reset_assert(void *data)
+{
+ reset_control_assert(data);
+}
+
+static int rzg2l_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct rzg2l_adc *adc;
+ int ret;
+ int irq;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(indio_dev);
+
+ ret = rzg2l_adc_parse_properties(pdev, adc);
+ if (ret)
+ return ret;
+
+ mutex_init(&adc->lock);
+
+ adc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(adc->base))
+ return PTR_ERR(adc->base);
+
+ adc->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(adc->pclk)) {
+ dev_err(dev, "Failed to get pclk");
+ return PTR_ERR(adc->pclk);
+ }
+
+ adc->adclk = devm_clk_get(dev, "adclk");
+ if (IS_ERR(adc->adclk)) {
+ dev_err(dev, "Failed to get adclk");
+ return PTR_ERR(adc->adclk);
+ }
+
+ adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n");
+ if (IS_ERR(adc->adrstn)) {
+ dev_err(dev, "failed to get adrstn\n");
+ return PTR_ERR(adc->adrstn);
+ }
+
+ adc->presetn = devm_reset_control_get_exclusive(dev, "presetn");
+ if (IS_ERR(adc->presetn)) {
+ dev_err(dev, "failed to get presetn\n");
+ return PTR_ERR(adc->presetn);
+ }
+
+ ret = reset_control_deassert(adc->adrstn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&pdev->dev,
+ rzg2l_adc_reset_assert, adc->adrstn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = reset_control_deassert(adc->presetn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&pdev->dev,
+ rzg2l_adc_reset_assert, adc->presetn);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = rzg2l_adc_hw_init(adc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq resource\n");
+ return irq;
+ }
+
+ ret = devm_request_irq(dev, irq, rzg2l_adc_isr,
+ 0, dev_name(dev), adc);
+ if (ret < 0)
+ return ret;
+
+ init_completion(&adc->completion);
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ indio_dev->name = DRIVER_NAME;
+ indio_dev->info = &rzg2l_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = adc->data->channels;
+ indio_dev->num_channels = adc->data->num_channels;
+
+ pm_runtime_set_suspended(dev);
+ ret = devm_add_action_or_reset(&pdev->dev,
+ rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(dev);
+ ret = devm_add_action_or_reset(&pdev->dev,
+ rzg2l_adc_pm_runtime_disable, &indio_dev->dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id rzg2l_adc_match[] = {
+ { .compatible = "renesas,rzg2l-adc",},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
+
+static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct rzg2l_adc *adc = iio_priv(indio_dev);
+
+ rzg2l_adc_pwr(adc, false);
+ clk_disable_unprepare(adc->adclk);
+ clk_disable_unprepare(adc->pclk);
+
+ return 0;
+}
+
+static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct rzg2l_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = clk_prepare_enable(adc->pclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(adc->adclk);
+ if (ret)
+ return ret;
+
+ rzg2l_adc_pwr(adc, true);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rzg2l_adc_pm_ops = {
+ SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend,
+ rzg2l_adc_pm_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver rzg2l_adc_driver = {
+ .probe = rzg2l_adc_probe,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = rzg2l_adc_match,
+ .pm = &rzg2l_adc_pm_ops,
+ },
+};
+
+module_platform_driver(rzg2l_adc_driver);
+
+MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index a4920646e9be..c03667e62732 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -131,6 +131,17 @@ config SENSIRION_SGP30
To compile this driver as module, choose M here: the
module will be called sgp30.
+config SENSIRION_SGP40
+ tristate "Sensirion SGP40 gas sensor"
+ depends on I2C
+ select CRC8
+ help
+ Say Y here to build I2C interface to support Sensirion SGP40 gas
+ sensor
+
+ To compile this driver as module, choose M here: the
+ module will be called sgp40.
+
config SPS30
tristate
select IIO_BUFFER
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 4898690cc155..d07af581f234 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SCD30_CORE) += scd30_core.o
obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
+obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o
obj-$(CONFIG_SPS30) += sps30.o
obj-$(CONFIG_SPS30_I2C) += sps30_i2c.o
obj-$(CONFIG_SPS30_SERIAL) += sps30_serial.o
diff --git a/drivers/iio/chemical/sgp40.c b/drivers/iio/chemical/sgp40.c
new file mode 100644
index 000000000000..8a56394cea4e
--- /dev/null
+++ b/drivers/iio/chemical/sgp40.c
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * sgp40.c - Support for Sensirion SGP40 Gas Sensor
+ *
+ * Copyright (C) 2021 Andreas Klinger <ak@it-klinger.de>
+ *
+ * I2C slave address: 0x59
+ *
+ * Datasheet can be found here:
+ * https://www.sensirion.com/file/datasheet_sgp40
+ *
+ * There are two functionalities supported:
+ *
+ * 1) read raw logarithmic resistance value from sensor
+ * --> useful to pass it to the algorithm of the sensor vendor for
+ * measuring deteriorations and improvements of air quality.
+ *
+ * 2) calculate an estimated absolute voc index (0 - 500 index points) for
+ * measuring the air quality.
+ * For this purpose the value of the resistance for which the voc index
+ * will be 250 can be set up using calibbias.
+ *
+ * Compensation values of relative humidity and temperature can be set up
+ * by writing to the out values of temp and humidityrelative.
+ */
+
+#include <linux/delay.h>
+#include <linux/crc8.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+
+/*
+ * floating point calculation of voc is done as integer
+ * where numbers are multiplied by 1 << SGP40_CALC_POWER
+ */
+#define SGP40_CALC_POWER 14
+
+#define SGP40_CRC8_POLYNOMIAL 0x31
+#define SGP40_CRC8_INIT 0xff
+
+DECLARE_CRC8_TABLE(sgp40_crc8_table);
+
+struct sgp40_data {
+ struct device *dev;
+ struct i2c_client *client;
+ int rht;
+ int temp;
+ int res_calibbias;
+ /* Prevent concurrent access to rht, tmp, calibbias */
+ struct mutex lock;
+};
+
+struct sgp40_tg_measure {
+ u8 command[2];
+ __be16 rht_ticks;
+ u8 rht_crc;
+ __be16 temp_ticks;
+ u8 temp_crc;
+} __packed;
+
+struct sgp40_tg_result {
+ __be16 res_ticks;
+ u8 res_crc;
+} __packed;
+
+static const struct iio_chan_spec sgp40_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+ {
+ .type = IIO_RESISTANCE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .output = 1,
+ },
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .output = 1,
+ },
+};
+
+/*
+ * taylor approximation of e^x:
+ * y = 1 + x + x^2 / 2 + x^3 / 6 + x^4 / 24 + ... + x^n / n!
+ *
+ * Because we are calculating x real value multiplied by 2^power we get
+ * an additional 2^power^n to divide for every element. For a reasonable
+ * precision this would overflow after a few iterations. Therefore we
+ * divide the x^n part whenever its about to overflow (xmax).
+ */
+
+static u32 sgp40_exp(int exp, u32 power, u32 rounds)
+{
+ u32 x, y, xp;
+ u32 factorial, divider, xmax;
+ int sign = 1;
+ int i;
+
+ if (exp == 0)
+ return 1 << power;
+ else if (exp < 0) {
+ sign = -1;
+ exp *= -1;
+ }
+
+ xmax = 0x7FFFFFFF / exp;
+ x = exp;
+ xp = 1;
+ factorial = 1;
+ y = 1 << power;
+ divider = 0;
+
+ for (i = 1; i <= rounds; i++) {
+ xp *= x;
+ factorial *= i;
+ y += (xp >> divider) / factorial;
+ divider += power;
+ /* divide when next multiplication would overflow */
+ if (xp >= xmax) {
+ xp >>= power;
+ divider -= power;
+ }
+ }
+
+ if (sign == -1)
+ return (1 << (power * 2)) / y;
+ else
+ return y;
+}
+
+static int sgp40_calc_voc(struct sgp40_data *data, u16 resistance_raw, int *voc)
+{
+ int x;
+ u32 exp = 0;
+
+ /* we calculate as a multiple of 16384 (2^14) */
+ mutex_lock(&data->lock);
+ x = ((int)resistance_raw - data->res_calibbias) * 106;
+ mutex_unlock(&data->lock);
+
+ /* voc = 500 / (1 + e^x) */
+ exp = sgp40_exp(x, SGP40_CALC_POWER, 18);
+ *voc = 500 * ((1 << (SGP40_CALC_POWER * 2)) / ((1<<SGP40_CALC_POWER) + exp));
+
+ dev_dbg(data->dev, "raw: %d res_calibbias: %d x: %d exp: %d voc: %d\n",
+ resistance_raw, data->res_calibbias, x, exp, *voc);
+
+ return 0;
+}
+
+static int sgp40_measure_resistance_raw(struct sgp40_data *data, u16 *resistance_raw)
+{
+ int ret;
+ struct i2c_client *client = data->client;
+ u32 ticks;
+ u16 ticks16;
+ u8 crc;
+ struct sgp40_tg_measure tg = {.command = {0x26, 0x0F}};
+ struct sgp40_tg_result tgres;
+
+ mutex_lock(&data->lock);
+
+ ticks = (data->rht / 10) * 65535 / 10000;
+ ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between 0 .. 100 %rH */
+ tg.rht_ticks = cpu_to_be16(ticks16);
+ tg.rht_crc = crc8(sgp40_crc8_table, (u8 *)&tg.rht_ticks, 2, SGP40_CRC8_INIT);
+
+ ticks = ((data->temp + 45000) / 10 ) * 65535 / 17500;
+ ticks16 = (u16)clamp(ticks, 0u, 65535u); /* clamp between -45 .. +130 °C */
+ tg.temp_ticks = cpu_to_be16(ticks16);
+ tg.temp_crc = crc8(sgp40_crc8_table, (u8 *)&tg.temp_ticks, 2, SGP40_CRC8_INIT);
+
+ mutex_unlock(&data->lock);
+
+ ret = i2c_master_send(client, (const char *)&tg, sizeof(tg));
+ if (ret != sizeof(tg)) {
+ dev_warn(data->dev, "i2c_master_send ret: %d sizeof: %zu\n", ret, sizeof(tg));
+ return -EIO;
+ }
+ msleep(30);
+
+ ret = i2c_master_recv(client, (u8 *)&tgres, sizeof(tgres));
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(tgres)) {
+ dev_warn(data->dev, "i2c_master_recv ret: %d sizeof: %zu\n", ret, sizeof(tgres));
+ return -EIO;
+ }
+
+ crc = crc8(sgp40_crc8_table, (u8 *)&tgres.res_ticks, 2, SGP40_CRC8_INIT);
+ if (crc != tgres.res_crc) {
+ dev_err(data->dev, "CRC error while measure-raw\n");
+ return -EIO;
+ }
+
+ *resistance_raw = be16_to_cpu(tgres.res_ticks);
+
+ return 0;
+}
+
+static int sgp40_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct sgp40_data *data = iio_priv(indio_dev);
+ int ret, voc;
+ u16 resistance_raw;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_RESISTANCE:
+ ret = sgp40_measure_resistance_raw(data, &resistance_raw);
+ if (ret)
+ return ret;
+
+ *val = resistance_raw;
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ mutex_lock(&data->lock);
+ *val = data->temp;
+ mutex_unlock(&data->lock);
+ return IIO_VAL_INT;
+ case IIO_HUMIDITYRELATIVE:
+ mutex_lock(&data->lock);
+ *val = data->rht;
+ mutex_unlock(&data->lock);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = sgp40_measure_resistance_raw(data, &resistance_raw);
+ if (ret)
+ return ret;
+
+ ret = sgp40_calc_voc(data, resistance_raw, &voc);
+ if (ret)
+ return ret;
+
+ *val = voc / (1 << SGP40_CALC_POWER);
+ /*
+ * calculation should fit into integer, where:
+ * voc <= (500 * 2^SGP40_CALC_POWER) = 8192000
+ * (with SGP40_CALC_POWER = 14)
+ */
+ *val2 = ((voc % (1 << SGP40_CALC_POWER)) * 244) / (1 << (SGP40_CALC_POWER - 12));
+ dev_dbg(data->dev, "voc: %d val: %d.%06d\n", voc, *val, *val2);
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&data->lock);
+ *val = data->res_calibbias;
+ mutex_unlock(&data->lock);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sgp40_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct sgp40_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_TEMP:
+ if ((val < -45000) || (val > 130000))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ data->temp = val;
+ mutex_unlock(&data->lock);
+ return 0;
+ case IIO_HUMIDITYRELATIVE:
+ if ((val < 0) || (val > 100000))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ data->rht = val;
+ mutex_unlock(&data->lock);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if ((val < 20000) || (val > 52768))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ data->res_calibbias = val;
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info sgp40_info = {
+ .read_raw = sgp40_read_raw,
+ .write_raw = sgp40_write_raw,
+};
+
+static int sgp40_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct iio_dev *indio_dev;
+ struct sgp40_data *data;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ data->dev = dev;
+
+ crc8_populate_msb(sgp40_crc8_table, SGP40_CRC8_POLYNOMIAL);
+
+ mutex_init(&data->lock);
+
+ /* set default values */
+ data->rht = 50000; /* 50 % */
+ data->temp = 25000; /* 25 °C */
+ data->res_calibbias = 30000; /* resistance raw value for voc index of 250 */
+
+ indio_dev->info = &sgp40_info;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = sgp40_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sgp40_channels);
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ dev_err(dev, "failed to register iio device\n");
+
+ return ret;
+}
+
+static const struct i2c_device_id sgp40_id[] = {
+ { "sgp40" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, sgp40_id);
+
+static const struct of_device_id sgp40_dt_ids[] = {
+ { .compatible = "sensirion,sgp40" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, sgp40_dt_ids);
+
+static struct i2c_driver sgp40_driver = {
+ .driver = {
+ .name = "sgp40",
+ .of_match_table = sgp40_dt_ids,
+ },
+ .probe = sgp40_probe,
+ .id_table = sgp40_id,
+};
+module_i2c_driver(sgp40_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("Sensirion SGP40 gas sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
index 802f9ae04cf4..dccc471e79da 100644
--- a/drivers/iio/common/st_sensors/st_sensors_buffer.c
+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
@@ -9,13 +9,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/triggered_buffer.h>
#include <linux/irqreturn.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 7a69c1be7393..0bbb090b108c 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
+#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.h b/drivers/iio/common/st_sensors/st_sensors_core.h
index e8894be55660..09f3e602a2e2 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.h
+++ b/drivers/iio/common/st_sensors/st_sensors_core.h
@@ -4,6 +4,7 @@
*/
#ifndef __ST_SENSORS_CORE_H
#define __ST_SENSORS_CORE_H
+struct iio_dev;
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data);
#endif
diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
index b9e59ad32a02..b3ff88700866 100644
--- a/drivers/iio/common/st_sensors/st_sensors_i2c.c
+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
@@ -7,15 +7,14 @@
* Denis Ciocca <denis.ciocca@st.com>
*/
+#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_i2c.h>
-
#define ST_SENSORS_I2C_MULTIREAD 0x80
static const struct regmap_config st_sensors_i2c_regmap_config = {
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
index 48fc41dc5633..0d1d66c77cd8 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -9,13 +9,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/spi/spi.h>
#include <linux/iio/common/st_sensors_spi.h>
-#include "st_sensors_core.h"
#define ST_SENSORS_SPI_MULTIREAD 0xc0
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 0b511665dee5..64e0a748a855 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index 9bde86982912..530529feebb5 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -229,7 +229,7 @@ static int ad5624r_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = devm_regulator_get(&spi->dev, "vcc");
+ st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret)
@@ -240,6 +240,22 @@ static int ad5624r_probe(struct spi_device *spi)
goto error_disable_reg;
voltage_uv = ret;
+ } else {
+ if (PTR_ERR(st->reg) != -ENODEV)
+ return PTR_ERR(st->reg);
+ /* Backwards compatibility. This naming is not correct */
+ st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+
+ ret = regulator_get_voltage(st->reg);
+ if (ret < 0)
+ goto error_disable_reg;
+
+ voltage_uv = ret;
+ }
}
spi_set_drvdata(spi, indio_dev);
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index bd6e75699a63..bd0b7f361154 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -294,6 +294,11 @@ static const struct iio_info max5821_info = {
.write_raw = max5821_write_raw,
};
+static void max5821_regulator_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int max5821_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -306,7 +311,6 @@ static int max5821_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
@@ -321,21 +325,29 @@ static int max5821_probe(struct i2c_client *client,
ret = PTR_ERR(data->vref_reg);
dev_err(&client->dev,
"Failed to get vref regulator: %d\n", ret);
- goto error_free_reg;
+ return ret;
}
ret = regulator_enable(data->vref_reg);
if (ret) {
dev_err(&client->dev,
"Failed to enable vref regulator: %d\n", ret);
- goto error_free_reg;
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&client->dev, max5821_regulator_disable,
+ data->vref_reg);
+ if (ret) {
+ dev_err(&client->dev,
+ "Failed to add action to managed regulator: %d\n", ret);
+ return ret;
}
ret = regulator_get_voltage(data->vref_reg);
if (ret < 0) {
dev_err(&client->dev,
"Failed to get voltage on regulator: %d\n", ret);
- goto error_disable_reg;
+ return ret;
}
data->vref_mv = ret / 1000;
@@ -346,25 +358,7 @@ static int max5821_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &max5821_info;
- return iio_device_register(indio_dev);
-
-error_disable_reg:
- regulator_disable(data->vref_reg);
-
-error_free_reg:
-
- return ret;
-}
-
-static int max5821_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct max5821_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- regulator_disable(data->vref_reg);
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id max5821_id[] = {
@@ -386,7 +380,6 @@ static struct i2c_driver max5821_driver = {
.pm = &max5821_pm_ops,
},
.probe = max5821_probe,
- .remove = max5821_remove,
.id_table = max5821_id,
};
module_i2c_driver(max5821_driver);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index bc63c2a34c5e..8f0ad022c7f1 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -303,8 +303,8 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = kmemdup(gyro_3d_channels,
- sizeof(gyro_3d_channels), GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels,
+ sizeof(gyro_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
@@ -315,7 +315,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
HID_USAGE_SENSOR_GYRO_3D, gyro_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
@@ -329,7 +329,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
&gyro_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -354,8 +354,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -369,7 +367,6 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index 6537f5cb8320..f5332b6a02bc 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -26,7 +26,6 @@
#ifdef CONFIG_IIO_BUFFER
int st_gyro_allocate_ring(struct iio_dev *indio_dev);
-void st_gyro_deallocate_ring(struct iio_dev *indio_dev);
int st_gyro_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_GYRO_TRIGGER_SET_STATE (&st_gyro_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
@@ -34,9 +33,6 @@ static inline int st_gyro_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
-static inline void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
-{
-}
#define ST_GYRO_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c
index 4feb7ada7195..4ae33ef25b9c 100644
--- a/drivers/iio/gyro/st_gyro_buffer.c
+++ b/drivers/iio/gyro/st_gyro_buffer.c
@@ -9,14 +9,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
@@ -66,13 +61,8 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {
int st_gyro_allocate_ring(struct iio_dev *indio_dev)
{
- return iio_triggered_buffer_setup(indio_dev, NULL,
- &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
-}
-
-void st_gyro_deallocate_ring(struct iio_dev *indio_dev)
-{
- iio_triggered_buffer_cleanup(indio_dev);
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index b86ee4d940d9..e8fc8af65143 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -9,17 +9,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
+#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/common/st_sensors.h>
#include "st_gyro.h"
@@ -517,7 +512,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
err = st_sensors_allocate_trigger(indio_dev,
ST_GYRO_TRIGGER_OPS);
if (err < 0)
- goto st_gyro_probe_trigger_error;
+ return err;
}
err = iio_device_register(indio_dev);
@@ -532,8 +527,6 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
st_gyro_device_register_error:
if (gdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-st_gyro_probe_trigger_error:
- st_gyro_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_gyro_common_probe);
@@ -545,8 +538,6 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
iio_device_unregister(indio_dev);
if (gdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-
- st_gyro_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_gyro_common_remove);
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index a25cc0379e16..3ef86e16ee65 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index 18d6a2aeda45..41d835493347 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 8a7a920e6200..597768c29a72 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -143,6 +143,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6050,
.fifo_size = 1024,
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
+ .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU6500_WHOAMI_VALUE,
@@ -151,6 +152,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU6515_WHOAMI_VALUE,
@@ -159,6 +161,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU6880_WHOAMI_VALUE,
@@ -167,6 +170,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 4096,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU6000_WHOAMI_VALUE,
@@ -175,6 +179,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6050,
.fifo_size = 1024,
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
+ .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU9150_WHOAMI_VALUE,
@@ -183,6 +188,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6050,
.fifo_size = 1024,
.temp = {INV_MPU6050_TEMP_OFFSET, INV_MPU6050_TEMP_SCALE},
+ .startup_time = {INV_MPU6050_GYRO_STARTUP_TIME, INV_MPU6050_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU9250_WHOAMI_VALUE,
@@ -191,6 +197,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_MPU9255_WHOAMI_VALUE,
@@ -199,6 +206,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_ICM20608_WHOAMI_VALUE,
@@ -207,6 +215,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_ICM20609_WHOAMI_VALUE,
@@ -215,6 +224,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 4 * 1024,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_ICM20689_WHOAMI_VALUE,
@@ -223,6 +233,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 4 * 1024,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_ICM20602_WHOAMI_VALUE,
@@ -231,6 +242,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 1008,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_ICM20602_GYRO_STARTUP_TIME, INV_ICM20602_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_ICM20690_WHOAMI_VALUE,
@@ -239,6 +251,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 1024,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_ICM20690_GYRO_STARTUP_TIME, INV_ICM20690_ACCEL_STARTUP_TIME},
},
{
.whoami = INV_IAM20680_WHOAMI_VALUE,
@@ -247,6 +260,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
.config = &chip_config_6500,
.fifo_size = 512,
.temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+ .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME},
},
};
@@ -379,12 +393,12 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
sleep = 0;
if (en) {
if (mask & INV_MPU6050_SENSOR_ACCL) {
- if (sleep < INV_MPU6050_ACCEL_UP_TIME)
- sleep = INV_MPU6050_ACCEL_UP_TIME;
+ if (sleep < st->hw->startup_time.accel)
+ sleep = st->hw->startup_time.accel;
}
if (mask & INV_MPU6050_SENSOR_GYRO) {
- if (sleep < INV_MPU6050_GYRO_UP_TIME)
- sleep = INV_MPU6050_GYRO_UP_TIME;
+ if (sleep < st->hw->startup_time.gyro)
+ sleep = st->hw->startup_time.gyro;
}
} else {
if (mask & INV_MPU6050_SENSOR_GYRO) {
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 58188dc0dd13..c6aa36ee966a 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -149,6 +149,10 @@ struct inv_mpu6050_hw {
int offset;
int scale;
} temp;
+ struct {
+ unsigned int accel;
+ unsigned int gyro;
+ } startup_time;
};
/*
@@ -320,11 +324,21 @@ struct inv_mpu6050_state {
/* delay time in milliseconds */
#define INV_MPU6050_POWER_UP_TIME 100
#define INV_MPU6050_TEMP_UP_TIME 100
-#define INV_MPU6050_ACCEL_UP_TIME 20
-#define INV_MPU6050_GYRO_UP_TIME 35
+#define INV_MPU6050_ACCEL_STARTUP_TIME 20
+#define INV_MPU6050_GYRO_STARTUP_TIME 60
#define INV_MPU6050_GYRO_DOWN_TIME 150
#define INV_MPU6050_SUSPEND_DELAY_MS 2000
+#define INV_MPU6500_GYRO_STARTUP_TIME 70
+#define INV_MPU6500_ACCEL_STARTUP_TIME 30
+
+#define INV_ICM20602_GYRO_STARTUP_TIME 100
+#define INV_ICM20602_ACCEL_STARTUP_TIME 20
+
+#define INV_ICM20690_GYRO_STARTUP_TIME 80
+#define INV_ICM20690_ACCEL_STARTUP_TIME 10
+
+
/* delay time in microseconds */
#define INV_MPU6050_REG_UP_TIME_MIN 5000
#define INV_MPU6050_REG_UP_TIME_MAX 10000
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index 2d0e8cdd4848..882546897255 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -91,22 +91,11 @@ static unsigned int inv_scan_query(struct iio_dev *indio_dev)
static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st)
{
- unsigned int gyro_skip = 0;
- unsigned int magn_skip = 0;
- unsigned int skip_samples;
-
- /* gyro first sample is out of specs, skip it */
- if (st->chip_config.gyro_fifo_enable)
- gyro_skip = 1;
+ unsigned int skip_samples = 0;
/* mag first sample is always not ready, skip it */
if (st->chip_config.magn_fifo_enable)
- magn_skip = 1;
-
- /* compute first samples to skip */
- skip_samples = gyro_skip;
- if (magn_skip > skip_samples)
- skip_samples = magn_skip;
+ skip_samples = 1;
return skip_samples;
}
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
index 8204f7303fd7..5e6625140db7 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/common/st_sensors.h>
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
index 50a36ab53bc3..78bede358747 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
@@ -10,7 +10,8 @@
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_i2c.h>
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
index 272c88990dd0..180b54e66438 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
@@ -9,7 +9,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/iio/common/st_sensors_spi.h>
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index fdd623407b96..a95cc2da56be 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -354,13 +354,14 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
const unsigned long *mask;
unsigned long *trialmask;
- trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL);
- if (trialmask == NULL)
- return -ENOMEM;
if (!indio_dev->masklength) {
WARN(1, "Trying to set scanmask prior to registering buffer\n");
- goto err_invalid_mask;
+ return -EINVAL;
}
+
+ trialmask = bitmap_alloc(indio_dev->masklength, GFP_KERNEL);
+ if (!trialmask)
+ return -ENOMEM;
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
set_bit(bit, trialmask);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 6d2175eb7af2..2dbb37e09b8c 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -740,10 +740,13 @@ static ssize_t iio_read_channel_label(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- if (!indio_dev->info->read_label)
- return -EINVAL;
+ if (indio_dev->info->read_label)
+ return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
+
+ if (this_attr->c->extend_name)
+ return sprintf(buf, "%s\n", this_attr->c->extend_name);
- return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
+ return -EINVAL;
}
static ssize_t iio_read_channel_info(struct device *dev,
@@ -1183,7 +1186,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev,
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
int ret;
- if (!indio_dev->info->read_label)
+ if (!indio_dev->info->read_label && !chan->extend_name)
return 0;
ret = __iio_add_chan_devattr("label",
@@ -1858,6 +1861,24 @@ static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
return 0;
}
+static int iio_check_extended_name(const struct iio_dev *indio_dev)
+{
+ unsigned int i;
+
+ if (!indio_dev->info->read_label)
+ return 0;
+
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].extend_name) {
+ dev_err(&indio_dev->dev,
+ "Cannot use labels and extend_name at the same time\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static const struct iio_buffer_setup_ops noop_ring_setup_ops;
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
@@ -1882,6 +1903,10 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (ret < 0)
return ret;
+ ret = iio_check_extended_name(indio_dev);
+ if (ret < 0)
+ return ret;
+
iio_device_register_debugfs(indio_dev);
ret = iio_buffers_alloc_sysfs_and_mask(indio_dev);
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 17dac8d0e11d..6b33975c8d73 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -54,7 +54,10 @@
struct adjd_s311_data {
struct i2c_client *client;
- u16 *buffer;
+ struct {
+ s16 chans[4];
+ s64 ts __aligned(8);
+ } scan;
};
enum adjd_s311_channel_idx {
@@ -129,10 +132,10 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
+ data->scan.chans[j++] = ret & ADJD_S311_DATA_MASK;
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, time_ns);
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
done:
iio_trigger_notify_done(indio_dev->trig);
@@ -225,23 +228,9 @@ static int adjd_s311_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
-static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
- const unsigned long *scan_mask)
-{
- struct adjd_s311_data *data = iio_priv(indio_dev);
-
- kfree(data->buffer);
- data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (data->buffer == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
static const struct iio_info adjd_s311_info = {
.read_raw = adjd_s311_read_raw,
.write_raw = adjd_s311_write_raw,
- .update_scan_mode = adjd_s311_update_scan_mode,
};
static int adjd_s311_probe(struct i2c_client *client,
@@ -256,7 +245,6 @@ static int adjd_s311_probe(struct i2c_client *client,
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
data->client = client;
indio_dev->info = &adjd_s311_info;
@@ -265,34 +253,12 @@ static int adjd_s311_probe(struct i2c_client *client,
indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
- err = iio_triggered_buffer_setup(indio_dev, NULL,
- adjd_s311_trigger_handler, NULL);
+ err = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ adjd_s311_trigger_handler, NULL);
if (err < 0)
return err;
- err = iio_device_register(indio_dev);
- if (err)
- goto exit_unreg_buffer;
-
- dev_info(&client->dev, "ADJD-S311 color sensor registered\n");
-
- return 0;
-
-exit_unreg_buffer:
- iio_triggered_buffer_cleanup(indio_dev);
- return err;
-}
-
-static int adjd_s311_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct adjd_s311_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- kfree(data->buffer);
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id adjd_s311_id[] = {
@@ -306,7 +272,6 @@ static struct i2c_driver adjd_s311_driver = {
.name = ADJD_S311_DRV_NAME,
},
.probe = adjd_s311_probe,
- .remove = adjd_s311_remove,
.id_table = adjd_s311_id,
};
module_i2c_driver(adjd_s311_driver);
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index 6d1b0ffd144b..fd9a8c27de2e 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -256,9 +256,16 @@ static const struct i2c_device_id cm3323_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cm3323_id);
+static const struct of_device_id cm3323_of_match[] = {
+ { .compatible = "capella,cm3323", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cm3323_of_match);
+
static struct i2c_driver cm3323_driver = {
.driver = {
.name = CM3323_DRV_NAME,
+ .of_match_table = cm3323_of_match,
},
.probe = cm3323_probe,
.id_table = cm3323_id,
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 2ff252c75c03..5a1a625d8d16 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -294,8 +294,8 @@ static int hid_als_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = kmemdup(als_channels,
- sizeof(als_channels), GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels,
+ sizeof(als_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
@@ -306,7 +306,7 @@ static int hid_als_probe(struct platform_device *pdev)
HID_USAGE_SENSOR_ALS, als_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->num_channels =
@@ -321,7 +321,7 @@ static int hid_als_probe(struct platform_device *pdev)
&als_state->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -346,8 +346,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -361,7 +359,6 @@ static int hid_als_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index 1621530f5f61..f10fa2abfe72 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -253,8 +253,8 @@ static int hid_prox_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels),
- GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels,
+ sizeof(prox_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
@@ -265,7 +265,7 @@ static int hid_prox_probe(struct platform_device *pdev)
HID_USAGE_SENSOR_PROX, prox_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->num_channels = ARRAY_SIZE(prox_channels);
@@ -279,7 +279,7 @@ static int hid_prox_probe(struct platform_device *pdev)
&prox_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -304,8 +304,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -319,7 +317,6 @@ static int hid_prox_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index e2abad48b9f4..e8f6cdf26f22 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -220,7 +220,6 @@ static int __si1145_command_reset(struct si1145_data *data)
return -ETIMEDOUT;
}
msleep(SI1145_COMMAND_MINSLEEP_MS);
- continue;
}
}
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index 0593abd600ec..b87222141429 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -267,6 +267,18 @@ static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = {
.predisable = tcs3414_buffer_predisable,
};
+static int tcs3414_powerdown(struct tcs3414_data *data)
+{
+ return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
+ data->control & ~(TCS3414_CONTROL_POWER |
+ TCS3414_CONTROL_ADC_EN));
+}
+
+static void tcs3414_powerdown_cleanup(void *data)
+{
+ tcs3414_powerdown(data);
+}
+
static int tcs3414_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -309,6 +321,11 @@ static int tcs3414_probe(struct i2c_client *client,
if (ret < 0)
return ret;
+ ret = devm_add_action_or_reset(&client->dev, tcs3414_powerdown_cleanup,
+ data);
+ if (ret < 0)
+ return ret;
+
data->timing = TCS3414_INTEG_12MS; /* free running */
ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING,
data->timing);
@@ -320,38 +337,12 @@ static int tcs3414_probe(struct i2c_client *client,
return ret;
data->gain = ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
tcs3414_trigger_handler, &tcs3414_buffer_setup_ops);
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
- if (ret < 0)
- goto buffer_cleanup;
-
- return 0;
-
-buffer_cleanup:
- iio_triggered_buffer_cleanup(indio_dev);
- return ret;
-}
-
-static int tcs3414_powerdown(struct tcs3414_data *data)
-{
- return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
- data->control & ~(TCS3414_CONTROL_POWER |
- TCS3414_CONTROL_ADC_EN));
-}
-
-static int tcs3414_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
- tcs3414_powerdown(iio_priv(indio_dev));
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -385,7 +376,6 @@ static struct i2c_driver tcs3414_driver = {
.pm = &tcs3414_pm_ops,
},
.probe = tcs3414_probe,
- .remove = tcs3414_remove,
.id_table = tcs3414_id,
};
module_i2c_driver(tcs3414_driver);
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index fb6c906c4c0c..785b7f7b8b06 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -25,25 +25,13 @@
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
-void st_magn_deallocate_ring(struct iio_dev *indio_dev);
int st_magn_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
-static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
-{
- return 0;
-}
-static inline void st_magn_remove_trigger(struct iio_dev *indio_dev, int irq)
-{
- return;
-}
static inline int st_magn_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
-static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
-{
-}
#define ST_MAGN_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
index 4917721fa2e5..cb43ccda808d 100644
--- a/drivers/iio/magnetometer/st_magn_buffer.c
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -9,14 +9,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
@@ -46,13 +41,8 @@ static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
int st_magn_allocate_ring(struct iio_dev *indio_dev)
{
- return iio_triggered_buffer_setup(indio_dev, NULL,
- &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
-}
-
-void st_magn_deallocate_ring(struct iio_dev *indio_dev)
-{
- iio_triggered_buffer_cleanup(indio_dev);
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index 0048c3cd36ee..9ffd50d796bf 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -9,16 +9,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/common/st_sensors.h>
#include "st_magn.h"
@@ -652,7 +647,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
err = st_sensors_allocate_trigger(indio_dev,
ST_MAGN_TRIGGER_OPS);
if (err < 0)
- goto st_magn_probe_trigger_error;
+ return err;
}
err = iio_device_register(indio_dev);
@@ -667,8 +662,6 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
st_magn_device_register_error:
if (mdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-st_magn_probe_trigger_error:
- st_magn_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_magn_common_probe);
@@ -680,8 +673,6 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
iio_device_unregister(indio_dev);
if (mdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-
- st_magn_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_magn_common_remove);
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index 3e23c117de8e..2dfe4ee99591 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 03c0a737aba6..fba978796395 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index c0079e2c8807..ba5b581d5b25 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -326,8 +326,8 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = kmemdup(incl_3d_channels,
- sizeof(incl_3d_channels), GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, incl_3d_channels,
+ sizeof(incl_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
@@ -339,7 +339,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
incl_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels);
@@ -353,7 +353,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
&incl_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -379,8 +379,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -394,7 +392,6 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &incl_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
index 4cac0173db8b..832df8da2bc6 100644
--- a/drivers/iio/potentiometer/Kconfig
+++ b/drivers/iio/potentiometer/Kconfig
@@ -6,6 +6,16 @@
menu "Digital potentiometers"
+config AD5110
+ tristate "Analog Devices AD5110 and similar Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Analog Devices AD5110, AD5112
+ and AD5114 digital potentiometer chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad5110.
+
config AD5272
tristate "Analog Devices AD5272 and similar Digital Potentiometer driver"
depends on I2C
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
index 091adf3cdd0b..5ebb8e3bbd76 100644
--- a/drivers/iio/potentiometer/Makefile
+++ b/drivers/iio/potentiometer/Makefile
@@ -4,6 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD5110) += ad5110.o
obj-$(CONFIG_AD5272) += ad5272.o
obj-$(CONFIG_DS1803) += ds1803.o
obj-$(CONFIG_MAX5432) += max5432.o
diff --git a/drivers/iio/potentiometer/ad5110.c b/drivers/iio/potentiometer/ad5110.c
new file mode 100644
index 000000000000..d4eeedae56e5
--- /dev/null
+++ b/drivers/iio/potentiometer/ad5110.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Analog Devices AD5110 digital potentiometer driver
+ *
+ * Copyright (C) 2021 Mugilraj Dhavachelvan <dmugil2000@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5110_5112_5114.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* AD5110 commands */
+#define AD5110_EEPROM_WR 1
+#define AD5110_RDAC_WR 2
+#define AD5110_SHUTDOWN 3
+#define AD5110_RESET 4
+#define AD5110_RDAC_RD 5
+#define AD5110_EEPROM_RD 6
+
+/* AD5110_EEPROM_RD data */
+#define AD5110_WIPER_POS 0
+#define AD5110_RESISTOR_TOL 1
+
+#define AD5110_WIPER_RESISTANCE 70
+
+struct ad5110_cfg {
+ int max_pos;
+ int kohms;
+ int shift;
+};
+
+enum ad5110_type {
+ AD5110_10,
+ AD5110_80,
+ AD5112_05,
+ AD5112_10,
+ AD5112_80,
+ AD5114_10,
+ AD5114_80,
+};
+
+static const struct ad5110_cfg ad5110_cfg[] = {
+ [AD5110_10] = { .max_pos = 128, .kohms = 10 },
+ [AD5110_80] = { .max_pos = 128, .kohms = 80 },
+ [AD5112_05] = { .max_pos = 64, .kohms = 5, .shift = 1 },
+ [AD5112_10] = { .max_pos = 64, .kohms = 10, .shift = 1 },
+ [AD5112_80] = { .max_pos = 64, .kohms = 80, .shift = 1 },
+ [AD5114_10] = { .max_pos = 32, .kohms = 10, .shift = 2 },
+ [AD5114_80] = { .max_pos = 32, .kohms = 80, .shift = 2 },
+};
+
+struct ad5110_data {
+ struct i2c_client *client;
+ s16 tol; /* resistor tolerance */
+ bool enable;
+ struct mutex lock;
+ const struct ad5110_cfg *cfg;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ u8 buf[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec ad5110_channels[] = {
+ {
+ .type = IIO_RESISTANCE,
+ .output = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_ENABLE),
+ },
+};
+
+static int ad5110_read(struct ad5110_data *data, u8 cmd, int *val)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+ data->buf[0] = cmd;
+ data->buf[1] = *val;
+
+ ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf));
+ if (ret < 0) {
+ goto error;
+ } else if (ret != sizeof(data->buf)) {
+ ret = -EIO;
+ goto error;
+ }
+
+ ret = i2c_master_recv_dmasafe(data->client, data->buf, 1);
+ if (ret < 0) {
+ goto error;
+ } else if (ret != 1) {
+ ret = -EIO;
+ goto error;
+ }
+
+ *val = data->buf[0];
+ ret = 0;
+
+error:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int ad5110_write(struct ad5110_data *data, u8 cmd, u8 val)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+ data->buf[0] = cmd;
+ data->buf[1] = val;
+
+ ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf));
+ if (ret < 0) {
+ goto error;
+ } else if (ret != sizeof(data->buf)) {
+ ret = -EIO;
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int ad5110_resistor_tol(struct ad5110_data *data, u8 cmd, int val)
+{
+ int ret;
+
+ ret = ad5110_read(data, cmd, &val);
+ if (ret)
+ return ret;
+
+ data->tol = data->cfg->kohms * (val & GENMASK(6, 0)) * 10 / 8;
+ if (!(val & BIT(7)))
+ data->tol *= -1;
+
+ return 0;
+}
+
+static ssize_t store_eeprom_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad5110_data *data = iio_priv(indio_dev);
+ int val = AD5110_WIPER_POS;
+ int ret;
+
+ ret = ad5110_read(data, AD5110_EEPROM_RD, &val);
+ if (ret)
+ return ret;
+
+ val = val >> data->cfg->shift;
+ return iio_format_value(buf, IIO_VAL_INT, 1, &val);
+}
+
+static ssize_t store_eeprom_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad5110_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = ad5110_write(data, AD5110_EEPROM_WR, 0);
+ if (ret) {
+ dev_err(&data->client->dev, "RDAC to EEPROM write failed\n");
+ return ret;
+ }
+
+ /* The storing of EEPROM data takes approximately 18 ms. */
+ msleep(20);
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR_RW(store_eeprom, 0);
+
+static struct attribute *ad5110_attributes[] = {
+ &iio_dev_attr_store_eeprom.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ad5110_attribute_group = {
+ .attrs = ad5110_attributes,
+};
+
+static int ad5110_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct ad5110_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ad5110_read(data, AD5110_RDAC_RD, val);
+ if (ret)
+ return ret;
+
+ *val = *val >> data->cfg->shift;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = AD5110_WIPER_RESISTANCE * data->cfg->max_pos;
+ *val2 = 1000 * data->cfg->kohms + data->tol;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * data->cfg->kohms + data->tol;
+ *val2 = data->cfg->max_pos;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_ENABLE:
+ *val = data->enable;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad5110_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad5110_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > data->cfg->max_pos || val < 0)
+ return -EINVAL;
+
+ return ad5110_write(data, AD5110_RDAC_WR, val << data->cfg->shift);
+ case IIO_CHAN_INFO_ENABLE:
+ if (val < 0 || val > 1)
+ return -EINVAL;
+ if (data->enable == val)
+ return 0;
+ ret = ad5110_write(data, AD5110_SHUTDOWN, val ? 0 : 1);
+ if (ret)
+ return ret;
+ data->enable = val;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ad5110_info = {
+ .read_raw = ad5110_read_raw,
+ .write_raw = ad5110_write_raw,
+ .attrs = &ad5110_attribute_group,
+};
+
+#define AD5110_COMPATIBLE(of_compatible, cfg) { \
+ .compatible = of_compatible, \
+ .data = &ad5110_cfg[cfg], \
+}
+
+static const struct of_device_id ad5110_of_match[] = {
+ AD5110_COMPATIBLE("adi,ad5110-10", AD5110_10),
+ AD5110_COMPATIBLE("adi,ad5110-80", AD5110_80),
+ AD5110_COMPATIBLE("adi,ad5112-05", AD5112_05),
+ AD5110_COMPATIBLE("adi,ad5112-10", AD5112_10),
+ AD5110_COMPATIBLE("adi,ad5112-80", AD5112_80),
+ AD5110_COMPATIBLE("adi,ad5114-10", AD5114_10),
+ AD5110_COMPATIBLE("adi,ad5114-80", AD5114_80),
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad5110_of_match);
+
+static const struct i2c_device_id ad5110_id[] = {
+ { "ad5110-10", AD5110_10 },
+ { "ad5110-80", AD5110_80 },
+ { "ad5112-05", AD5112_05 },
+ { "ad5112-10", AD5112_10 },
+ { "ad5112-80", AD5112_80 },
+ { "ad5114-10", AD5114_10 },
+ { "ad5114-80", AD5114_80 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad5110_id);
+
+static int ad5110_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct iio_dev *indio_dev;
+ struct ad5110_data *data;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ mutex_init(&data->lock);
+ data->enable = 1;
+ data->cfg = device_get_match_data(dev);
+
+ /* refresh RDAC register with EEPROM */
+ ret = ad5110_write(data, AD5110_RESET, 0);
+ if (ret) {
+ dev_err(dev, "Refresh RDAC with EEPROM failed\n");
+ return ret;
+ }
+
+ ret = ad5110_resistor_tol(data, AD5110_EEPROM_RD, AD5110_RESISTOR_TOL);
+ if (ret) {
+ dev_err(dev, "Read resistor tolerance failed\n");
+ return ret;
+ }
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ad5110_info;
+ indio_dev->channels = ad5110_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad5110_channels);
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct i2c_driver ad5110_driver = {
+ .driver = {
+ .name = "ad5110",
+ .of_match_table = ad5110_of_match,
+ },
+ .probe_new = ad5110_probe,
+ .id_table = ad5110_id,
+};
+module_i2c_driver(ad5110_driver);
+
+MODULE_AUTHOR("Mugilraj Dhavachelvan <dmugil2000@gmail.com>");
+MODULE_DESCRIPTION("AD5110 digital potentiometer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c
index 6e22b538091f..098d144a8fdd 100644
--- a/drivers/iio/potentiometer/max5481.c
+++ b/drivers/iio/potentiometer/max5481.c
@@ -125,6 +125,11 @@ static const struct of_device_id max5481_match[] = {
};
MODULE_DEVICE_TABLE(of, max5481_match);
+static void max5481_wiper_save(void *data)
+{
+ max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
+}
+
static int max5481_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -136,7 +141,6 @@ static int max5481_probe(struct spi_device *spi)
if (!indio_dev)
return -ENOMEM;
- spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
@@ -158,18 +162,11 @@ static int max5481_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- return iio_device_register(indio_dev);
-}
-
-static int max5481_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct max5481_data *data = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
+ ret = devm_add_action(&spi->dev, max5481_wiper_save, data);
+ if (ret < 0)
+ return ret;
- /* save wiper reg to NV reg */
- return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id max5481_id_table[] = {
@@ -187,7 +184,6 @@ static struct spi_driver max5481_driver = {
.of_match_table = max5481_match,
},
.probe = max5481_probe,
- .remove = max5481_remove,
.id_table = max5481_id_table,
};
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 10c52b8df2ba..a9215eb32d70 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -13,17 +13,24 @@
#include <linux/iio/buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-#define CHANNEL_SCAN_INDEX_PRESSURE 0
+enum {
+ CHANNEL_SCAN_INDEX_PRESSURE,
+ CHANNEL_SCAN_INDEX_TIMESTAMP,
+};
struct press_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info press_attr;
- u32 press_data;
+ struct {
+ u32 press_data;
+ u64 timestamp __aligned(8);
+ } scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
+ s64 timestamp;
};
static const u32 press_sensitivity_addresses[] = {
@@ -41,7 +48,9 @@ static const struct iio_chan_spec press_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_PRESSURE,
- }
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
+
};
/* Adjust channel real bits based on report descriptor */
@@ -154,14 +163,6 @@ static const struct iio_info press_info = {
.write_raw = &press_write_raw,
};
-/* Function to push data to buffer */
-static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
- int len)
-{
- dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- iio_push_to_buffers(indio_dev, data);
-}
-
/* Callback handler to send event after all samples are received and captured */
static int press_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
@@ -171,10 +172,13 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev,
struct press_state *press_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "press_proc_event\n");
- if (atomic_read(&press_state->common_attributes.data_ready))
- hid_sensor_push_data(indio_dev,
- &press_state->press_data,
- sizeof(press_state->press_data));
+ if (atomic_read(&press_state->common_attributes.data_ready)) {
+ if (!press_state->timestamp)
+ press_state->timestamp = iio_get_time_ns(indio_dev);
+
+ iio_push_to_buffers_with_timestamp(
+ indio_dev, &press_state->scan, press_state->timestamp);
+ }
return 0;
}
@@ -191,9 +195,13 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) {
case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE:
- press_state->press_data = *(u32 *)raw_data;
+ press_state->scan.press_data = *(u32 *)raw_data;
ret = 0;
break;
+ case HID_USAGE_SENSOR_TIME_TIMESTAMP:
+ press_state->timestamp = hid_sensor_convert_timestamp(
+ &press_state->common_attributes, *(s64 *)raw_data);
+ break;
default:
break;
}
@@ -259,8 +267,8 @@ static int hid_press_probe(struct platform_device *pdev)
return ret;
}
- indio_dev->channels = kmemdup(press_channels, sizeof(press_channels),
- GFP_KERNEL);
+ indio_dev->channels = devm_kmemdup(&pdev->dev, press_channels,
+ sizeof(press_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
@@ -271,7 +279,7 @@ static int hid_press_probe(struct platform_device *pdev)
HID_USAGE_SENSOR_PRESSURE, press_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
- goto error_free_dev_mem;
+ return ret;
}
indio_dev->num_channels =
@@ -286,7 +294,7 @@ static int hid_press_probe(struct platform_device *pdev)
&press_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "trigger setup failed\n");
- goto error_free_dev_mem;
+ return ret;
}
ret = iio_device_register(indio_dev);
@@ -311,8 +319,6 @@ error_iio_unreg:
iio_device_unregister(indio_dev);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
-error_free_dev_mem:
- kfree(indio_dev->channels);
return ret;
}
@@ -326,7 +332,6 @@ static int hid_press_remove(struct platform_device *pdev)
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes);
- kfree(indio_dev->channels);
return 0;
}
diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
index e40b1d7dc129..9538118c9648 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -242,47 +242,26 @@ static int hp03_probe(struct i2c_client *client,
* which has it's dedicated I2C address and contains
* the calibration constants for the sensor.
*/
- priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR);
+ priv->eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter,
+ HP03_EEPROM_ADDR);
if (IS_ERR(priv->eeprom_client)) {
dev_err(dev, "New EEPROM I2C device failed\n");
return PTR_ERR(priv->eeprom_client);
}
- priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client,
- &hp03_regmap_config);
+ priv->eeprom_regmap = devm_regmap_init_i2c(priv->eeprom_client,
+ &hp03_regmap_config);
if (IS_ERR(priv->eeprom_regmap)) {
dev_err(dev, "Failed to allocate EEPROM regmap\n");
- ret = PTR_ERR(priv->eeprom_regmap);
- goto err_cleanup_eeprom_client;
+ return PTR_ERR(priv->eeprom_regmap);
}
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(dev, indio_dev);
if (ret) {
dev_err(dev, "Failed to register IIO device\n");
- goto err_cleanup_eeprom_regmap;
+ return ret;
}
- i2c_set_clientdata(client, indio_dev);
-
- return 0;
-
-err_cleanup_eeprom_regmap:
- regmap_exit(priv->eeprom_regmap);
-
-err_cleanup_eeprom_client:
- i2c_unregister_device(priv->eeprom_client);
- return ret;
-}
-
-static int hp03_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct hp03_priv *priv = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- regmap_exit(priv->eeprom_regmap);
- i2c_unregister_device(priv->eeprom_client);
-
return 0;
}
@@ -304,7 +283,6 @@ static struct i2c_driver hp03_driver = {
.of_match_table = hp03_of_match,
},
.probe = hp03_probe,
- .remove = hp03_remove,
.id_table = hp03_id,
};
module_i2c_driver(hp03_driver);
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 9417b3bd7513..156e6a72dc5c 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -43,7 +43,6 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata
#ifdef CONFIG_IIO_BUFFER
int st_press_allocate_ring(struct iio_dev *indio_dev);
-void st_press_deallocate_ring(struct iio_dev *indio_dev);
int st_press_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
@@ -51,10 +50,6 @@ static inline int st_press_allocate_ring(struct iio_dev *indio_dev)
{
return 0;
}
-
-static inline void st_press_deallocate_ring(struct iio_dev *indio_dev)
-{
-}
#define ST_PRESS_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c
index 7cf6f06797e1..25dbd5476b26 100644
--- a/drivers/iio/pressure/st_pressure_buffer.c
+++ b/drivers/iio/pressure/st_pressure_buffer.c
@@ -9,14 +9,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/common/st_sensors.h>
@@ -46,13 +41,8 @@ static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = {
int st_press_allocate_ring(struct iio_dev *indio_dev)
{
- return iio_triggered_buffer_setup(indio_dev, NULL,
- &st_sensors_trigger_handler, &st_press_buffer_setup_ops);
-}
-
-void st_press_deallocate_ring(struct iio_dev *indio_dev)
-{
- iio_triggered_buffer_cleanup(indio_dev);
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops);
}
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 7912b5a68395..ab1c17fac807 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -9,17 +9,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
-#include <linux/iio/buffer.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
@@ -724,7 +718,7 @@ int st_press_common_probe(struct iio_dev *indio_dev)
err = st_sensors_allocate_trigger(indio_dev,
ST_PRESS_TRIGGER_OPS);
if (err < 0)
- goto st_press_probe_trigger_error;
+ return err;
}
err = iio_device_register(indio_dev);
@@ -739,8 +733,6 @@ int st_press_common_probe(struct iio_dev *indio_dev)
st_press_device_register_error:
if (press_data->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-st_press_probe_trigger_error:
- st_press_deallocate_ring(indio_dev);
return err;
}
EXPORT_SYMBOL(st_press_common_probe);
@@ -752,8 +744,6 @@ void st_press_common_remove(struct iio_dev *indio_dev)
iio_device_unregister(indio_dev);
if (press_data->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
-
- st_press_deallocate_ring(indio_dev);
}
EXPORT_SYMBOL(st_press_common_remove);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index f0a5af314ceb..52fa98f24478 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -7,9 +7,10 @@
* Denis Ciocca <denis.ciocca@st.com>
*/
+#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index b48cf7d01cd7..ee393df54cee 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
+#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c
index 7a0472323f17..8c06d02139b6 100644
--- a/drivers/iio/proximity/rfd77402.c
+++ b/drivers/iio/proximity/rfd77402.c
@@ -90,18 +90,18 @@ static const struct iio_chan_spec rfd77402_channels[] = {
},
};
-static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
+static int rfd77402_set_state(struct i2c_client *client, u8 state, u16 check)
{
int ret;
- ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
+ ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
state | RFD77402_CMD_VALID);
if (ret < 0)
return ret;
usleep_range(10000, 20000);
- ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R);
+ ret = i2c_smbus_read_word_data(client, RFD77402_STATUS_R);
if (ret < 0)
return ret;
if ((ret & RFD77402_STATUS_PM_MASK) != check)
@@ -110,24 +110,24 @@ static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
return 0;
}
-static int rfd77402_measure(struct rfd77402_data *data)
+static int rfd77402_measure(struct i2c_client *client)
{
int ret;
int tries = 10;
- ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
+ ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
+ ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
if (ret < 0)
goto err;
while (tries-- > 0) {
- ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR);
+ ret = i2c_smbus_read_byte_data(client, RFD77402_ICSR);
if (ret < 0)
goto err;
if (ret & RFD77402_ICSR_RESULT)
@@ -140,7 +140,7 @@ static int rfd77402_measure(struct rfd77402_data *data)
goto err;
}
- ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
+ ret = i2c_smbus_read_word_data(client, RFD77402_RESULT_R);
if (ret < 0)
goto err;
@@ -153,7 +153,7 @@ static int rfd77402_measure(struct rfd77402_data *data)
return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
err:
- rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
+ rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
return ret;
}
@@ -168,7 +168,7 @@ static int rfd77402_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
- ret = rfd77402_measure(data);
+ ret = rfd77402_measure(data->client);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
@@ -188,23 +188,23 @@ static const struct iio_info rfd77402_info = {
.read_raw = rfd77402_read_raw,
};
-static int rfd77402_init(struct rfd77402_data *data)
+static int rfd77402_init(struct i2c_client *client)
{
int ret, i;
- ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
+ ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
if (ret < 0)
return ret;
/* configure INT pad as push-pull, active low */
- ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR,
+ ret = i2c_smbus_write_byte_data(client, RFD77402_ICSR,
RFD77402_ICSR_INT_MODE);
if (ret < 0)
return ret;
/* I2C configuration */
- ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG,
+ ret = i2c_smbus_write_word_data(client, RFD77402_I2C_INIT_CFG,
RFD77402_I2C_ADDR_INCR |
RFD77402_I2C_DATA_INCR |
RFD77402_I2C_HOST_DEBUG |
@@ -213,45 +213,50 @@ static int rfd77402_init(struct rfd77402_data *data)
return ret;
/* set initialization */
- ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
+ ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0500);
if (ret < 0)
return ret;
- ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
+ ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
if (ret < 0)
return ret;
/* set initialization */
- ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
+ ret = i2c_smbus_write_word_data(client, RFD77402_PMU_CFG, 0x0600);
if (ret < 0)
return ret;
- ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
+ ret = rfd77402_set_state(client, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) {
- ret = i2c_smbus_write_word_data(data->client,
+ ret = i2c_smbus_write_word_data(client,
rf77402_tof_config[i].reg,
rf77402_tof_config[i].val);
if (ret < 0)
return ret;
}
- ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
+ ret = rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
return ret;
}
-static int rfd77402_powerdown(struct rfd77402_data *data)
+static int rfd77402_powerdown(struct i2c_client *client)
{
- return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
+ return rfd77402_set_state(client, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
}
+static void rfd77402_disable(void *client)
+{
+ rfd77402_powerdown(client);
+}
+
static int rfd77402_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -270,7 +275,6 @@ static int rfd77402_probe(struct i2c_client *client,
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
@@ -280,46 +284,26 @@ static int rfd77402_probe(struct i2c_client *client,
indio_dev->name = RFD77402_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = rfd77402_init(data);
+ ret = rfd77402_init(client);
if (ret < 0)
return ret;
- ret = iio_device_register(indio_dev);
+ ret = devm_add_action_or_reset(&client->dev, rfd77402_disable, client);
if (ret)
- goto err_powerdown;
-
- return 0;
-
-err_powerdown:
- rfd77402_powerdown(data);
- return ret;
-}
-
-static int rfd77402_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- iio_device_unregister(indio_dev);
- rfd77402_powerdown(iio_priv(indio_dev));
+ return ret;
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int rfd77402_suspend(struct device *dev)
{
- struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
- to_i2c_client(dev)));
-
- return rfd77402_powerdown(data);
+ return rfd77402_powerdown(to_i2c_client(dev));
}
static int rfd77402_resume(struct device *dev)
{
- struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
- to_i2c_client(dev)));
-
- return rfd77402_init(data);
+ return rfd77402_init(to_i2c_client(dev));
}
#endif
@@ -337,7 +321,6 @@ static struct i2c_driver rfd77402_driver = {
.pm = &rfd77402_pm_ops,
},
.probe = rfd77402_probe,
- .remove = rfd77402_remove,
.id_table = rfd77402_id,
};
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 175f3b7c61d7..a3fdb59b06d2 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -20,6 +20,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -1221,10 +1222,9 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev)
}
static const struct sx9310_reg_default *
-sx9310_get_default_reg(struct sx9310_data *data, int idx,
+sx9310_get_default_reg(struct device *dev, int idx,
struct sx9310_reg_default *reg_def)
{
- const struct device_node *np = data->client->dev.of_node;
u32 combined[SX9310_NUM_CHANNELS];
u32 start = 0, raw = 0, pos = 0;
unsigned long comb_mask = 0;
@@ -1232,40 +1232,24 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
const char *res;
memcpy(reg_def, &sx9310_default_regs[idx], sizeof(*reg_def));
- if (!np)
- return reg_def;
-
switch (reg_def->reg) {
case SX9310_REG_PROX_CTRL2:
- if (of_property_read_bool(np, "semtech,cs0-ground")) {
+ if (device_property_read_bool(dev, "semtech,cs0-ground")) {
reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK;
reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND;
}
- count = of_property_count_elems_of_size(np, "semtech,combined-sensors",
- sizeof(u32));
- if (count > 0 && count <= ARRAY_SIZE(combined)) {
- ret = of_property_read_u32_array(np, "semtech,combined-sensors",
- combined, count);
- if (ret)
- break;
- } else {
- /*
- * Either the property does not exist in the DT or the
- * number of entries is incorrect.
- */
+ count = device_property_count_u32(dev, "semtech,combined-sensors");
+ if (count < 0 || count > ARRAY_SIZE(combined))
break;
- }
- for (i = 0; i < count; i++) {
- if (combined[i] >= SX9310_NUM_CHANNELS) {
- /* Invalid sensor (invalid DT). */
- break;
- }
- comb_mask |= BIT(combined[i]);
- }
- if (i < count)
+ ret = device_property_read_u32_array(dev, "semtech,combined-sensors",
+ combined, count);
+ if (ret)
break;
+ for (i = 0; i < count; i++)
+ comb_mask |= BIT(combined[i]);
+
reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK;
if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3;
@@ -1278,7 +1262,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
break;
case SX9310_REG_PROX_CTRL4:
- ret = of_property_read_string(np, "semtech,resolution", &res);
+ ret = device_property_read_string(dev, "semtech,resolution", &res);
if (ret)
break;
@@ -1302,7 +1286,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
break;
case SX9310_REG_PROX_CTRL5:
- ret = of_property_read_u32(np, "semtech,startup-sensor", &start);
+ ret = device_property_read_u32(dev, "semtech,startup-sensor", &start);
if (ret) {
start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
reg_def->def);
@@ -1312,7 +1296,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK,
start);
- ret = of_property_read_u32(np, "semtech,proxraw-strength", &raw);
+ ret = device_property_read_u32(dev, "semtech,proxraw-strength", &raw);
if (ret) {
raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK,
reg_def->def);
@@ -1325,7 +1309,7 @@ sx9310_get_default_reg(struct sx9310_data *data, int idx,
raw);
break;
case SX9310_REG_PROX_CTRL7:
- ret = of_property_read_u32(np, "semtech,avg-pos-strength", &pos);
+ ret = device_property_read_u32(dev, "semtech,avg-pos-strength", &pos);
if (ret)
break;
@@ -1361,7 +1345,7 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
/* Program some sane defaults. */
for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
- initval = sx9310_get_default_reg(data, i, &tmp);
+ initval = sx9310_get_default_reg(&indio_dev->dev, i, &tmp);
ret = regmap_write(data->regmap, initval->reg, initval->def);
if (ret)
return ret;
diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
index 43817f6b3086..ff83638db16f 100644
--- a/drivers/iio/proximity/vcnl3020.c
+++ b/drivers/iio/proximity/vcnl3020.c
@@ -2,8 +2,6 @@
/*
* Support for Vishay VCNL3020 proximity sensor on i2c bus.
* Based on Vishay VCNL4000 driver code.
- *
- * TODO: interrupts.
*/
#include <linux/module.h>
@@ -11,9 +9,10 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regmap.h>
+#include <linux/interrupt.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#define VCNL3020_PROD_ID 0x21
@@ -37,6 +36,21 @@
* measurement
*/
+/* Enables periodic proximity measurement */
+#define VCNL_PS_EN BIT(1)
+
+/* Enables state machine and LP oscillator for self timed measurements */
+#define VCNL_PS_SELFTIMED_EN BIT(0)
+
+/* Bit masks for ICR */
+
+/* Enable interrupts on low or high thresholds */
+#define VCNL_ICR_THRES_EN BIT(1)
+
+/* Bit masks for ISR */
+#define VCNL_INT_TH_HI BIT(0) /* High threshold hit */
+#define VCNL_INT_TH_LOW BIT(1) /* Low threshold hit */
+
#define VCNL_ON_DEMAND_TIMEOUT_US 100000
#define VCNL_POLL_US 20000
@@ -57,12 +71,14 @@ static const int vcnl3020_prox_sampling_frequency[][2] = {
* @dev: vcnl3020 device.
* @rev: revision id.
* @lock: lock for protecting access to device hardware registers.
+ * @buf: DMA safe __be16 buffer.
*/
struct vcnl3020_data {
struct regmap *regmap;
struct device *dev;
u8 rev;
struct mutex lock;
+ __be16 buf ____cacheline_aligned;
};
/**
@@ -140,14 +156,34 @@ static int vcnl3020_init(struct vcnl3020_data *data)
vcnl3020_led_current_property);
};
+static bool vcnl3020_is_in_periodic_mode(struct vcnl3020_data *data)
+{
+ int rc;
+ unsigned int cmd;
+
+ rc = regmap_read(data->regmap, VCNL_COMMAND, &cmd);
+ if (rc) {
+ dev_err(data->dev,
+ "Error (%d) reading command register\n", rc);
+ return false;
+ }
+
+ return !!(cmd & VCNL_PS_SELFTIMED_EN);
+}
+
static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
{
int rc;
unsigned int reg;
- __be16 res;
mutex_lock(&data->lock);
+ /* Protect against event capture. */
+ if (vcnl3020_is_in_periodic_mode(data)) {
+ rc = -EBUSY;
+ goto err_unlock;
+ }
+
rc = regmap_write(data->regmap, VCNL_COMMAND, VCNL_PS_OD);
if (rc)
goto err_unlock;
@@ -163,12 +199,12 @@ static int vcnl3020_measure_proximity(struct vcnl3020_data *data, int *val)
}
/* high & low result bytes read */
- rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &res,
- sizeof(res));
+ rc = regmap_bulk_read(data->regmap, VCNL_PS_RESULT_HI, &data->buf,
+ sizeof(data->buf));
if (rc)
goto err_unlock;
- *val = be16_to_cpu(res);
+ *val = be16_to_cpu(data->buf);
err_unlock:
mutex_unlock(&data->lock);
@@ -200,6 +236,15 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
{
unsigned int i;
int index = -1;
+ int rc;
+
+ mutex_lock(&data->lock);
+
+ /* Protect against event capture. */
+ if (vcnl3020_is_in_periodic_mode(data)) {
+ rc = -EBUSY;
+ goto err_unlock;
+ }
for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
if (val == vcnl3020_prox_sampling_frequency[i][0] &&
@@ -209,18 +254,250 @@ static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
}
}
- if (index < 0)
+ if (index < 0) {
+ rc = -EINVAL;
+ goto err_unlock;
+ }
+
+ rc = regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
+ if (rc)
+ dev_err(data->dev,
+ "Error (%d) writing proximity rate register\n", rc);
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return rc;
+}
+
+static bool vcnl3020_is_thr_enabled(struct vcnl3020_data *data)
+{
+ int rc;
+ unsigned int icr;
+
+ rc = regmap_read(data->regmap, VCNL_PS_ICR, &icr);
+ if (rc) {
+ dev_err(data->dev,
+ "Error (%d) reading ICR register\n", rc);
+ return false;
+ }
+
+ return !!(icr & VCNL_ICR_THRES_EN);
+}
+
+static int vcnl3020_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ int rc;
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ rc = regmap_bulk_read(data->regmap, VCNL_PS_HI_THR_HI,
+ &data->buf, sizeof(data->buf));
+ if (rc < 0)
+ return rc;
+ *val = be16_to_cpu(data->buf);
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_FALLING:
+ rc = regmap_bulk_read(data->regmap, VCNL_PS_LO_THR_HI,
+ &data->buf, sizeof(data->buf));
+ if (rc < 0)
+ return rc;
+ *val = be16_to_cpu(data->buf);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
return -EINVAL;
+ }
+}
+
+static int vcnl3020_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ int rc;
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->lock);
- return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ /* 16 bit word/ low * high */
+ data->buf = cpu_to_be16(val);
+ rc = regmap_bulk_write(data->regmap, VCNL_PS_HI_THR_HI,
+ &data->buf, sizeof(data->buf));
+ if (rc < 0)
+ goto err_unlock;
+ rc = IIO_VAL_INT;
+ goto err_unlock;
+ case IIO_EV_DIR_FALLING:
+ data->buf = cpu_to_be16(val);
+ rc = regmap_bulk_write(data->regmap, VCNL_PS_LO_THR_HI,
+ &data->buf, sizeof(data->buf));
+ if (rc < 0)
+ goto err_unlock;
+ rc = IIO_VAL_INT;
+ goto err_unlock;
+ default:
+ rc = -EINVAL;
+ goto err_unlock;
+ }
+ default:
+ rc = -EINVAL;
+ goto err_unlock;
+ }
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return rc;
}
+static int vcnl3020_enable_periodic(struct iio_dev *indio_dev,
+ struct vcnl3020_data *data)
+{
+ int rc;
+ int cmd;
+
+ mutex_lock(&data->lock);
+
+ /* Enable periodic measurement of proximity data. */
+ cmd = VCNL_PS_EN | VCNL_PS_SELFTIMED_EN;
+
+ rc = regmap_write(data->regmap, VCNL_COMMAND, cmd);
+ if (rc) {
+ dev_err(data->dev,
+ "Error (%d) writing command register\n", rc);
+ goto err_unlock;
+ }
+
+ /*
+ * Enable interrupts on threshold, for proximity data by
+ * default.
+ */
+ rc = regmap_write(data->regmap, VCNL_PS_ICR, VCNL_ICR_THRES_EN);
+ if (rc)
+ dev_err(data->dev,
+ "Error (%d) reading ICR register\n", rc);
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return rc;
+}
+
+static int vcnl3020_disable_periodic(struct iio_dev *indio_dev,
+ struct vcnl3020_data *data)
+{
+ int rc;
+
+ mutex_lock(&data->lock);
+
+ rc = regmap_write(data->regmap, VCNL_COMMAND, 0);
+ if (rc) {
+ dev_err(data->dev,
+ "Error (%d) writing command register\n", rc);
+ goto err_unlock;
+ }
+
+ rc = regmap_write(data->regmap, VCNL_PS_ICR, 0);
+ if (rc) {
+ dev_err(data->dev,
+ "Error (%d) writing ICR register\n", rc);
+ goto err_unlock;
+ }
+
+ /* Clear interrupt flag bit */
+ rc = regmap_write(data->regmap, VCNL_ISR, 0);
+ if (rc)
+ dev_err(data->dev,
+ "Error (%d) writing ISR register\n", rc);
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return rc;
+}
+
+static int vcnl3020_config_threshold(struct iio_dev *indio_dev, bool state)
+{
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+
+ if (state) {
+ return vcnl3020_enable_periodic(indio_dev, data);
+ } else {
+ if (!vcnl3020_is_thr_enabled(data))
+ return 0;
+ return vcnl3020_disable_periodic(indio_dev, data);
+ }
+}
+
+static int vcnl3020_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ return vcnl3020_config_threshold(indio_dev, state);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vcnl3020_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ return vcnl3020_is_thr_enabled(data);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_event_spec vcnl3020_event_spec[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
static const struct iio_chan_spec vcnl3020_channels[] = {
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .event_spec = vcnl3020_event_spec,
+ .num_event_specs = ARRAY_SIZE(vcnl3020_event_spec),
},
};
@@ -251,17 +528,11 @@ static int vcnl3020_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
- int rc;
struct vcnl3020_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- rc = iio_device_claim_direct_mode(indio_dev);
- if (rc)
- return rc;
- rc = vcnl3020_write_proxy_samp_freq(data, val, val2);
- iio_device_release_direct_mode(indio_dev);
- return rc;
+ return vcnl3020_write_proxy_samp_freq(data, val, val2);
default:
return -EINVAL;
}
@@ -287,6 +558,10 @@ static const struct iio_info vcnl3020_info = {
.read_raw = vcnl3020_read_raw,
.write_raw = vcnl3020_write_raw,
.read_avail = vcnl3020_read_avail,
+ .read_event_value = vcnl3020_read_event,
+ .write_event_value = vcnl3020_write_event,
+ .read_event_config = vcnl3020_read_event_config,
+ .write_event_config = vcnl3020_write_event_config,
};
static const struct regmap_config vcnl3020_regmap_config = {
@@ -295,6 +570,37 @@ static const struct regmap_config vcnl3020_regmap_config = {
.max_register = VCNL_PS_MOD_ADJ,
};
+static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct vcnl3020_data *data = iio_priv(indio_dev);
+ unsigned int isr;
+ int rc;
+
+ rc = regmap_read(data->regmap, VCNL_ISR, &isr);
+ if (rc) {
+ dev_err(data->dev, "Error (%d) reading reg (0x%x)\n",
+ rc, VCNL_ISR);
+ return IRQ_HANDLED;
+ }
+
+ if (!(isr & VCNL_ICR_THRES_EN))
+ return IRQ_NONE;
+
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns(indio_dev));
+
+ rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN);
+ if (rc)
+ dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n",
+ rc, VCNL_ISR);
+
+ return IRQ_HANDLED;
+}
+
static int vcnl3020_probe(struct i2c_client *client)
{
struct vcnl3020_data *data;
@@ -327,6 +633,19 @@ static int vcnl3020_probe(struct i2c_client *client)
indio_dev->name = "vcnl3020";
indio_dev->modes = INDIO_DIRECT_MODE;
+ if (client->irq) {
+ rc = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, vcnl3020_handle_irq_thread,
+ IRQF_ONESHOT, indio_dev->name,
+ indio_dev);
+ if (rc) {
+ dev_err(&client->dev,
+ "Error (%d) irq request failed (%u)\n", rc,
+ client->irq);
+ return rc;
+ }
+ }
+
return devm_iio_device_register(&client->dev, indio_dev);
}
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index 3b5ba26d7d86..3b4a0e60e605 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -89,6 +89,8 @@
#define LTC2983_STATUS_START_MASK BIT(7)
#define LTC2983_STATUS_START(x) FIELD_PREP(LTC2983_STATUS_START_MASK, x)
+#define LTC2983_STATUS_UP_MASK GENMASK(7, 6)
+#define LTC2983_STATUS_UP(reg) FIELD_GET(LTC2983_STATUS_UP_MASK, reg)
#define LTC2983_STATUS_CHAN_SEL_MASK GENMASK(4, 0)
#define LTC2983_STATUS_CHAN_SEL(x) \
@@ -1362,17 +1364,16 @@ put_child:
static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio)
{
- u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0;
+ u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0, status;
int ret;
- unsigned long time;
-
- /* make sure the device is up */
- time = wait_for_completion_timeout(&st->completion,
- msecs_to_jiffies(250));
- if (!time) {
+ /* make sure the device is up: start bit (7) is 0 and done bit (6) is 1 */
+ ret = regmap_read_poll_timeout(st->regmap, LTC2983_STATUS_REG, status,
+ LTC2983_STATUS_UP(status) == 1, 25000,
+ 25000 * 10);
+ if (ret) {
dev_err(&st->spi->dev, "Device startup timed out\n");
- return -ETIMEDOUT;
+ return ret;
}
st->iio_chan = devm_kzalloc(&st->spi->dev,
@@ -1492,10 +1493,11 @@ static int ltc2983_probe(struct spi_device *spi)
ret = ltc2983_parse_dt(st);
if (ret)
return ret;
- /*
- * let's request the irq now so it is used to sync the device
- * startup in ltc2983_setup()
- */
+
+ ret = ltc2983_setup(st, true);
+ if (ret)
+ return ret;
+
ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
IRQF_TRIGGER_RISING, name, st);
if (ret) {
@@ -1503,10 +1505,6 @@ static int ltc2983_probe(struct spi_device *spi)
return ret;
}
- ret = ltc2983_setup(st, true);
- if (ret)
- return ret;
-
indio_dev->name = name;
indio_dev->num_channels = st->iio_channels;
indio_dev->channels = st->iio_chan;
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index 54976c7dad92..e4943a0bc9aa 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -193,6 +193,25 @@ static bool tmp006_check_identification(struct i2c_client *client)
return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC;
}
+static int tmp006_power(struct device *dev, bool up)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct tmp006_data *data = iio_priv(indio_dev);
+
+ if (up)
+ data->config |= TMP006_CONFIG_MOD_MASK;
+ else
+ data->config &= ~TMP006_CONFIG_MOD_MASK;
+
+ return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+ data->config);
+}
+
+static void tmp006_powerdown_cleanup(void *dev)
+{
+ tmp006_power(dev, false);
+}
+
static int tmp006_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -228,38 +247,29 @@ static int tmp006_probe(struct i2c_client *client,
return ret;
data->config = ret;
- return iio_device_register(indio_dev);
-}
-
-static int tmp006_powerdown(struct tmp006_data *data)
-{
- return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
- data->config & ~TMP006_CONFIG_MOD_MASK);
-}
-
-static int tmp006_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) {
+ ret = tmp006_power(&client->dev, true);
+ if (ret < 0)
+ return ret;
+ }
- iio_device_unregister(indio_dev);
- tmp006_powerdown(iio_priv(indio_dev));
+ ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup,
+ &client->dev);
+ if (ret < 0)
+ return ret;
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int tmp006_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
- return tmp006_powerdown(iio_priv(indio_dev));
+ return tmp006_power(dev, false);
}
static int tmp006_resume(struct device *dev)
{
- struct tmp006_data *data = iio_priv(i2c_get_clientdata(
- to_i2c_client(dev)));
- return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
- data->config | TMP006_CONFIG_MOD_MASK);
+ return tmp006_power(dev, true);
}
#endif
@@ -277,7 +287,6 @@ static struct i2c_driver tmp006_driver = {
.pm = &tmp006_pm_ops,
},
.probe = tmp006_probe,
- .remove = tmp006_remove,
.id_table = tmp006_id,
};
module_i2c_driver(tmp006_driver);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6a3fd2d75f96..01bb42f0ca0b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -510,6 +510,22 @@ config MFD_HI6421_PMIC
menus in order to enable them.
We communicate with the Hi6421 via memory-mapped I/O.
+config MFD_HI6421_SPMI
+ tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
+ depends on OF
+ depends on SPMI
+ select MFD_CORE
+ select REGMAP_SPMI
+ help
+ Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
+ multi-functions, such as regulators, RTC, codec, Coulomb counter,
+ etc.
+
+ This driver includes core APIs _only_. You have to select
+ individual components like voltage regulators under corresponding
+ menus in order to enable them.
+ We communicate with the Hi6421v600 via a SPMI bus.
+
config MFD_HI655X_PMIC
tristate "HiSilicon Hi655X series PMU/Codec IC"
depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8116c19d5fd4..570b9ffb34d0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -231,6 +231,7 @@ obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
obj-$(CONFIG_MFD_IQS62X) += iqs62x.o
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
+obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT4831) += rt4831.o
diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c
new file mode 100644
index 000000000000..4f136826681b
--- /dev/null
+++ b/drivers/mfd/hi6421-spmi-pmic.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for regulators in HISI PMIC IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
+ */
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+static const struct mfd_cell hi6421v600_devs[] = {
+ { .name = "hi6421v600-irq", },
+ { .name = "hi6421v600-regulator", },
+};
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 16,
+ .val_bits = BITS_PER_BYTE,
+ .max_register = 0xffff,
+ .fast_io = true
+};
+
+static int hi6421_spmi_pmic_probe(struct spmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ int ret;
+ struct hi6421_spmi_pmic *ddata;
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ ddata->regmap = devm_regmap_init_spmi_ext(sdev, &regmap_config);
+ if (IS_ERR(ddata->regmap))
+ return PTR_ERR(ddata->regmap);
+
+ ddata->dev = dev;
+
+ dev_set_drvdata(&sdev->dev, ddata);
+
+ ret = devm_mfd_add_devices(&sdev->dev, PLATFORM_DEVID_NONE,
+ hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
+ NULL, 0, NULL);
+ if (ret < 0)
+ dev_err(dev, "Failed to add child devices: %d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id pmic_spmi_id_table[] = {
+ { .compatible = "hisilicon,hi6421-spmi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
+
+static struct spmi_driver hi6421_spmi_pmic_driver = {
+ .driver = {
+ .name = "hi6421-spmi-pmic",
+ .of_match_table = pmic_spmi_id_table,
+ },
+ .probe = hi6421_spmi_pmic_probe,
+};
+module_spmi_driver(hi6421_spmi_pmic_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a420b59917db..85ba901bc11b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -220,6 +220,16 @@ config GEHC_ACHC
To compile this driver as a module, choose M here: the
module will be called gehc-achc.
+config HI6421V600_IRQ
+ tristate "HiSilicon Hi6421v600 IRQ and powerkey"
+ depends on OF
+ depends on SPMI
+ select MFD_CORE
+ select REGMAP_SPMI
+ help
+ This driver provides IRQ handling for Hi6421v600, used on
+ some Kirin chipsets, like the one at Hikey 970.
+
config HP_ILO
tristate "Channel interface driver for the HP iLO processor"
depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 68b7b0736f16..a086197af544 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
+obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c
new file mode 100644
index 000000000000..08535e97ff43
--- /dev/null
+++ b/drivers/misc/hi6421v600-irq.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for irqs in HISI PMIC IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+struct hi6421v600_irq {
+ struct device *dev;
+ struct irq_domain *domain;
+ int irq;
+ unsigned int *irqs;
+ struct regmap *regmap;
+
+ /* Protect IRQ mask changes */
+ spinlock_t lock;
+};
+
+enum hi6421v600_irq_list {
+ OTMP = 0,
+ VBUS_CONNECT,
+ VBUS_DISCONNECT,
+ ALARMON_R,
+ HOLD_6S,
+ HOLD_1S,
+ POWERKEY_UP,
+ POWERKEY_DOWN,
+ OCP_SCP_R,
+ COUL_R,
+ SIM0_HPD_R,
+ SIM0_HPD_F,
+ SIM1_HPD_R,
+ SIM1_HPD_F,
+
+ PMIC_IRQ_LIST_MAX
+};
+
+#define HISI_IRQ_BANK_SIZE 2
+
+/*
+ * IRQ number for the power key button and mask for both UP and DOWN IRQs
+ */
+#define HISI_POWERKEY_IRQ_NUM 0
+#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
+
+/*
+ * Registers for IRQ address and IRQ mask bits
+ *
+ * Please notice that we need to regmap a larger region, as other
+ * registers are used by the irqs.
+ * See drivers/irq/hi6421-irq.c.
+ */
+#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
+#define SOC_PMIC_IRQ0_ADDR 0x0212
+
+/*
+ * The IRQs are mapped as:
+ *
+ * ====================== ============= ============ =====
+ * IRQ MASK REGISTER IRQ REGISTER BIT
+ * ====================== ============= ============ =====
+ * OTMP 0x0202 0x212 bit 0
+ * VBUS_CONNECT 0x0202 0x212 bit 1
+ * VBUS_DISCONNECT 0x0202 0x212 bit 2
+ * ALARMON_R 0x0202 0x212 bit 3
+ * HOLD_6S 0x0202 0x212 bit 4
+ * HOLD_1S 0x0202 0x212 bit 5
+ * POWERKEY_UP 0x0202 0x212 bit 6
+ * POWERKEY_DOWN 0x0202 0x212 bit 7
+ *
+ * OCP_SCP_R 0x0203 0x213 bit 0
+ * COUL_R 0x0203 0x213 bit 1
+ * SIM0_HPD_R 0x0203 0x213 bit 2
+ * SIM0_HPD_F 0x0203 0x213 bit 3
+ * SIM1_HPD_R 0x0203 0x213 bit 4
+ * SIM1_HPD_F 0x0203 0x213 bit 5
+ * ====================== ============= ============ =====
+ *
+ * Each mask register contains 8 bits. The ancillary macros below
+ * convert a number from 0 to 14 into a register address and a bit mask
+ */
+#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
+ (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
+#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
+#define HISI_8BITS_MASK 0xff
+
+static irqreturn_t hi6421v600_irq_handler(int irq, void *__priv)
+{
+ struct hi6421v600_irq *priv = __priv;
+ unsigned long pending;
+ unsigned int in;
+ int i, offset;
+
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
+
+ /* Mark pending IRQs as handled */
+ regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, in);
+
+ pending = in & HISI_8BITS_MASK;
+
+ if (i == HISI_POWERKEY_IRQ_NUM &&
+ (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
+ /*
+ * If both powerkey down and up IRQs are received,
+ * handle them at the right order
+ */
+ generic_handle_irq(priv->irqs[POWERKEY_DOWN]);
+ generic_handle_irq(priv->irqs[POWERKEY_UP]);
+ pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
+ }
+
+ if (!pending)
+ continue;
+
+ for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
+ generic_handle_irq(priv->irqs[offset + i * BITS_PER_BYTE]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hi6421v600_irq_mask(struct irq_data *d)
+{
+ struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ unsigned int data;
+ u32 offset;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ regmap_read(priv->regmap, offset, &data);
+ data |= HISI_IRQ_MASK_BIT(d);
+ regmap_write(priv->regmap, offset, data);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void hi6421v600_irq_unmask(struct irq_data *d)
+{
+ struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+ unsigned long flags;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ regmap_read(priv->regmap, offset, &data);
+ data &= ~HISI_IRQ_MASK_BIT(d);
+ regmap_write(priv->regmap, offset, data);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static struct irq_chip hi6421v600_pmu_irqchip = {
+ .name = "hi6421v600-irq",
+ .irq_mask = hi6421v600_irq_mask,
+ .irq_unmask = hi6421v600_irq_unmask,
+ .irq_disable = hi6421v600_irq_mask,
+ .irq_enable = hi6421v600_irq_unmask,
+};
+
+static int hi6421v600_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct hi6421v600_irq *priv = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &hi6421v600_pmu_irqchip,
+ handle_simple_irq, "hi6421v600");
+ irq_set_chip_data(virq, priv);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops hi6421v600_domain_ops = {
+ .map = hi6421v600_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void hi6421v600_irq_init(struct hi6421v600_irq *priv)
+{
+ int i;
+ unsigned int pending;
+
+ /* Mask all IRQs */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
+ regmap_write(priv->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
+ HISI_8BITS_MASK);
+
+ /* Mark all IRQs as handled */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
+ regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i,
+ HISI_8BITS_MASK);
+ }
+}
+
+static int hi6421v600_irq_probe(struct platform_device *pdev)
+{
+ struct device *pmic_dev = pdev->dev.parent;
+ struct device_node *np = pmic_dev->of_node;
+ struct platform_device *pmic_pdev;
+ struct device *dev = &pdev->dev;
+ struct hi6421v600_irq *priv;
+ struct hi6421_spmi_pmic *pmic;
+ unsigned int virq;
+ int i, ret;
+
+ /*
+ * This driver is meant to be called by hi6421-spmi-core,
+ * which should first set drvdata. If this doesn't happen, hit
+ * a warn on and return.
+ */
+ pmic = dev_get_drvdata(pmic_dev);
+ if (WARN_ON(!pmic))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->regmap = pmic->regmap;
+
+ spin_lock_init(&priv->lock);
+
+ pmic_pdev = container_of(pmic_dev, struct platform_device, dev);
+
+ priv->irq = platform_get_irq(pmic_pdev, 0);
+ if (priv->irq < 0) {
+ dev_err(dev, "Error %d when getting IRQs\n", priv->irq);
+ return priv->irq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ hi6421v600_irq_init(priv);
+
+ priv->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
+ if (!priv->irqs)
+ return -ENOMEM;
+
+ priv->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
+ &hi6421v600_domain_ops, priv);
+ if (!priv->domain) {
+ dev_err(dev, "Failed to create IRQ domain\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
+ virq = irq_create_mapping(priv->domain, i);
+ if (!virq) {
+ dev_err(dev, "Failed to map H/W IRQ\n");
+ return -ENODEV;
+ }
+ priv->irqs[i] = virq;
+ }
+
+ ret = devm_request_threaded_irq(dev,
+ priv->irq, hi6421v600_irq_handler,
+ NULL,
+ IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pmic", priv);
+ if (ret < 0) {
+ dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id hi6421v600_irq_table[] = {
+ { .name = "hi6421v600-irq" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, hi6421v600_irq_table);
+
+static struct platform_driver hi6421v600_irq_driver = {
+ .id_table = hi6421v600_irq_table,
+ .driver = {
+ .name = "hi6421v600-irq",
+ },
+ .probe = hi6421v600_irq_probe,
+};
+module_platform_driver(hi6421v600_irq_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 IRQ driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index c8eaae6412bb..e03627ad4460 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -36,7 +36,7 @@ source "drivers/staging/rtl8723bs/Kconfig"
source "drivers/staging/rtl8712/Kconfig"
-source "drivers/staging/rtl8188eu/Kconfig"
+source "drivers/staging/r8188eu/Kconfig"
source "drivers/staging/rts5208/Kconfig"
@@ -102,6 +102,4 @@ source "drivers/staging/qlge/Kconfig"
source "drivers/staging/wfx/Kconfig"
-source "drivers/staging/hikey9xx/Kconfig"
-
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 818b6f964369..c7f8d8d8dd11 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_RTL8723BS) += rtl8723bs/
obj-$(CONFIG_R8712U) += rtl8712/
-obj-$(CONFIG_R8188EU) += rtl8188eu/
+obj-$(CONFIG_R8188EU) += r8188eu/
obj-$(CONFIG_RTS5208) += rts5208/
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
@@ -41,4 +41,3 @@ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_WFX) += wfx/
-obj-y += hikey9xx/
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
index cb6feb34dd40..f980af037345 100644
--- a/drivers/staging/board/board.c
+++ b/drivers/staging/board/board.c
@@ -136,6 +136,7 @@ int __init board_staging_register_clock(const struct board_staging_clk *bsc)
static int board_staging_add_dev_domain(struct platform_device *pdev,
const char *domain)
{
+ struct device *dev = &pdev->dev;
struct of_phandle_args pd_args;
struct device_node *np;
@@ -148,7 +149,11 @@ static int board_staging_add_dev_domain(struct platform_device *pdev,
pd_args.np = np;
pd_args.args_count = 0;
- return of_genpd_add_device(&pd_args, &pdev->dev);
+ /* Initialization similar to device_pm_init_common() */
+ spin_lock_init(&dev->power.lock);
+ dev->power.early_init = true;
+
+ return of_genpd_add_device(&pd_args, dev);
}
#else
static inline int board_staging_add_dev_domain(struct platform_device *pdev,
diff --git a/drivers/staging/clocking-wizard/Kconfig b/drivers/staging/clocking-wizard/Kconfig
index 69cf51445f08..2324b5d73788 100644
--- a/drivers/staging/clocking-wizard/Kconfig
+++ b/drivers/staging/clocking-wizard/Kconfig
@@ -5,6 +5,6 @@
config COMMON_CLK_XLNX_CLKWZRD
tristate "Xilinx Clocking Wizard"
- depends on COMMON_CLK && OF && IOMEM
+ depends on COMMON_CLK && OF && HAS_IOMEM
help
Support for the Xilinx Clocking Wizard IP core clock generator.
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 3723269890d5..ed992ca605eb 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -992,9 +992,7 @@ out_free:
int fbtft_init_display(struct fbtft_par *par)
{
int buf[64];
- char msg[128];
- char str[16];
- int i = 0;
+ int i;
int j;
/* sanity check */
@@ -1005,9 +1003,11 @@ int fbtft_init_display(struct fbtft_par *par)
}
/* make sure stop marker exists */
- for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++)
+ for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++) {
if (par->init_sequence[i] == -3)
break;
+ }
+
if (i == FBTFT_MAX_INIT_SEQUENCE) {
dev_err(par->info->device,
"missing stop marker at end of init sequence\n");
@@ -1036,17 +1036,14 @@ int fbtft_init_display(struct fbtft_par *par)
switch (par->init_sequence[i]) {
case -1:
i++;
+
/* make debug message */
- strcpy(msg, "");
- j = i + 1;
- while (par->init_sequence[j] >= 0) {
- sprintf(str, "0x%02X ", par->init_sequence[j]);
- strcat(msg, str);
- j++;
- }
+ for (j = 0; par->init_sequence[i + 1 + j] >= 0; j++);
+
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
- "init: write(0x%02X) %s\n",
- par->init_sequence[i], msg);
+ "init: write(0x%02X) %*ph\n",
+ par->init_sequence[i], j,
+ &par->init_sequence[i + 1]);
/* Write */
j = 0;
diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c
index 7902e52a699b..8f39cc5617aa 100644
--- a/drivers/staging/gdm724x/netlink_k.c
+++ b/drivers/staging/gdm724x/netlink_k.c
@@ -19,8 +19,8 @@ static DEFINE_MUTEX(netlink_mutex);
#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + \
ND_IFINDEX_LEN))
-#define ND_NLMSG_S_LEN(len) (len + ND_IFINDEX_LEN)
-#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len - ND_IFINDEX_LEN)
+#define ND_NLMSG_S_LEN(len) ((len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh) ((nlh)->nlmsg_len - ND_IFINDEX_LEN)
#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
#define ND_MAX_MSG_LEN (1024 * 32)
diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig
deleted file mode 100644
index 9f53df9068fe..000000000000
--- a/drivers/staging/hikey9xx/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# to be placed at drivers/mfd
-config MFD_HI6421_SPMI
- tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC"
- depends on HAS_IOMEM
- depends on OF
- depends on SPMI
- select MFD_CORE
- select REGMAP_SPMI
- help
- Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes
- multi-functions, such as regulators, RTC, codec, Coulomb counter,
- etc.
-
- This driver includes core APIs _only_. You have to select
- individual components like voltage regulators under corresponding
- menus in order to enable them.
- We communicate with the Hi6421v600 via a SPMI bus.
diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile
deleted file mode 100644
index e3108d7dd849..000000000000
--- a/drivers/staging/hikey9xx/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
diff --git a/drivers/staging/hikey9xx/TODO b/drivers/staging/hikey9xx/TODO
deleted file mode 100644
index 65e7996a3066..000000000000
--- a/drivers/staging/hikey9xx/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-ToDo list:
-
-- Port other drivers needed by Hikey 960/970;
-- Test drivers on Hikey 960;
-- Validate device tree bindings.
diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
deleted file mode 100644
index 35ef3d4c760b..000000000000
--- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c
+++ /dev/null
@@ -1,311 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Device driver for regulators in HISI PMIC IC
- *
- * Copyright (c) 2013 Linaro Ltd.
- * Copyright (c) 2011 Hisilicon.
- * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
- */
-
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/hi6421-spmi-pmic.h>
-#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spmi.h>
-
-enum hi6421_spmi_pmic_irq_list {
- OTMP = 0,
- VBUS_CONNECT,
- VBUS_DISCONNECT,
- ALARMON_R,
- HOLD_6S,
- HOLD_1S,
- POWERKEY_UP,
- POWERKEY_DOWN,
- OCP_SCP_R,
- COUL_R,
- SIM0_HPD_R,
- SIM0_HPD_F,
- SIM1_HPD_R,
- SIM1_HPD_F,
-
- PMIC_IRQ_LIST_MAX
-};
-
-#define HISI_IRQ_BANK_SIZE 2
-
-/*
- * IRQ number for the power key button and mask for both UP and DOWN IRQs
- */
-#define HISI_POWERKEY_IRQ_NUM 0
-#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
-
-/*
- * Registers for IRQ address and IRQ mask bits
- *
- * Please notice that we need to regmap a larger region, as other
- * registers are used by the regulators.
- * See drivers/regulator/hi6421-regulator.c.
- */
-#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
-#define SOC_PMIC_IRQ0_ADDR 0x0212
-
-/*
- * The IRQs are mapped as:
- *
- * ====================== ============= ============ =====
- * IRQ MASK REGISTER IRQ REGISTER BIT
- * ====================== ============= ============ =====
- * OTMP 0x0202 0x212 bit 0
- * VBUS_CONNECT 0x0202 0x212 bit 1
- * VBUS_DISCONNECT 0x0202 0x212 bit 2
- * ALARMON_R 0x0202 0x212 bit 3
- * HOLD_6S 0x0202 0x212 bit 4
- * HOLD_1S 0x0202 0x212 bit 5
- * POWERKEY_UP 0x0202 0x212 bit 6
- * POWERKEY_DOWN 0x0202 0x212 bit 7
- *
- * OCP_SCP_R 0x0203 0x213 bit 0
- * COUL_R 0x0203 0x213 bit 1
- * SIM0_HPD_R 0x0203 0x213 bit 2
- * SIM0_HPD_F 0x0203 0x213 bit 3
- * SIM1_HPD_R 0x0203 0x213 bit 4
- * SIM1_HPD_F 0x0203 0x213 bit 5
- * ====================== ============= ============ =====
- *
- * Each mask register contains 8 bits. The ancillary macros below
- * convert a number from 0 to 14 into a register address and a bit mask
- */
-#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
- (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
-#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
-#define HISI_8BITS_MASK 0xff
-
-static const struct mfd_cell hi6421v600_devs[] = {
- { .name = "hi6421v600-regulator", },
-};
-
-static irqreturn_t hi6421_spmi_irq_handler(int irq, void *priv)
-{
- struct hi6421_spmi_pmic *ddata = (struct hi6421_spmi_pmic *)priv;
- unsigned long pending;
- unsigned int in;
- int i, offset;
-
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
- regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
-
- /* Mark pending IRQs as handled */
- regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, in);
-
- pending = in & HISI_8BITS_MASK;
-
- if (i == HISI_POWERKEY_IRQ_NUM &&
- (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
- /*
- * If both powerkey down and up IRQs are received,
- * handle them at the right order
- */
- generic_handle_irq(ddata->irqs[POWERKEY_DOWN]);
- generic_handle_irq(ddata->irqs[POWERKEY_UP]);
- pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
- }
-
- if (!pending)
- continue;
-
- for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
- generic_handle_irq(ddata->irqs[offset + i * BITS_PER_BYTE]);
- }
- }
-
- return IRQ_HANDLED;
-}
-
-static void hi6421_spmi_irq_mask(struct irq_data *d)
-{
- struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
- unsigned long flags;
- unsigned int data;
- u32 offset;
-
- offset = HISI_IRQ_MASK_REG(d);
-
- spin_lock_irqsave(&ddata->lock, flags);
-
- regmap_read(ddata->regmap, offset, &data);
- data |= HISI_IRQ_MASK_BIT(d);
- regmap_write(ddata->regmap, offset, data);
-
- spin_unlock_irqrestore(&ddata->lock, flags);
-}
-
-static void hi6421_spmi_irq_unmask(struct irq_data *d)
-{
- struct hi6421_spmi_pmic *ddata = irq_data_get_irq_chip_data(d);
- u32 data, offset;
- unsigned long flags;
-
- offset = HISI_IRQ_MASK_REG(d);
-
- spin_lock_irqsave(&ddata->lock, flags);
-
- regmap_read(ddata->regmap, offset, &data);
- data &= ~HISI_IRQ_MASK_BIT(d);
- regmap_write(ddata->regmap, offset, data);
-
- spin_unlock_irqrestore(&ddata->lock, flags);
-}
-
-static struct irq_chip hi6421_spmi_pmu_irqchip = {
- .name = "hi6421v600-irq",
- .irq_mask = hi6421_spmi_irq_mask,
- .irq_unmask = hi6421_spmi_irq_unmask,
- .irq_disable = hi6421_spmi_irq_mask,
- .irq_enable = hi6421_spmi_irq_unmask,
-};
-
-static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct hi6421_spmi_pmic *ddata = d->host_data;
-
- irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip,
- handle_simple_irq, "hi6421v600");
- irq_set_chip_data(virq, ddata);
- irq_set_irq_type(virq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops hi6421_spmi_domain_ops = {
- .map = hi6421_spmi_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static void hi6421_spmi_pmic_irq_init(struct hi6421_spmi_pmic *ddata)
-{
- int i;
- unsigned int pending;
-
- /* Mask all IRQs */
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
- regmap_write(ddata->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
- HISI_8BITS_MASK);
-
- /* Mark all IRQs as handled */
- for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
- regmap_read(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
- regmap_write(ddata->regmap, SOC_PMIC_IRQ0_ADDR + i,
- HISI_8BITS_MASK);
- }
-}
-
-static const struct regmap_config regmap_config = {
- .reg_bits = 16,
- .val_bits = BITS_PER_BYTE,
- .max_register = 0xffff,
- .fast_io = true
-};
-
-static int hi6421_spmi_pmic_probe(struct spmi_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- struct hi6421_spmi_pmic *ddata;
- unsigned int virq;
- int ret, i;
-
- ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
- if (!ddata)
- return -ENOMEM;
-
- ddata->regmap = devm_regmap_init_spmi_ext(pdev, &regmap_config);
- if (IS_ERR(ddata->regmap))
- return PTR_ERR(ddata->regmap);
-
- spin_lock_init(&ddata->lock);
-
- ddata->dev = dev;
-
- ddata->gpio = of_get_gpio(np, 0);
- if (ddata->gpio < 0)
- return ddata->gpio;
-
- if (!gpio_is_valid(ddata->gpio))
- return -EINVAL;
-
- ret = devm_gpio_request_one(dev, ddata->gpio, GPIOF_IN, "pmic");
- if (ret < 0) {
- dev_err(dev, "Failed to request gpio%d\n", ddata->gpio);
- return ret;
- }
-
- ddata->irq = gpio_to_irq(ddata->gpio);
-
- hi6421_spmi_pmic_irq_init(ddata);
-
- ddata->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
- if (!ddata->irqs)
- return -ENOMEM;
-
- ddata->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
- &hi6421_spmi_domain_ops, ddata);
- if (!ddata->domain) {
- dev_err(dev, "Failed to create IRQ domain\n");
- return -ENODEV;
- }
-
- for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
- virq = irq_create_mapping(ddata->domain, i);
- if (!virq) {
- dev_err(dev, "Failed to map H/W IRQ\n");
- return -ENODEV;
- }
- ddata->irqs[i] = virq;
- }
-
- ret = devm_request_threaded_irq(dev,
- ddata->irq, hi6421_spmi_irq_handler,
- NULL,
- IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
- "pmic", ddata);
- if (ret < 0) {
- dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
- ret);
- return ret;
- }
-
- dev_set_drvdata(&pdev->dev, ddata);
-
- ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
- hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs),
- NULL, 0, NULL);
- if (ret < 0)
- dev_err(dev, "Failed to add child devices: %d\n", ret);
-
- return ret;
-}
-
-static const struct of_device_id pmic_spmi_id_table[] = {
- { .compatible = "hisilicon,hi6421-spmi" },
- { }
-};
-MODULE_DEVICE_TABLE(of, pmic_spmi_id_table);
-
-static struct spmi_driver hi6421_spmi_pmic_driver = {
- .driver = {
- .name = "hi6421-spmi-pmic",
- .of_match_table = pmic_spmi_id_table,
- },
- .probe = hi6421_spmi_pmic_probe,
-};
-module_spmi_driver(hi6421_spmi_pmic_driver);
-
-MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c
index cbc0032c1604..98d759e7cc95 100644
--- a/drivers/staging/ks7010/ks7010_sdio.c
+++ b/drivers/staging/ks7010/ks7010_sdio.c
@@ -939,9 +939,9 @@ static void ks7010_private_init(struct ks_wlan_private *priv,
memset(&priv->wstats, 0, sizeof(priv->wstats));
/* sleep mode */
+ atomic_set(&priv->sleepstatus.status, 0);
atomic_set(&priv->sleepstatus.doze_request, 0);
atomic_set(&priv->sleepstatus.wakeup_request, 0);
- atomic_set(&priv->sleepstatus.wakeup_request, 0);
trx_device_init(priv);
hostif_init(priv);
diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c
index 09e7b4cd0138..631ad769c3d5 100644
--- a/drivers/staging/ks7010/ks_wlan_net.c
+++ b/drivers/staging/ks7010/ks_wlan_net.c
@@ -158,13 +158,13 @@ static int ks_wlan_get_name(struct net_device *dev,
/* for SLEEP MODE */
if (priv->dev_state < DEVICE_STATE_READY)
- strcpy(cwrq->name, "NOT READY!");
+ strscpy(cwrq->name, "NOT READY!", sizeof(cwrq->name));
else if (priv->reg.phy_type == D_11B_ONLY_MODE)
- strcpy(cwrq->name, "IEEE 802.11b");
+ strscpy(cwrq->name, "IEEE 802.11b", sizeof(cwrq->name));
else if (priv->reg.phy_type == D_11G_ONLY_MODE)
- strcpy(cwrq->name, "IEEE 802.11g");
+ strscpy(cwrq->name, "IEEE 802.11g", sizeof(cwrq->name));
else
- strcpy(cwrq->name, "IEEE 802.11b/g");
+ strscpy(cwrq->name, "IEEE 802.11b/g", sizeof(cwrq->name));
return 0;
}
@@ -1808,8 +1808,8 @@ static int ks_wlan_get_firmware_version(struct net_device *dev,
{
struct ks_wlan_private *priv = netdev_priv(dev);
- strcpy(extra, priv->firmware_version);
dwrq->length = priv->version_size + 1;
+ strscpy(extra, priv->firmware_version, dwrq->length);
return 0;
}
diff --git a/drivers/staging/most/video/video.c b/drivers/staging/most/video/video.c
index 90933d78c332..b7858e47145f 100644
--- a/drivers/staging/most/video/video.c
+++ b/drivers/staging/most/video/video.c
@@ -258,7 +258,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index)
return -EINVAL;
- strcpy(f->description, "MPEG");
+ strscpy(f->description, "MPEG", sizeof(f->description));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
f->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -306,7 +306,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (input->index >= V4L2_CMP_MAX_INPUT)
return -EINVAL;
- strcpy(input->name, "MOST Video");
+ strscpy(input->name, "MOST Video", sizeof(input->name));
input->type |= V4L2_INPUT_TYPE_CAMERA;
input->audioset = 0;
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index f9bdf4e33134..6acfc94a16e7 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -56,6 +56,7 @@
#define PCIE_BAR_ENABLE BIT(0)
#define PCIE_PORT_INT_EN(x) BIT(20 + (x))
#define PCIE_PORT_LINKUP BIT(0)
+#define PCIE_PORT_CNT 3
#define PERST_DELAY_MS 100
@@ -388,10 +389,11 @@ static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie)
msleep(PERST_DELAY_MS);
}
-static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
+static int mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
{
struct device *dev = pcie->dev;
struct mt7621_pcie_port *port, *tmp;
+ u8 num_disabled = 0;
int err;
mt7621_pcie_reset_assert(pcie);
@@ -423,6 +425,7 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
slot);
mt7621_control_assert(port);
port->enabled = false;
+ num_disabled++;
if (slot == 0) {
tmp = port;
@@ -433,6 +436,8 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
phy_power_off(tmp->phy);
}
}
+
+ return (num_disabled != PCIE_PORT_CNT) ? 0 : -ENODEV;
}
static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
@@ -540,7 +545,11 @@ static int mt7621_pci_probe(struct platform_device *pdev)
return err;
}
- mt7621_pcie_init_ports(pcie);
+ err = mt7621_pcie_init_ports(pcie);
+ if (err) {
+ dev_err(dev, "Nothing connected in virtual bridges\n");
+ return 0;
+ }
err = mt7621_pcie_enable_ports(bridge);
if (err) {
diff --git a/drivers/staging/qlge/qlge_dbg.c b/drivers/staging/qlge/qlge_dbg.c
index 37e593f0fd82..66d28358342f 100644
--- a/drivers/staging/qlge/qlge_dbg.c
+++ b/drivers/staging/qlge/qlge_dbg.c
@@ -733,7 +733,7 @@ int qlge_core_dump(struct qlge_adapter *qdev, struct qlge_mpi_coredump *mpi_core
}
/* Insert the global header */
- memset(&(mpi_coredump->mpi_global_header), 0,
+ memset(&mpi_coredump->mpi_global_header, 0,
sizeof(struct mpi_coredump_global_header));
mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
mpi_coredump->mpi_global_header.header_size =
@@ -1221,7 +1221,7 @@ static void qlge_gen_reg_dump(struct qlge_adapter *qdev,
{
int i, status;
- memset(&(mpi_coredump->mpi_global_header), 0,
+ memset(&mpi_coredump->mpi_global_header, 0,
sizeof(struct mpi_coredump_global_header));
mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE;
mpi_coredump->mpi_global_header.header_size =
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/r8188eu/Kconfig
index 970d5abd6336..dc1719d3f2e4 100644
--- a/drivers/staging/rtl8188eu/Kconfig
+++ b/drivers/staging/r8188eu/Kconfig
@@ -9,14 +9,15 @@ config R8188EU
select LIB80211_CRYPT_WEP
select LIB80211_CRYPT_CCMP
help
- This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
- If built as a module, it will be called r8188eu.
+ This option adds support for the Realtek RTL8188EU chipset, used in USB
+ devices such as the ASUS USB-N10 Nano. This newer driver is based on GitHub
+ sources for version v4.1.4_6773.20130222, and contains modifications for
+ newer kernel features. If built as a module, it will be called r8188eu.
if R8188EU
config 88EU_AP_MODE
bool "Realtek RTL8188EU AP mode"
- default y
help
This option enables Access Point mode. Unless you know that your system
will never be used as an AP, or the target system has limited memory,
diff --git a/drivers/staging/r8188eu/Makefile b/drivers/staging/r8188eu/Makefile
new file mode 100644
index 000000000000..aebaf29990fd
--- /dev/null
+++ b/drivers/staging/r8188eu/Makefile
@@ -0,0 +1,105 @@
+SHELL := /bin/bash
+EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
+EXTRA_CFLAGS += -O1
+
+ccflags-y += -D__CHECK_ENDIAN__
+
+CONFIG_BT_COEXIST = n
+CONFIG_WOWLAN = n
+
+OUTSRC_FILES := \
+ hal/HalHWImg8188E_MAC.o \
+ hal/HalHWImg8188E_BB.o \
+ hal/HalHWImg8188E_RF.o \
+ hal/HalPhyRf_8188e.o \
+ hal/HalPwrSeqCmd.o \
+ hal/Hal8188EPwrSeq.o \
+ hal/Hal8188ERateAdaptive.o\
+ hal/hal_intf.o \
+ hal/hal_com.o \
+ hal/odm.o \
+ hal/odm_debug.o \
+ hal/odm_interface.o \
+ hal/odm_HWConfig.o \
+ hal/odm_RegConfig8188E.o\
+ hal/odm_RTL8188E.o \
+ hal/rtl8188e_cmd.o \
+ hal/rtl8188e_dm.o \
+ hal/rtl8188e_hal_init.o \
+ hal/rtl8188e_mp.o \
+ hal/rtl8188e_phycfg.o \
+ hal/rtl8188e_rf6052.o \
+ hal/rtl8188e_rxdesc.o \
+ hal/rtl8188e_sreset.o \
+ hal/rtl8188e_xmit.o \
+ hal/rtl8188eu_led.o \
+ hal/rtl8188eu_recv.o \
+ hal/rtl8188eu_xmit.o \
+ hal/usb_halinit.o \
+ hal/usb_ops_linux.o
+
+RTL871X = rtl8188e
+
+HCI_NAME = usb
+
+_OS_INTFS_FILES := \
+ os_dep/ioctl_linux.o \
+ os_dep/mlme_linux.o \
+ os_dep/os_intfs.o \
+ os_dep/osdep_service.o \
+ os_dep/recv_linux.o \
+ os_dep/usb_intf.o \
+ os_dep/usb_ops_linux.o \
+ os_dep/xmit_linux.o
+
+_HAL_INTFS_FILES += $(OUTSRC_FILES)
+
+ifeq ($(CONFIG_BT_COEXIST), y)
+EXTRA_CFLAGS += -DCONFIG_BT_COEXIST
+endif
+
+ifeq ($(CONFIG_WOWLAN), y)
+EXTRA_CFLAGS += -DCONFIG_WOWLAN
+endif
+
+SUBARCH := $(shell uname -m | sed -e "s/i.86/i386/; s/ppc.*/powerpc/; s/armv.l/arm/; s/aarch64/arm64/;")
+
+ARCH ?= $(SUBARCH)
+CROSS_COMPILE ?=
+KVER ?= $(if $(KERNELRELEASE),$(KERNELRELEASE),$(shell uname -r))
+KSRC ?= $(if $(KERNEL_SRC),$(KERNEL_SRC),/lib/modules/$(KVER)/build)
+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless
+INSTALL_PREFIX :=
+
+rtk_core := \
+ core/rtw_ap.o \
+ core/rtw_br_ext.o \
+ core/rtw_cmd.o \
+ core/rtw_debug.o \
+ core/rtw_efuse.o \
+ core/rtw_ieee80211.o \
+ core/rtw_io.o \
+ core/rtw_ioctl_set.o \
+ core/rtw_iol.o \
+ core/rtw_led.o \
+ core/rtw_mlme.o \
+ core/rtw_mlme_ext.o \
+ core/rtw_mp.o \
+ core/rtw_mp_ioctl.o \
+ core/rtw_pwrctrl.o \
+ core/rtw_p2p.o \
+ core/rtw_recv.o \
+ core/rtw_rf.o \
+ core/rtw_security.o \
+ core/rtw_sreset.o \
+ core/rtw_sta_mgt.o \
+ core/rtw_wlan_util.o \
+ core/rtw_xmit.o
+
+r8188eu-y += $(rtk_core)
+
+r8188eu-y += $(_HAL_INTFS_FILES)
+
+r8188eu-y += $(_OS_INTFS_FILES)
+
+obj-$(CONFIG_R8188EU) := r8188eu.o
diff --git a/drivers/staging/r8188eu/TODO b/drivers/staging/r8188eu/TODO
new file mode 100644
index 000000000000..ab9d5d145b3b
--- /dev/null
+++ b/drivers/staging/r8188eu/TODO
@@ -0,0 +1,16 @@
+To-do list:
+
+* Correct the coding style according to Linux guidelines; please read the document
+ at https://www.kernel.org/doc/html/latest/process/coding-style.html.
+* Remove unnecessary debugging/printing macros; for those that are still needed
+ use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()).
+* Remove dead code such as unusued functions, variables, fields, etc..
+* Use in-kernel API and remove unnecessary wrappers where possible.
+* Fix bugs due to code that sleeps in atomic context.
+* Remove the HAL layer and migrate its functionality into the relevant parts of
+ the driver.
+* Switch to use LIB80211.
+* Switch to use MAC80211.
+* Switch to use CFG80211.
+* Improve the error handling of various functions, particularly those that use
+ existing kernel APIs.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/r8188eu/core/rtw_ap.c
index b817aa8b9de4..1c07ad28b242 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/r8188eu/core/rtw_ap.c
@@ -1,18 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
- *
- ******************************************************************************/
-#define _RTW_AP_C_
+/* Copyright(c) 2007 - 2012 Realtek Corporation. */
-#include <linux/ieee80211.h>
+#define _RTW_AP_C_
-#include <osdep_service.h>
-#include <drv_types.h>
-#include <wifi.h>
-#include <ieee80211.h>
-#include <asm/unaligned.h>
+#include "../include/osdep_service.h"
+#include "../include/drv_types.h"
+#include "../include/wifi.h"
+#include "../include/ieee80211.h"
#ifdef CONFIG_88EU_AP_MODE
@@ -61,86 +55,86 @@ static void update_BCNTIM(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
- unsigned char *pie = pnetwork_mlmeext->ies;
- u8 *p, *dst_ie, *premainder_ie = NULL;
- u8 *pbackup_remainder_ie = NULL;
- uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+ unsigned char *pie = pnetwork_mlmeext->IEs;
/* update TIM IE */
- p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, WLAN_EID_TIM, &tim_ielen,
- pnetwork_mlmeext->ie_length - _FIXED_IE_LENGTH_);
- if (p && tim_ielen > 0) {
- tim_ielen += 2;
- premainder_ie = p + tim_ielen;
- tim_ie_offset = (int)(p - pie);
- remainder_ielen = pnetwork_mlmeext->ie_length -
- tim_ie_offset - tim_ielen;
- /* append TIM IE from dst_ie offset */
- dst_ie = p;
- } else {
- tim_ielen = 0;
+ if (true) {
+ u8 *p, *dst_ie, *premainder_ie = NULL;
+ u8 *pbackup_remainder_ie = NULL;
+ __le16 tim_bitmap_le;
+ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+ if (p && tim_ielen > 0) {
+ tim_ielen += 2;
+ premainder_ie = p + tim_ielen;
+ tim_ie_offset = (int)(p - pie);
+ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+ /* append TIM IE from dst_ie offset */
+ dst_ie = p;
+ } else {
+ tim_ielen = 0;
- /* calculate head_len */
- offset = _FIXED_IE_LENGTH_;
- offset += pnetwork_mlmeext->ssid.ssid_length + 2;
+ /* calculate head_len */
+ offset = _FIXED_IE_LENGTH_;
+ offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
- /* get supported rates len */
- p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, WLAN_EID_SUPP_RATES,
- &tmp_len, (pnetwork_mlmeext->ie_length -
- _BEACON_IE_OFFSET_));
- if (p)
- offset += tmp_len + 2;
+ /* get supported rates len */
+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+ if (p)
+ offset += tmp_len + 2;
- /* DS Parameter Set IE, len = 3 */
- offset += 3;
+ /* DS Parameter Set IE, len = 3 */
+ offset += 3;
- premainder_ie = pie + offset;
+ premainder_ie = pie + offset;
- remainder_ielen = pnetwork_mlmeext->ie_length -
- offset - tim_ielen;
+ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
- /* append TIM IE from offset */
- dst_ie = pie + offset;
- }
+ /* append TIM IE from offset */
+ dst_ie = pie + offset;
+ }
- if (remainder_ielen > 0) {
- pbackup_remainder_ie = rtw_malloc(remainder_ielen);
- if (pbackup_remainder_ie && premainder_ie)
- memcpy(pbackup_remainder_ie, premainder_ie,
- remainder_ielen);
- }
- *dst_ie++ = WLAN_EID_TIM;
+ if (remainder_ielen > 0) {
+ pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC);
+ if (pbackup_remainder_ie && premainder_ie)
+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+ }
+ *dst_ie++ = _TIM_IE_;
- if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fc))
- tim_ielen = 5;
- else
- tim_ielen = 4;
+ if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fc))
+ tim_ielen = 5;
+ else
+ tim_ielen = 4;
- *dst_ie++ = tim_ielen;
+ *dst_ie++ = tim_ielen;
- *dst_ie++ = 0;/* DTIM count */
- *dst_ie++ = 1;/* DTIM period */
+ *dst_ie++ = 0;/* DTIM count */
+ *dst_ie++ = 1;/* DTIM period */
- if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
- *dst_ie++ = BIT(0);/* bitmap ctrl */
- else
- *dst_ie++ = 0;
+ if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
+ *dst_ie++ = BIT(0);/* bitmap ctrl */
+ else
+ *dst_ie++ = 0;
- if (tim_ielen == 4) {
- *dst_ie++ = pstapriv->tim_bitmap & 0xff;
- } else if (tim_ielen == 5) {
- put_unaligned_le16(pstapriv->tim_bitmap, dst_ie);
- dst_ie += 2;
- }
+ if (tim_ielen == 4) {
+ *dst_ie++ = *(u8 *)&tim_bitmap_le;
+ } else if (tim_ielen == 5) {
+ memcpy(dst_ie, &tim_bitmap_le, 2);
+ dst_ie += 2;
+ }
- /* copy remainder IE */
- if (pbackup_remainder_ie) {
- memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+ /* copy remainder IE */
+ if (pbackup_remainder_ie) {
+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
- kfree(pbackup_remainder_ie);
+ kfree(pbackup_remainder_ie);
+ }
+ offset = (uint)(dst_ie - pie);
+ pnetwork_mlmeext->IELength = offset + remainder_ielen;
}
- offset = (uint)(dst_ie - pie);
- pnetwork_mlmeext->ie_length = offset + remainder_ielen;
set_tx_beacon_cmd(padapter);
}
@@ -149,10 +143,8 @@ static u8 chk_sta_is_alive(struct sta_info *psta)
{
u8 ret = false;
- if ((psta->sta_stats.last_rx_data_pkts +
- psta->sta_stats.last_rx_ctrl_pkts) ==
- (psta->sta_stats.rx_data_pkts +
- psta->sta_stats.rx_ctrl_pkts))
+ if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) ==
+ (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
;
else
ret = true;
@@ -162,11 +154,11 @@ static u8 chk_sta_is_alive(struct sta_info *psta)
return ret;
}
-void expire_timeout_chk(struct adapter *padapter)
+void expire_timeout_chk(struct adapter *padapter)
{
- struct list_head *phead;
+ struct list_head *phead, *plist;
u8 updated = 0;
- struct sta_info *psta, *temp;
+ struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 chk_alive_num = 0;
char chk_alive_list[NUM_STA];
@@ -175,14 +167,22 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->auth_list_lock);
phead = &pstapriv->auth_list;
+ plist = phead->next;
+
/* check auth_queue */
- list_for_each_entry_safe(psta, temp, phead, auth_list) {
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, auth_list);
+ plist = plist->next;
+
if (psta->expire_to > 0) {
psta->expire_to--;
if (psta->expire_to == 0) {
list_del_init(&psta->auth_list);
pstapriv->auth_list_cnt--;
+ DBG_88E("auth expire %6ph\n",
+ psta->hwaddr);
+
spin_unlock_bh(&pstapriv->auth_list_lock);
spin_lock_bh(&pstapriv->sta_hash_lock);
@@ -192,6 +192,7 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->auth_list_lock);
}
}
+
}
spin_unlock_bh(&pstapriv->auth_list_lock);
@@ -200,8 +201,13 @@ void expire_timeout_chk(struct adapter *padapter)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
+ plist = phead->next;
+
/* check asoc_queue */
- list_for_each_entry_safe(psta, temp, phead, asoc_list) {
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, asoc_list);
+ plist = plist->next;
+
if (chk_sta_is_alive(psta) || !psta->expire_to) {
psta->expire_to = pstapriv->expire_to;
psta->keep_alive_trycnt = 0;
@@ -220,18 +226,13 @@ void expire_timeout_chk(struct adapter *padapter)
if (psta->state & WIFI_SLEEP_STATE) {
if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
- /* to check if alive by another methods
- * if station is at ps mode.
- */
+ /* to check if alive by another methods if station is at ps mode. */
psta->expire_to = pstapriv->expire_to;
psta->state |= WIFI_STA_ALIVE_CHK_STATE;
- /* to update bcn with tim_bitmap
- * for this station
- */
+ /* to update bcn with tim_bitmap for this station */
pstapriv->tim_bitmap |= BIT(psta->aid);
- update_beacon(padapter, WLAN_EID_TIM, NULL,
- false);
+ update_beacon(padapter, _TIM_IE_, NULL, false);
if (!pmlmeext->active_keep_alive_check)
continue;
@@ -240,24 +241,27 @@ void expire_timeout_chk(struct adapter *padapter)
if (pmlmeext->active_keep_alive_check) {
int stainfo_offset;
- stainfo_offset =
- rtw_stainfo_offset(pstapriv, psta);
+ stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
if (stainfo_offset_valid(stainfo_offset))
- chk_alive_list[chk_alive_num++] =
- stainfo_offset;
+ chk_alive_list[chk_alive_num++] = stainfo_offset;
continue;
}
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
- updated = ap_free_sta(padapter, psta, true,
- WLAN_REASON_DEAUTH_LEAVING);
+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
} else {
/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) &&
- padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME / pstapriv->asoc_list_cnt / 2))
+ padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME / pstapriv->asoc_list_cnt / 2)) {
+ DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
+ (psta->hwaddr), psta->sleepq_len,
+ padapter->xmitpriv.free_xmitframe_cnt,
+ pstapriv->asoc_list_cnt);
wakeup_sta_to_xmit(padapter, psta);
+ }
}
}
@@ -276,34 +280,32 @@ void expire_timeout_chk(struct adapter *padapter)
for (i = 0; i < chk_alive_num; i++) {
int ret = _FAIL;
- psta = rtw_get_stainfo_by_offset(pstapriv,
- chk_alive_list[i]);
+ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
- if (psta->state & WIFI_SLEEP_STATE) {
- ret = issue_nulldata(padapter, psta->hwaddr,
- 0, 1, 50);
- } else {
- ret = issue_nulldata(padapter, psta->hwaddr,
- 0, 3, 50);
- }
+ if (psta->state & WIFI_SLEEP_STATE)
+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50);
+ else
+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50);
psta->keep_alive_trycnt++;
if (ret == _SUCCESS) {
+ DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr));
psta->expire_to = pstapriv->expire_to;
psta->keep_alive_trycnt = 0;
continue;
} else if (psta->keep_alive_trycnt <= 3) {
+ DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
psta->expire_to = 1;
continue;
}
psta->keep_alive_trycnt = 0;
+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
spin_lock_bh(&pstapriv->asoc_list_lock);
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
- updated = ap_free_sta(padapter, psta, true,
- WLAN_REASON_DEAUTH_LEAVING);
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
spin_unlock_bh(&pstapriv->asoc_list_lock);
}
@@ -317,10 +319,14 @@ void expire_timeout_chk(struct adapter *padapter)
void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
{
int i;
+ u8 rf_type;
u32 init_rate = 0;
unsigned char sta_band = 0, raid, shortGIrate = false;
+ unsigned char limit;
unsigned int tx_ra_bitmap = 0;
struct ht_priv *psta_ht = NULL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
if (psta)
psta_ht = &psta->htpriv;
@@ -337,20 +343,31 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
}
/* n mode ra_bitmap */
if (psta_ht->ht_option) {
- for (i = 0; i < 8; i++)
- if (psta_ht->ht_cap.mcs.rx_mask[0] & BIT(i))
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+ if (rf_type == RF_2T2R)
+ limit = 16;/* 2R */
+ else
+ limit = 8;/* 1R */
+
+ for (i = 0; i < limit; i++) {
+ if (psta_ht->ht_cap.mcs.rx_mask[i / 8] & BIT(i % 8))
tx_ra_bitmap |= BIT(i + 12);
+ }
/* max short GI rate */
shortGIrate = psta_ht->sgi;
}
- if (tx_ra_bitmap & 0xffff000)
- sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
- else if (tx_ra_bitmap & 0xff0)
- sta_band |= WIRELESS_11G | WIRELESS_11B;
- else
- sta_band |= WIRELESS_11B;
+ if (pcur_network->Configuration.DSConfig > 14) {
+ sta_band |= WIRELESS_INVALID;
+ } else {
+ if (tx_ra_bitmap & 0xffff000)
+ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+ else if (tx_ra_bitmap & 0xff0)
+ sta_band |= WIRELESS_11G | WIRELESS_11B;
+ else
+ sta_band |= WIRELESS_11B;
+ }
psta->wireless_mode = sta_band;
@@ -369,6 +386,9 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
tx_ra_bitmap |= ((raid << 28) & 0xf0000000);
+ DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
+ __func__, psta->mac_id, raid, tx_ra_bitmap, arg);
+
/* bitmap[0:27] = tx_rate_bitmap */
/* bitmap[28:31]= Rate Adaptive id */
/* arg[0:4] = macid */
@@ -382,17 +402,19 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
psta->raid = raid;
psta->init_rate = init_rate;
+ } else {
+ DBG_88E("station aid %d exceed the max number\n", psta->aid);
}
}
-static void update_bmc_sta(struct adapter *padapter)
+void update_bmc_sta(struct adapter *padapter)
{
u32 init_rate = 0;
unsigned char network_type, raid;
int i, supportRateNum = 0;
unsigned int tx_ra_bitmap = 0;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct wlan_bssid_ex *pcur_network = &pmlmepriv->cur_network.network;
+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
if (psta) {
@@ -404,14 +426,13 @@ static void update_bmc_sta(struct adapter *padapter)
psta->ieee8021x_blocked = 0;
- memset(&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
/* prepare for add_RATid */
supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
- network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates);
+ network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
- memcpy(psta->bssrateset, &pcur_network->SupportedRates,
- supportRateNum);
+ memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
psta->bssratelen = supportRateNum;
/* b/g mode ra_bitmap */
@@ -420,13 +441,16 @@ static void update_bmc_sta(struct adapter *padapter)
tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f);
}
- /* force to b mode */
- network_type = WIRELESS_11B;
- tx_ra_bitmap = 0xf;
+ if (pcur_network->Configuration.DSConfig > 14) {
+ network_type = WIRELESS_INVALID;
+ } else {
+ /* force to b mode */
+ network_type = WIRELESS_11B;
+ tx_ra_bitmap = 0xf;
+ }
raid = networktype_to_raid(network_type);
- init_rate = get_highest_rate_idx(tx_ra_bitmap & 0x0fffffff) &
- 0x3f;
+ init_rate = get_highest_rate_idx(tx_ra_bitmap & 0x0fffffff) & 0x3f;
/* ap mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
@@ -437,6 +461,7 @@ static void update_bmc_sta(struct adapter *padapter)
arg = psta->mac_id & 0x1f;
arg |= BIT(7);
tx_ra_bitmap |= ((raid << 28) & 0xf0000000);
+ DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg);
/* bitmap[0:27] = tx_rate_bitmap */
/* bitmap[28:31]= Rate Adaptive id */
@@ -448,12 +473,14 @@ static void update_bmc_sta(struct adapter *padapter)
psta->raid = raid;
psta->init_rate = init_rate;
- rtw_stassoc_hw_rpt(padapter, psta);
+ rtw_sta_media_status_rpt(padapter, psta, 1);
spin_lock_bh(&psta->lock);
psta->state = _FW_LINKED;
spin_unlock_bh(&psta->lock);
+ } else {
+ DBG_88E("add_RATid_bmc_sta error!\n");
}
}
@@ -471,8 +498,11 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
struct ht_priv *phtpriv_sta = &psta->htpriv;
+ u16 sta_cap_info;
+ u16 ap_cap_info;
psta->mac_id = psta->aid + 1;
+ DBG_88E("%s\n", __func__);
/* ap mode */
rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
@@ -490,17 +520,16 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
if (phtpriv_sta->ht_option) {
/* check if sta supports rx ampdu */
phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+ sta_cap_info = le16_to_cpu(phtpriv_sta->ht_cap.cap_info);
+ ap_cap_info = le16_to_cpu(phtpriv_ap->ht_cap.cap_info);
/* check if sta support s Short GI */
- if (le16_to_cpu(phtpriv_sta->ht_cap.cap_info &
- phtpriv_ap->ht_cap.cap_info) &
+ if ((sta_cap_info & ap_cap_info) &
(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40))
phtpriv_sta->sgi = true;
/* bwmode */
- if (le16_to_cpu(phtpriv_sta->ht_cap.cap_info &
- phtpriv_ap->ht_cap.cap_info) &
- IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ if ((sta_cap_info & ap_cap_info) & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
}
@@ -522,7 +551,7 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
/* todo: init other variables */
- memset(&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
spin_lock_bh(&psta->lock);
psta->state |= _FW_LINKED;
@@ -531,23 +560,32 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
static void update_hw_ht_param(struct adapter *padapter)
{
- u8 max_ampdu_len;
- u8 min_mpdu_spacing;
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ unsigned char max_AMPDU_len;
+ unsigned char min_MPDU_spacing;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
- /* handle A-MPDU parameter field
- * ampdu_params_info [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
- * ampdu_params_info [4:2]:Min MPDU Start Spacing
- */
- max_ampdu_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x03;
- min_mpdu_spacing = (pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) >> 2;
+ DBG_88E("%s\n", __func__);
+
+ /* handle A-MPDU parameter field */
+ /*
+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+ AMPDU_para [4:2]:Min MPDU Start Spacing
+ */
+ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
- rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, &min_mpdu_spacing);
- rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, &max_ampdu_len);
+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
- /* Config SM Power Save setting */
- pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & 0x0C) >> 2;
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+ /* */
+ /* Config SM Power Save setting */
+ /* */
+ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
}
static void start_bss_network(struct adapter *padapter, u8 *pbuf)
@@ -556,27 +594,28 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
u16 bcn_interval;
u32 acparm;
- uint ie_len;
+ int ie_len;
struct registry_priv *pregpriv = &padapter->registrypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- struct wlan_bssid_ex *pnetwork = &pmlmepriv->cur_network.network;
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
struct HT_info_element *pht_info = NULL;
+#ifdef CONFIG_88EU_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
cur_channel = pnetwork->Configuration.DSConfig;
cur_bwmode = HT_CHANNEL_WIDTH_20;
cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
- /* check if there is wps ie,
- * if there is wpsie in beacon, the hostapd will update
- * beacon twice when stating hostapd, and at first time the
- * security ie (RSN/WPA IE) will not include in beacon.
- */
- if (!rtw_get_wps_ie(pnetwork->ies + _FIXED_IE_LENGTH_, pnetwork->ie_length - _FIXED_IE_LENGTH_, NULL, NULL))
+ /* check if there is wps ie, */
+ /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+ /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
+ if (!rtw_get_wps_ie(pnetwork->IEs + _FIXED_IE_LENGTH_, pnetwork->IELength - _FIXED_IE_LENGTH_, NULL, NULL))
pmlmeext->bstart_bss = true;
/* todo: update wmm, ht cap */
@@ -589,11 +628,8 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
update_hw_ht_param(padapter);
}
- /* setting only at first time */
- if (!pmlmepriv->cur_network.join_res) {
- /* WEP Key will be set before this function, do not
- * clear CAM.
- */
+ if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */
+ /* WEP Key will be set before this function, do not clear CAM. */
if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) &&
(psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
flush_all_cam_entry(padapter); /* clear CAM */
@@ -620,8 +656,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
/* Beacon Control related register */
- rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL,
- (u8 *)(&bcn_interval));
+ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
UpdateBrateTbl(padapter, pnetwork->SupportedRates);
rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
@@ -631,10 +666,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
}
/* set channel, bwmode */
- p = rtw_get_ie(pnetwork->ies + sizeof(struct ndis_802_11_fixed_ie),
- WLAN_EID_HT_OPERATION, &ie_len,
- pnetwork->ie_length -
- sizeof(struct ndis_802_11_fixed_ie));
+ p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie)));
if (p && ie_len) {
pht_info = (struct HT_info_element *)(p + 2);
@@ -654,11 +686,11 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
}
}
}
- /* TODO: need to judge the phy parameters on concurrent
- * mode for single phy
- */
+ /* TODO: need to judge the phy parameters on concurrent mode for single phy */
set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+ DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset);
+
/* */
pmlmeext->cur_channel = cur_channel;
pmlmeext->cur_bwmode = cur_bwmode;
@@ -668,17 +700,23 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf)
/* update cur_wireless_mode */
update_wireless_mode(padapter);
- /* update capability after cur_wireless_mode updated */
- update_capinfo(padapter, rtw_get_capability(pnetwork));
+ /* udpate capability after cur_wireless_mode updated */
+ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork));
/* let pnetwork_mlmeext == pnetwork_mlme. */
memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+#ifdef CONFIG_88EU_P2P
+ memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength);
+ pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength;
+#endif /* CONFIG_88EU_P2P */
+
if (pmlmeext->bstart_bss) {
- update_beacon(padapter, WLAN_EID_TIM, NULL, false);
+ update_beacon(padapter, _TIM_IE_, NULL, false);
/* issue beacon frame */
- send_beacon(padapter);
+ if (send_beacon(padapter) == _FAIL)
+ DBG_88E("issue_beacon, fail!\n");
}
/* update bc/mc sta_info */
@@ -702,8 +740,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct wlan_bssid_ex *pbss_network = &pmlmepriv->cur_network.network;
- u8 *ie = pbss_network->ies;
+ struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+ u8 *ie = pbss_network->IEs;
/* SSID */
/* Supported rates */
@@ -716,24 +754,26 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
/* ht_capab, ht_oper */
/* WPS IE */
- if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ DBG_88E("%s, len =%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
return _FAIL;
- if (len < 0 || len > MAX_IE_SZ)
+ if (len > MAX_IE_SZ)
return _FAIL;
- pbss_network->ie_length = len;
+ pbss_network->IELength = len;
memset(ie, 0, MAX_IE_SZ);
- memcpy(ie, pbuf, pbss_network->ie_length);
+ memcpy(ie, pbuf, pbss_network->IELength);
if (pbss_network->InfrastructureMode != Ndis802_11APMode)
return _FAIL;
pbss_network->Rssi = 0;
- ether_addr_copy(pbss_network->MacAddress, myid(&padapter->eeprompriv));
+ memcpy(pbss_network->MacAddress, myid(&padapter->eeprompriv), ETH_ALEN);
/* beacon interval */
p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
@@ -743,20 +783,17 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
cap = get_unaligned_le16(ie);
/* SSID */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_SSID, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0) {
- ie_len = min_t(int, ie_len, sizeof(pbss_network->ssid.ssid));
- memset(&pbss_network->ssid, 0, sizeof(struct ndis_802_11_ssid));
- memcpy(pbss_network->ssid.ssid, p + 2, ie_len);
- pbss_network->ssid.ssid_length = ie_len;
+ memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+ memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+ pbss_network->Ssid.SsidLength = ie_len;
}
/* channel */
channel = 0;
pbss_network->Configuration.Length = 0;
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_DS_PARAMS, &ie_len,
- (pbss_network->ie_length - _BEACON_IE_OFFSET_));
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0)
channel = *(p + 2);
@@ -764,31 +801,25 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
/* get supported rates */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_SUPP_RATES, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p) {
- ie_len = min_t(int, ie_len, NDIS_802_11_LENGTH_RATES_EX);
memcpy(supportRate, p + 2, ie_len);
supportRateNum = ie_len;
}
/* get ext_supported rates */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_EXT_SUPP_RATES,
- &ie_len, pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
if (p) {
- ie_len = min_t(int, ie_len,
- NDIS_802_11_LENGTH_RATES_EX - supportRateNum);
memcpy(supportRate + supportRateNum, p + 2, ie_len);
supportRateNum += ie_len;
}
- network_type = rtw_check_network_type(supportRate);
+ network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
/* parsing ERP_IE */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_ERP_INFO, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0)
ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p);
@@ -805,8 +836,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pairwise_cipher = 0;
psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_RSN, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0) {
if (rtw_parse_wpa2_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
@@ -825,8 +855,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
- p = rtw_get_ie(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_ - (ie_len + 2));
+ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
if ((p) && (!memcmp(p + 2, OUI1, 4))) {
if (rtw_parse_wpa_ie(p, ie_len + 2, &group_cipher,
&pairwise_cipher, NULL) == _SUCCESS) {
@@ -841,7 +871,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
}
break;
}
- if ((!p) || (ie_len == 0))
+ if (!p || ie_len == 0)
break;
}
@@ -850,17 +880,14 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
pmlmepriv->qospriv.qos_option = 0;
if (pregistrypriv->wmm_enable) {
for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
- p = rtw_get_ie(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_ - (ie_len + 2));
+ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
if ((p) && !memcmp(p + 2, WMM_PARA_IE, 6)) {
pmlmepriv->qospriv.qos_option = 1;
- /* QoS Info, support U-APSD */
- *(p + 8) |= BIT(7);
+ *(p + 8) |= BIT(7);/* QoS Info, support U-APSD */
- /* disable all ACM bits since the WMM
- * admission control is not supported
- */
+ /* disable all ACM bits since the WMM admission control is not supported */
*(p + 10) &= ~BIT(4); /* BE */
*(p + 14) &= ~BIT(4); /* BK */
*(p + 18) &= ~BIT(4); /* VI */
@@ -868,20 +895,23 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
break;
}
- if ((!p) || (ie_len == 0))
+ if (!p || ie_len == 0)
break;
}
}
/* parsing HT_CAP_IE */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_HT_CAPABILITY, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0) {
+ u8 rf_type;
struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p + 2);
pHT_caps_ie = p;
ht_cap = true;
network_type |= WIRELESS_11_24N;
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
(psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (0x07 << 2));
@@ -891,15 +921,16 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
/* set Max Rx AMPDU size to 64K */
pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_FACTOR & 0x03);
- pht_cap->mcs.rx_mask[0] = 0xff;
- pht_cap->mcs.rx_mask[1] = 0x0;
- ie_len = min_t(int, ie_len, sizeof(pmlmepriv->htpriv.ht_cap));
+ if (rf_type == RF_1T1R) {
+ pht_cap->mcs.rx_mask[0] = 0xff;
+ pht_cap->mcs.rx_mask[1] = 0x0;
+ }
memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);
}
/* parsing HT_INFO_IE */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_HT_OPERATION, &ie_len,
- pbss_network->ie_length - _BEACON_IE_OFFSET_);
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len,
+ (pbss_network->IELength - _BEACON_IE_OFFSET_));
if (p && ie_len > 0)
pHT_info_ie = p;
switch (network_type) {
@@ -912,9 +943,6 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
case WIRELESS_11BG_24N:
pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
- case WIRELESS_11A:
- pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
- break;
default:
pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
@@ -942,7 +970,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len)
HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie);
}
- pbss_network->Length = get_wlan_bssid_ex_sz(pbss_network);
+ pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network);
/* issue beacon to start bss network */
start_bss_network(padapter, (u8 *)pbss_network);
@@ -967,6 +995,8 @@ void rtw_set_macaddr_acl(struct adapter *padapter, int mode)
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+ DBG_88E("%s, mode =%d\n", __func__, mode);
+
pacl_list->mode = mode;
}
@@ -980,18 +1010,24 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
if ((NUM_ACL - 1) < pacl_list->num)
return -1;
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
- list_for_each(plist, phead) {
- paclnode = list_entry(plist, struct rtw_wlan_acl_node, list);
+ plist = phead->next;
+
+ while (phead != plist) {
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
added = true;
+ DBG_88E("%s, sta has been added\n", __func__);
break;
}
}
@@ -1010,7 +1046,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
if (!paclnode->valid) {
INIT_LIST_HEAD(&paclnode->list);
- ether_addr_copy(paclnode->addr, addr);
+ memcpy(paclnode->addr, addr, ETH_ALEN);
paclnode->valid = true;
@@ -1022,6 +1058,8 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
}
}
+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+
spin_unlock_bh(&pacl_node_q->lock);
return ret;
@@ -1029,16 +1067,24 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
{
- struct list_head *phead;
- struct rtw_wlan_acl_node *paclnode, *temp;
+ struct list_head *plist, *phead;
+ int ret = 0;
+ struct rtw_wlan_acl_node *paclnode;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
- list_for_each_entry_safe(paclnode, temp, phead, list) {
+ plist = phead->next;
+
+ while (phead != plist) {
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
+
if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
if (paclnode->valid) {
paclnode->valid = false;
@@ -1052,7 +1098,13 @@ int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
spin_unlock_bh(&pacl_node_q->lock);
- return 0;
+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+ return ret;
+}
+
+static void update_bcn_fixed_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
}
static void update_bcn_erpinfo_ie(struct adapter *padapter)
@@ -1061,24 +1113,24 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
- unsigned char *p, *ie = pnetwork->ies;
+ unsigned char *p, *ie = pnetwork->IEs;
u32 len = 0;
+ DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
+
if (!pmlmeinfo->ERP_enable)
return;
/* parsing ERP_IE */
- p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, WLAN_EID_ERP_INFO, &len,
- (pnetwork->ie_length - _BEACON_IE_OFFSET_));
+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len,
+ (pnetwork->IELength - _BEACON_IE_OFFSET_));
if (p && len > 0) {
struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p;
if (pmlmepriv->num_sta_non_erp == 1)
- pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT |
- RTW_ERP_INFO_USE_PROTECTION;
+ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION;
else
- pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT |
- RTW_ERP_INFO_USE_PROTECTION);
+ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION);
if (pmlmepriv->num_sta_no_short_preamble > 0)
pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
@@ -1089,6 +1141,31 @@ static void update_bcn_erpinfo_ie(struct adapter *padapter)
}
}
+static void update_bcn_htcap_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_htinfo_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_rsn_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wpa_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wmm_ie(struct adapter *padapter)
+{
+ DBG_88E("%s\n", __func__);
+}
+
static void update_bcn_wps_ie(struct adapter *padapter)
{
u8 *pwps_ie = NULL, *pwps_ie_src;
@@ -1098,15 +1175,12 @@ static void update_bcn_wps_ie(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
- unsigned char *ie = pnetwork->ies;
- u32 ielen = pnetwork->ie_length;
+ unsigned char *ie = pnetwork->IEs;
+ u32 ielen = pnetwork->IELength;
- pwps_ie_src = pmlmepriv->wps_beacon_ie;
- if (!pwps_ie_src)
- return;
+ DBG_88E("%s\n", __func__);
- pwps_ie = rtw_get_wps_ie(ie + _FIXED_IE_LENGTH_,
- ielen - _FIXED_IE_LENGTH_, NULL, &wps_ielen);
+ pwps_ie = rtw_get_wps_ie(ie + _FIXED_IE_LENGTH_, ielen - _FIXED_IE_LENGTH_, NULL, &wps_ielen);
if (!pwps_ie || wps_ielen == 0)
return;
@@ -1118,31 +1192,49 @@ static void update_bcn_wps_ie(struct adapter *padapter)
remainder_ielen = ielen - wps_offset - wps_ielen;
if (remainder_ielen > 0) {
- pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+ pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC);
if (pbackup_remainder_ie)
memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
}
+ pwps_ie_src = pmlmepriv->wps_beacon_ie;
+ if (!pwps_ie_src)
+ goto exit;
+
wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
- if (wps_offset + wps_ielen + 2 + remainder_ielen <= MAX_IE_SZ) {
+ if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) {
memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2);
- pwps_ie += wps_ielen + 2;
+ pwps_ie += (wps_ielen + 2);
if (pbackup_remainder_ie)
memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
- /* update ie_length */
- pnetwork->ie_length = wps_offset + wps_ielen + 2 + remainder_ielen;
+ /* update IELength */
+ pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen;
}
+exit:
kfree(pbackup_remainder_ie);
}
+static void update_bcn_p2p_ie(struct adapter *padapter)
+{
+}
+
static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
{
+ DBG_88E("%s\n", __func__);
- if (!memcmp(WPS_OUI, oui, 4))
+ if (!memcmp(RTW_WPA_OUI, oui, 4))
+ update_bcn_wpa_ie(padapter);
+ else if (!memcmp(WMM_OUI, oui, 4))
+ update_bcn_wmm_ie(padapter);
+ else if (!memcmp(WPS_OUI, oui, 4))
update_bcn_wps_ie(padapter);
+ else if (!memcmp(P2P_OUI, oui, 4))
+ update_bcn_p2p_ie(padapter);
+ else
+ DBG_88E("unknown OUI type!\n");
}
void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
@@ -1162,13 +1254,25 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
spin_lock_bh(&pmlmepriv->bcn_update_lock);
switch (ie_id) {
- case WLAN_EID_TIM:
+ case 0xFF:
+ update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+ break;
+ case _TIM_IE_:
update_BCNTIM(padapter);
break;
- case WLAN_EID_ERP_INFO:
+ case _ERPINFO_IE_:
update_bcn_erpinfo_ie(padapter);
break;
- case WLAN_EID_VENDOR_SPECIFIC:
+ case _HT_CAPABILITY_IE_:
+ update_bcn_htcap_ie(padapter);
+ break;
+ case _RSN_IE_2_:
+ update_bcn_rsn_ie(padapter);
+ break;
+ case _HT_ADD_INFO_IE_:
+ update_bcn_htinfo_ie(padapter);
+ break;
+ case _VENDOR_SPECIFIC_IE_:
update_bcn_vendor_spec_ie(padapter, oui);
break;
default:
@@ -1184,17 +1288,17 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
}
/*
- * op_mode
- * Set to 0 (HT pure) under the following conditions
- * - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- * - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
- * Set to 1 (HT non-member protection) if there may be non-HT STAs
- * in both the primary and the secondary channel
- * Set to 2 if only HT STAs are associated in BSS,
- * however and at least one 20 MHz HT STA is associated
- * Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
- * (currently non-GF HT station is considered as non-HT STA also)
- */
+op_mode
+Set to 0 (HT pure) under the followign conditions
+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+ in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+ however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+ (currently non-GF HT station is considered as non-HT STA also)
+*/
static int rtw_ht_operation_update(struct adapter *padapter)
{
u16 cur_op_mode, new_op_mode;
@@ -1205,6 +1309,9 @@ static int rtw_ht_operation_update(struct adapter *padapter)
if (pmlmepriv->htpriv.ht_option)
return 0;
+ DBG_88E("%s current operation mode = 0x%X\n",
+ __func__, pmlmepriv->ht_op_mode);
+
if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
pmlmepriv->num_sta_ht_no_gf) {
pmlmepriv->ht_op_mode |=
@@ -1254,12 +1361,15 @@ static int rtw_ht_operation_update(struct adapter *padapter)
op_mode_changes++;
}
+ DBG_88E("%s new operation mode = 0x%X changes =%d\n",
+ __func__, pmlmepriv->ht_op_mode, op_mode_changes);
+
return op_mode_changes;
}
void associated_clients_update(struct adapter *padapter, u8 updated)
{
- /* update associated stations cap. */
+ /* update associcated stations cap. */
if (updated) {
struct list_head *phead, *plist;
struct sta_info *psta = NULL;
@@ -1268,9 +1378,13 @@ void associated_clients_update(struct adapter *padapter, u8 updated)
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
+ plist = phead->next;
+
/* check asoc_queue */
- list_for_each(plist, phead) {
- psta = list_entry(plist, struct sta_info, asoc_list);
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, asoc_list);
+
+ plist = plist->next;
VCS_update(padapter, psta);
}
@@ -1319,7 +1433,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
if (pmlmepriv->num_sta_non_erp == 1) {
beacon_updated = true;
- update_beacon(padapter, WLAN_EID_ERP_INFO, NULL, true);
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
}
}
} else {
@@ -1330,12 +1444,12 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
if (pmlmepriv->num_sta_non_erp == 0) {
beacon_updated = true;
- update_beacon(padapter, WLAN_EID_ERP_INFO, NULL, true);
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
}
}
}
- if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)) {
+ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) {
if (!psta->no_short_slot_time_set) {
psta->no_short_slot_time_set = 1;
@@ -1364,6 +1478,9 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
if (psta->flags & WLAN_STA_HT) {
u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info);
+ DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n",
+ (psta->hwaddr), ht_capab);
+
if (psta->no_ht_set) {
psta->no_ht_set = 0;
pmlmepriv->num_sta_no_ht--;
@@ -1374,6 +1491,9 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
psta->no_ht_gf_set = 1;
pmlmepriv->num_sta_ht_no_gf++;
}
+ DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_no_gf);
}
if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH_20_40) == 0) {
@@ -1381,21 +1501,31 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
psta->ht_20mhz_set = 1;
pmlmepriv->num_sta_ht_20mhz++;
}
+ DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_20mhz);
}
} else {
if (!psta->no_ht_set) {
psta->no_ht_set = 1;
pmlmepriv->num_sta_no_ht++;
}
+ if (pmlmepriv->htpriv.ht_option) {
+ DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n",
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_no_ht);
+ }
}
if (rtw_ht_operation_update(padapter) > 0) {
- update_beacon(padapter, WLAN_EID_HT_CAPABILITY, NULL, false);
- update_beacon(padapter, WLAN_EID_HT_OPERATION, NULL, true);
+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associated stations cap. */
+ /* update associcated stations cap. */
associated_clients_update(padapter, beacon_updated);
+
+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
}
u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
@@ -1422,7 +1552,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
pmlmepriv->num_sta_non_erp--;
if (pmlmepriv->num_sta_non_erp == 0) {
beacon_updated = true;
- update_beacon(padapter, WLAN_EID_ERP_INFO, NULL, true);
+ update_beacon(padapter, _ERPINFO_IE_, NULL, true);
}
}
@@ -1452,11 +1582,13 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
}
if (rtw_ht_operation_update(padapter) > 0) {
- update_beacon(padapter, WLAN_EID_HT_CAPABILITY, NULL, false);
- update_beacon(padapter, WLAN_EID_HT_OPERATION, NULL, true);
+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
}
- /* update associated stations cap. */
+ /* update associcated stations cap. */
+
+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
return beacon_updated;
}
@@ -1501,22 +1633,66 @@ u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
return beacon_updated;
}
+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+ struct list_head *phead, *plist;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
+ return ret;
+
+ DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+ spin_lock_bh(&pstapriv->asoc_list_lock);
+ phead = &pstapriv->asoc_list;
+ plist = phead->next;
+
+ /* for each sta in asoc_queue */
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, asoc_list);
+ plist = plist->next;
+
+ issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
+ psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+ }
+ spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+ issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+ return ret;
+}
+
int rtw_sta_flush(struct adapter *padapter)
{
- struct list_head *phead;
- struct sta_info *psta, *temp;
+ struct list_head *phead, *plist;
+ int ret = 0;
+ struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)
- return 0;
+ return ret;
spin_lock_bh(&pstapriv->asoc_list_lock);
phead = &pstapriv->asoc_list;
+ plist = phead->next;
+
/* free sta asoc_queue */
- list_for_each_entry_safe(psta, temp, phead, asoc_list) {
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, asoc_list);
+
+ plist = plist->next;
+
list_del_init(&psta->asoc_list);
pstapriv->asoc_list_cnt--;
@@ -1528,7 +1704,7 @@ int rtw_sta_flush(struct adapter *padapter)
associated_clients_update(padapter, true);
- return 0;
+ return ret;
}
/* called > TSR LEVEL for USB or SDIO Interface*/
@@ -1604,6 +1780,9 @@ void start_ap_mode(struct adapter *padapter)
pmlmepriv->wps_probe_resp_ie = NULL;
pmlmepriv->wps_assoc_resp_ie = NULL;
+ pmlmepriv->p2p_beacon_ie = NULL;
+ pmlmepriv->p2p_probe_resp_ie = NULL;
+
/* for ACL */
INIT_LIST_HEAD(&pacl_list->acl_node_q.queue);
pacl_list->num = 0;
@@ -1616,7 +1795,8 @@ void start_ap_mode(struct adapter *padapter)
void stop_ap_mode(struct adapter *padapter)
{
- struct rtw_wlan_acl_node *paclnode, *n;
+ struct list_head *phead, *plist;
+ struct rtw_wlan_acl_node *paclnode;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1627,16 +1807,19 @@ void stop_ap_mode(struct adapter *padapter)
pmlmepriv->update_bcn = false;
pmlmeext->bstart_bss = false;
- /* reset and init security priv , this can refine with
- * rtw_reset_securitypriv
- */
+ /* reset and init security priv , this can refine with rtw_reset_securitypriv */
memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
/* for ACL */
spin_lock_bh(&pacl_node_q->lock);
- list_for_each_entry_safe(paclnode, n, &pacl_node_q->queue, list) {
+ phead = get_list_head(pacl_node_q);
+ plist = phead->next;
+ while (phead != plist) {
+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+ plist = plist->next;
+
if (paclnode->valid) {
paclnode->valid = false;
@@ -1647,6 +1830,8 @@ void stop_ap_mode(struct adapter *padapter)
}
spin_unlock_bh(&pacl_node_q->lock);
+ DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
+
rtw_sta_flush(padapter);
/* free_assoc_sta_resources */
diff --git a/drivers/staging/r8188eu/core/rtw_br_ext.c b/drivers/staging/r8188eu/core/rtw_br_ext.c
new file mode 100644
index 000000000000..62a672243696
--- /dev/null
+++ b/drivers/staging/r8188eu/core/rtw_br_ext.c
@@ -0,0 +1,717 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/
+
+#define _RTW_BR_EXT_C_
+
+#include "../include/linux/if_arp.h"
+#include "../include/net/ip.h"
+#include "../include/linux/atalk.h"
+#include "../include/linux/udp.h"
+#include "../include/linux/if_pppox.h"
+
+#include "../include/drv_types.h"
+#include "../include/rtw_br_ext.h"
+#include "../include/usb_osintf.h"
+#include "../include/recv_osdep.h"
+
+#ifndef csum_ipv6_magic
+#include "../include/net/ip6_checksum.h"
+#endif
+
+#include "../include/linux/ipv6.h"
+#include "../include/linux/icmpv6.h"
+#include "../include/net/ndisc.h"
+#include "../include/net/checksum.h"
+
+#define NAT25_IPV4 01
+#define NAT25_IPV6 02
+#define NAT25_IPX 03
+#define NAT25_APPLE 04
+#define NAT25_PPPOE 05
+
+#define RTL_RELAY_TAG_LEN (ETH_ALEN)
+#define TAG_HDR_LEN 4
+
+#define MAGIC_CODE 0x8186
+#define MAGIC_CODE_LEN 2
+#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */
+
+/*-----------------------------------------------------------------
+ How database records network address:
+ 0 1 2 3 4 5 6 7 8 9 10
+ |----|----|----|----|----|----|----|----|----|----|----|
+ IPv4 |type| | IP addr |
+ IPX |type| Net addr | Node addr |
+ IPX |type| Net addr |Sckt addr|
+ Apple |type| Network |node|
+ PPPoE |type| SID | AC MAC |
+-----------------------------------------------------------------*/
+
+/* Find a tag in pppoe frame and return the pointer */
+static unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
+{
+ unsigned char *cur_ptr, *start_ptr;
+ unsigned short tagLen, tagType;
+
+ start_ptr = cur_ptr = (unsigned char *)ph->tag;
+ while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
+ /* prevent un-alignment access */
+ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
+ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
+ if (tagType == type)
+ return cur_ptr;
+ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
+ }
+ return NULL;
+}
+
+static int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+ int data_len;
+
+ data_len = tag->tag_len + TAG_HDR_LEN;
+ if (skb_tailroom(skb) < data_len) {
+ _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+ return -1;
+ }
+
+ skb_put(skb, data_len);
+ /* have a room for new tag */
+ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+ ph->length = htons(ntohs(ph->length) + data_len);
+ memcpy((unsigned char *)ph->tag, tag, data_len);
+ return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+ int tail_len;
+ unsigned long end, tail;
+
+ if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
+ return -1;
+
+ tail = (unsigned long)skb_tail_pointer(skb);
+ end = (unsigned long)src+len;
+ if (tail < end)
+ return -1;
+
+ tail_len = (int)(tail-end);
+ if (tail_len > 0)
+ memmove(src, src+len, tail_len);
+
+ skb_trim(skb, skb->len-len);
+ return 0;
+}
+
+static unsigned long __nat25_timeout(struct adapter *priv)
+{
+ unsigned long timeout;
+
+ timeout = jiffies - NAT25_AGEING_TIME*HZ;
+
+ return timeout;
+}
+
+static int __nat25_has_expired(struct adapter *priv,
+ struct nat25_network_db_entry *fdb)
+{
+ if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+ return 1;
+
+ return 0;
+}
+
+static void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+ unsigned int *ipAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPV4;
+ memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
+}
+
+static void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+ unsigned char *ac_mac, __be16 *sid)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_PPPOE;
+ memcpy(networkAddr+1, (unsigned char *)sid, 2);
+ memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
+}
+
+static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+ unsigned int *ipAddr)
+{
+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+ networkAddr[0] = NAT25_IPV6;
+ memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
+}
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+ while (len > 0) {
+ if (*data == tag && *(data+1) == len8b && len >= len8b*8)
+ return data+2;
+
+ len -= (*(data+1))*8;
+ data += (*(data+1))*8;
+ }
+ return NULL;
+}
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+ unsigned char *mac;
+
+ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
+ if (len >= 8) {
+ mac = scan_tlv(&data[8], len-8, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+ if (len >= 16) {
+ mac = scan_tlv(&data[16], len-16, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+ if (len >= 24) {
+ mac = scan_tlv(&data[24], len-24, 1, 1);
+ if (mac) {
+ _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+ if (len >= 24) {
+ mac = scan_tlv(&data[24], len-24, 2, 1);
+ if (mac) {
+ _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+ if (len >= 40) {
+ mac = scan_tlv(&data[40], len-40, 2, 1);
+ if (mac) {
+ _DEBUG_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+ memcpy(mac, replace_mac, 6);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int __nat25_network_hash(unsigned char *networkAddr)
+{
+ if (networkAddr[0] == NAT25_IPV4) {
+ unsigned long x;
+
+ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_IPX) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_APPLE) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_PPPOE) {
+ unsigned long x;
+
+ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else if (networkAddr[0] == NAT25_IPV6) {
+ unsigned long x;
+
+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+ networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+ networkAddr[16];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ } else {
+ unsigned long x = 0;
+ int i;
+
+ for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
+ x ^= networkAddr[i];
+
+ return x & (NAT25_HASH_SIZE - 1);
+ }
+}
+
+static void __network_hash_link(struct adapter *priv,
+ struct nat25_network_db_entry *ent, int hash)
+{
+ /* Caller must spin_lock already! */
+ ent->next_hash = priv->nethash[hash];
+ if (ent->next_hash)
+ ent->next_hash->pprev_hash = &ent->next_hash;
+ priv->nethash[hash] = ent;
+ ent->pprev_hash = &priv->nethash[hash];
+}
+
+static void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+ /* Caller must spin_lock already! */
+ *ent->pprev_hash = ent->next_hash;
+ if (ent->next_hash)
+ ent->next_hash->pprev_hash = ent->pprev_hash;
+ ent->next_hash = NULL;
+ ent->pprev_hash = NULL;
+}
+
+static void __nat25_db_network_insert(struct adapter *priv,
+ unsigned char *macAddr, unsigned char *networkAddr)
+{
+ struct nat25_network_db_entry *db;
+ int hash;
+
+ spin_lock_bh(&priv->br_ext_lock);
+ hash = __nat25_network_hash(networkAddr);
+ db = priv->nethash[hash];
+ while (db) {
+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+ memcpy(db->macAddr, macAddr, ETH_ALEN);
+ db->ageing_timer = jiffies;
+ spin_unlock_bh(&priv->br_ext_lock);
+ return;
+ }
+ db = db->next_hash;
+ }
+ db = kmalloc(sizeof(*db), GFP_ATOMIC);
+ if (!db) {
+ spin_unlock_bh(&priv->br_ext_lock);
+ return;
+ }
+ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
+ memcpy(db->macAddr, macAddr, ETH_ALEN);
+ atomic_set(&db->use_count, 1);
+ db->ageing_timer = jiffies;
+
+ __network_hash_link(priv, db, hash);
+
+ spin_unlock_bh(&priv->br_ext_lock);
+}
+
+static void __nat25_db_print(struct adapter *priv)
+{
+}
+
+/*
+ * NAT2.5 interface
+ */
+
+void nat25_db_cleanup(struct adapter *priv)
+{
+ int i;
+
+ spin_lock_bh(&priv->br_ext_lock);
+
+ for (i = 0; i < NAT25_HASH_SIZE; i++) {
+ struct nat25_network_db_entry *f;
+ f = priv->nethash[i];
+ while (f) {
+ struct nat25_network_db_entry *g;
+
+ g = f->next_hash;
+ if (priv->scdb_entry == f) {
+ memset(priv->scdb_mac, 0, ETH_ALEN);
+ memset(priv->scdb_ip, 0, 4);
+ priv->scdb_entry = NULL;
+ }
+ __network_hash_unlink(f);
+ kfree(f);
+ f = g;
+ }
+ }
+ spin_unlock_bh(&priv->br_ext_lock);
+}
+
+void nat25_db_expire(struct adapter *priv)
+{
+ int i;
+
+ spin_lock_bh(&priv->br_ext_lock);
+
+ for (i = 0; i < NAT25_HASH_SIZE; i++) {
+ struct nat25_network_db_entry *f;
+ f = priv->nethash[i];
+
+ while (f) {
+ struct nat25_network_db_entry *g;
+ g = f->next_hash;
+
+ if (__nat25_has_expired(priv, f)) {
+ if (atomic_dec_and_test(&f->use_count)) {
+ if (priv->scdb_entry == f) {
+ memset(priv->scdb_mac, 0, ETH_ALEN);
+ memset(priv->scdb_ip, 0, 4);
+ priv->scdb_entry = NULL;
+ }
+ __network_hash_unlink(f);
+ kfree(f);
+ }
+ }
+ f = g;
+ }
+ }
+ spin_unlock_bh(&priv->br_ext_lock);
+}
+
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
+{
+ unsigned short protocol;
+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+ unsigned int tmp;
+
+ if (!skb)
+ return -1;
+
+ if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+ return -1;
+
+ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+
+ /*---------------------------------------------------*/
+ /* Handle IP frame */
+ /*---------------------------------------------------*/
+ if (protocol == ETH_P_IP) {
+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+ if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
+ DEBUG_WARN("NAT25: malformed IP packet !\n");
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ /* some multicast with source IP is all zero, maybe other case is illegal */
+ /* in class A, B, C, host address is all zero or all one is illegal */
+ if (iph->saddr == 0)
+ return 0;
+ tmp = be32_to_cpu(iph->saddr);
+ DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
+ __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+ /* record source IP address and , source mac address into db */
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == ETH_P_ARP) {
+ /*---------------------------------------------------*/
+ /* Handle ARP frame */
+ /*---------------------------------------------------*/
+ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+ unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+ unsigned int *sender;
+
+ if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
+ DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ return 0; /* skb_copy for all ARP frame */
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+ arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+ /* change to ARP sender mac address to wlan STA address */
+ memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+ arp_ptr += arp->ar_hln;
+ sender = (unsigned int *)arp_ptr;
+ __nat25_generate_ipv4_network_addr(networkAddr, sender);
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+ __nat25_db_print(priv);
+ return 0;
+ default:
+ return -1;
+ }
+ } else if ((protocol == ETH_P_PPP_DISC) ||
+ (protocol == ETH_P_PPP_SES)) {
+ /*---------------------------------------------------*/
+ /* Handle PPPoE frame */
+ /*---------------------------------------------------*/
+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+ unsigned short *pMagic;
+
+ switch (method) {
+ case NAT25_CHECK:
+ if (ph->sid == 0)
+ return 0;
+ return 1;
+ case NAT25_INSERT:
+ if (ph->sid == 0) { /* Discovery phase according to tag */
+ if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
+ if (priv->ethBrExtInfo.addPPPoETag) {
+ struct pppoe_tag *tag, *pOldTag;
+ unsigned char tag_buf[40];
+ int old_tag_len = 0;
+
+ tag = (struct pppoe_tag *)tag_buf;
+ pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+ if (pOldTag) { /* if SID existed, copy old value and delete it */
+ old_tag_len = ntohs(pOldTag->tag_len);
+ if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+ DEBUG_ERR("SID tag length too long!\n");
+ return -1;
+ }
+
+ memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
+ pOldTag->tag_data, old_tag_len);
+
+ if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
+ DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+ return -1;
+ }
+ ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
+ }
+
+ tag->tag_type = PTT_RELAY_SID;
+ tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
+
+ /* insert the magic_code+client mac in relay tag */
+ pMagic = (unsigned short *)tag->tag_data;
+ *pMagic = htons(MAGIC_CODE);
+ memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
+
+ /* Add relay tag */
+ if (__nat25_add_pppoe_tag(skb, tag) < 0)
+ return -1;
+
+ DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
+ (ph->code == PADI_CODE ? "PADI" : "PADR"));
+ } else { /* not add relay tag */
+ if (priv->pppoe_connection_in_progress &&
+ memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) {
+ DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+ return -2;
+ }
+
+ if (priv->pppoe_connection_in_progress == 0)
+ memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
+
+ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+ }
+ } else {
+ return -1;
+ }
+ } else { /* session phase */
+ DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+ __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &ph->sid);
+
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+ __nat25_db_print(priv);
+
+ if (!priv->ethBrExtInfo.addPPPoETag &&
+ priv->pppoe_connection_in_progress &&
+ !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+ priv->pppoe_connection_in_progress = 0;
+ }
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == 0x888e) {
+ /*---------------------------------------------------*/
+ /* Handle EAP frame */
+ /*---------------------------------------------------*/
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ return 0;
+ default:
+ return -1;
+ }
+ } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
+ /*---------------------------------------------------*/
+ /* Handle C-Media proprietary frame */
+ /*---------------------------------------------------*/
+ switch (method) {
+ case NAT25_CHECK:
+ return -1;
+ case NAT25_INSERT:
+ return 0;
+ default:
+ return -1;
+ }
+ } else if (protocol == ETH_P_IPV6) {
+ /*------------------------------------------------*/
+ /* Handle IPV6 frame */
+ /*------------------------------------------------*/
+ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
+ DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+ return -1;
+ }
+
+ switch (method) {
+ case NAT25_CHECK:
+ if (skb->data[0] & 1)
+ return 0;
+ return -1;
+ case NAT25_INSERT:
+ DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+ " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+ if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+ __nat25_db_print(priv);
+
+ if (iph->nexthdr == IPPROTO_ICMPV6 &&
+ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) {
+ if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
+ skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
+ struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+ hdr->icmp6_cksum = 0;
+ hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+ iph->payload_len,
+ IPPROTO_ICMPV6,
+ csum_partial((__u8 *)hdr, iph->payload_len, 0));
+ }
+ }
+ }
+ return 0;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+#define SERVER_PORT 67
+#define CLIENT_PORT 68
+#define DHCP_MAGIC 0x63825363
+#define BROADCAST_FLAG 0x8000
+
+struct dhcpMessage {
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ __be16 secs;
+ __be16 flags;
+ __be32 ciaddr;
+ __be32 yiaddr;
+ __be32 siaddr;
+ __be32 giaddr;
+ u_int8_t chaddr[16];
+ u_int8_t sname[64];
+ u_int8_t file[128];
+ __be32 cookie;
+ u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
+{
+ if (!skb)
+ return;
+
+ if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+ __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
+
+ if (protocol == __constant_htons(ETH_P_IP)) { /* IP */
+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+ if (iph->protocol == IPPROTO_UDP) { /* UDP */
+ struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
+
+ if ((udph->source == __constant_htons(CLIENT_PORT)) &&
+ (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */
+ struct dhcpMessage *dhcph =
+ (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
+ u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
+
+ if (cookie == DHCP_MAGIC) { /* match magic word */
+ if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
+ /* if not broadcast */
+ register int sum = 0;
+
+ DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
+ /* or BROADCAST flag */
+ dhcph->flags |= htons(BROADCAST_FLAG);
+ /* recalculate checksum */
+ sum = ~(udph->check) & 0xffff;
+ sum += be16_to_cpu(dhcph->flags);
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+ udph->check = ~sum;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+ unsigned char *ipAddr)
+{
+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+ struct nat25_network_db_entry *db;
+ int hash;
+
+ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
+ hash = __nat25_network_hash(networkAddr);
+ db = priv->nethash[hash];
+ while (db) {
+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+ return (void *)db;
+ }
+
+ db = db->next_hash;
+ }
+
+ return NULL;
+}
diff --git a/drivers/staging/r8188eu/core/rtw_cmd.c b/drivers/staging/r8188eu/core/rtw_cmd.c
new file mode 100644
index 000000000000..ce73ac7cf973
--- /dev/null
+++ b/drivers/staging/r8188eu/core/rtw_cmd.c
@@ -0,0 +1,2128 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2012 Realtek Corporation. */
+
+#define _RTW_CMD_C_
+
+#include "../include/osdep_service.h"
+#include "../include/drv_types.h"
+#include "../include/recv_osdep.h"
+#include "../include/mlme_osdep.h"
+#include "../include/rtw_br_ext.h"
+#include "../include/rtw_mlme_ext.h"
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+static int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+ int res = _SUCCESS;
+
+ sema_init(&pcmdpriv->cmd_queue_sema, 0);
+ /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */
+ sema_init(&pcmdpriv->terminate_cmdthread_sema, 0);
+
+ _rtw_init_queue(&pcmdpriv->cmd_queue);
+
+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+ pcmdpriv->cmd_seq = 1;
+
+ pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
+ GFP_KERNEL);
+
+ if (!pcmdpriv->cmd_allocated_buf) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1));
+
+ pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL);
+
+ if (!pcmdpriv->rsp_allocated_buf) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3);
+
+ pcmdpriv->cmd_issued_cnt = 0;
+ pcmdpriv->cmd_done_cnt = 0;
+ pcmdpriv->rsp_cnt = 0;
+exit:
+
+ return res;
+}
+
+static void c2h_wk_callback(struct work_struct *work);
+
+static int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+ int res = _SUCCESS;
+
+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+ atomic_set(&pevtpriv->event_seq, 0);
+ pevtpriv->evt_done_cnt = 0;
+
+ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+ pevtpriv->c2h_wk_alive = false;
+ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1);
+
+ return res;
+}
+
+void rtw_free_evt_priv(struct evt_priv *pevtpriv)
+{
+ _cancel_workitem_sync(&pevtpriv->c2h_wk);
+ while (pevtpriv->c2h_wk_alive)
+ msleep(10);
+
+ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
+ void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
+ if (c2h && c2h != (void *)pevtpriv)
+ kfree(c2h);
+ }
+}
+
+static void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+ if (pcmdpriv) {
+ kfree(pcmdpriv->cmd_allocated_buf);
+ kfree(pcmdpriv->rsp_allocated_buf);
+ }
+}
+
+/*
+Calling Context:
+
+rtw_enqueue_cmd can only be called between kernel thread,
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+
+*/
+
+static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+{
+ unsigned long flags;
+
+ if (!obj)
+ goto exit;
+
+ spin_lock_irqsave(&queue->lock, flags);
+
+ list_add_tail(&obj->list, &queue->queue);
+
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+exit:
+
+ return _SUCCESS;
+}
+
+static struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
+{
+ struct cmd_obj *obj;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ if (list_empty(&queue->queue)) {
+ obj = NULL;
+ } else {
+ obj = container_of((&queue->queue)->next, struct cmd_obj, list);
+ rtw_list_delete(&obj->list);
+ }
+
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return obj;
+}
+
+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+ u32 res;
+
+ res = _rtw_init_cmd_priv(pcmdpriv);
+
+ return res;
+}
+
+u32 rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+ int res;
+
+ res = _rtw_init_evt_priv(pevtpriv);
+
+ return res;
+}
+
+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+ _rtw_free_cmd_priv(pcmdpriv);
+}
+
+static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+ u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
+
+ /* To decide allow or not */
+ if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
+ (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+ if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
+ bAllow = true;
+ }
+ }
+
+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+ bAllow = true;
+
+ if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
+ !pcmdpriv->cmdthd_running) /* com_thread not running */
+ return _FAIL;
+ return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+ int res = _FAIL;
+ struct adapter *padapter = pcmdpriv->padapter;
+
+ if (!cmd_obj)
+ goto exit;
+
+ cmd_obj->padapter = padapter;
+
+ res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+ if (_FAIL == res) {
+ rtw_free_cmd_obj(cmd_obj);
+ goto exit;
+ }
+
+ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
+
+ if (res == _SUCCESS)
+ up(&pcmdpriv->cmd_queue_sema);
+
+exit:
+
+ return res;
+}
+
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+ struct cmd_obj *cmd_obj;
+
+ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
+
+ return cmd_obj;
+}
+
+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv)
+{
+
+ pcmdpriv->cmd_done_cnt++;
+ /* up(&(pcmdpriv->cmd_done_sema)); */
+
+}
+
+void rtw_free_cmd_obj(struct cmd_obj *pcmd)
+{
+
+ if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
+ /* free parmbuf in cmd_obj */
+ kfree(pcmd->parmbuf);
+ }
+
+ if (pcmd->rsp) {
+ if (pcmd->rspsz != 0) {
+ /* free rsp in cmd_obj */
+ kfree(pcmd->rsp);
+ }
+ }
+
+ /* free cmd_obj */
+ kfree(pcmd);
+
+}
+
+int rtw_cmd_thread(void *context)
+{
+ u8 ret;
+ struct cmd_obj *pcmd;
+ u8 *pcmdbuf;
+ u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
+ void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
+ struct adapter *padapter = (struct adapter *)context;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ thread_enter("RTW_CMD_THREAD");
+
+ pcmdbuf = pcmdpriv->cmd_buf;
+
+ pcmdpriv->cmdthd_running = true;
+ up(&pcmdpriv->terminate_cmdthread_sema);
+
+ while (1) {
+ if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL)
+ break;
+
+ if (padapter->bDriverStopped ||
+ padapter->bSurpriseRemoved) {
+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+ break;
+ }
+_next:
+ if (padapter->bDriverStopped ||
+ padapter->bSurpriseRemoved) {
+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+ break;
+ }
+
+ pcmd = rtw_dequeue_cmd(pcmdpriv);
+ if (!pcmd)
+ continue;
+
+ if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
+ pcmd->res = H2C_DROPPED;
+ goto post_process;
+ }
+
+ pcmdpriv->cmd_issued_cnt++;
+
+ pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */
+
+ memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
+ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+ if (cmd_hdl) {
+ ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+ pcmd->res = ret;
+ }
+
+ pcmdpriv->cmd_seq++;
+ } else {
+ pcmd->res = H2C_PARAMETERS_ERROR;
+ }
+
+ cmd_hdl = NULL;
+
+post_process:
+
+ /* call callback function for post-processed */
+ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
+ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+ if (!pcmd_callback)
+ rtw_free_cmd_obj(pcmd);
+ else
+ /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
+ pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+ } else {
+ rtw_free_cmd_obj(pcmd);
+ }
+
+ flush_signals_thread();
+
+ goto _next;
+ }
+ pcmdpriv->cmdthd_running = false;
+
+ /* free all cmd_obj resources */
+ do {
+ pcmd = rtw_dequeue_cmd(pcmdpriv);
+ if (!pcmd)
+ break;
+
+ /* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */
+
+ rtw_free_cmd_obj(pcmd);
+ } while (1);
+
+ up(&pcmdpriv->terminate_cmdthread_sema);
+
+ thread_exit();
+}
+
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action)
+{
+ struct cmd_obj *ph2c;
+ struct usb_suspend_parm *psetusbsuspend;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 ret = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ ret = _FAIL;
+ goto exit;
+ }
+
+ psetusbsuspend = kzalloc(sizeof(struct usb_suspend_parm), GFP_ATOMIC);
+ if (!psetusbsuspend) {
+ kfree(ph2c);
+ ret = _FAIL;
+ goto exit;
+ }
+
+ psetusbsuspend->action = action;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend));
+
+ ret = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return ret;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+ ### NOTE:#### (!!!!)
+ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
+ struct rtw_ieee80211_channel *ch, int ch_num)
+{
+ u8 res = _FAIL;
+ struct cmd_obj *ph2c;
+ struct sitesurvey_parm *psurveyPara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
+ }
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c)
+ return _FAIL;
+
+ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
+ if (!psurveyPara) {
+ kfree(ph2c);
+ return _FAIL;
+ }
+
+ rtw_free_network_queue(padapter, false);
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+
+ /* psurveyPara->bsslimit = 48; */
+ psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+ /* prepare ssid list */
+ if (ssid) {
+ int i;
+ for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
+ if (ssid[i].SsidLength) {
+ memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
+ psurveyPara->ssid_num++;
+ }
+ }
+ }
+
+ /* prepare channel list */
+ if (ch) {
+ int i;
+ for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+ if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
+ memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+ psurveyPara->ch_num++;
+ }
+ }
+ }
+
+ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+ if (res == _SUCCESS) {
+ pmlmepriv->scan_start_time = jiffies;
+
+ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
+
+ rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+
+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
+ } else {
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+ }
+
+ return res;
+}
+
+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
+{
+ struct cmd_obj *ph2c;
+ struct setdatarate_parm *pbsetdataratepara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pbsetdataratepara = kzalloc(sizeof(struct setdatarate_parm), GFP_ATOMIC);
+ if (!pbsetdataratepara) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+ pbsetdataratepara->mac_id = 5;
+ memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset)
+{
+ struct cmd_obj *ph2c;
+ struct setbasicrate_parm *pssetbasicratepara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ pssetbasicratepara = kzalloc(sizeof(struct setbasicrate_parm), GFP_ATOMIC);
+
+ if (!pssetbasicratepara) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_);
+
+ memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+/*
+unsigned char rtw_setphy_cmd(unsigned char *adapter)
+
+1. be called only after rtw_update_registrypriv_dev_network(~) or mp testing program
+2. for AdHoc/Ap mode or mp mode?
+
+*/
+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch)
+{
+ struct cmd_obj *ph2c;
+ struct setphy_parm *psetphypara;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ psetphypara = kzalloc(sizeof(struct setphy_parm), GFP_ATOMIC);
+
+ if (!psetphypara) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_);
+
+ psetphypara->modem = modem;
+ psetphypara->rfchannel = ch;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val)
+{
+ struct cmd_obj *ph2c;
+ struct writeBB_parm *pwritebbparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ pwritebbparm = kzalloc(sizeof(struct writeBB_parm), GFP_ATOMIC);
+
+ if (!pwritebbparm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg));
+
+ pwritebbparm->offset = offset;
+ pwritebbparm->value = val;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_getbbreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
+{
+ struct cmd_obj *ph2c;
+ struct readBB_parm *prdbbparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ prdbbparm = kzalloc(sizeof(struct readBB_parm), GFP_ATOMIC);
+
+ if (!prdbbparm) {
+ kfree(ph2c);
+ return _FAIL;
+ }
+
+ INIT_LIST_HEAD(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg);
+ ph2c->parmbuf = (unsigned char *)prdbbparm;
+ ph2c->cmdsz = sizeof(struct readBB_parm);
+ ph2c->rsp = pval;
+ ph2c->rspsz = sizeof(struct readBB_rsp);
+
+ prdbbparm->offset = offset;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_setrfreg_cmd(struct adapter *padapter, u8 offset, u32 val)
+{
+ struct cmd_obj *ph2c;
+ struct writeRF_parm *pwriterfparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ pwriterfparm = kzalloc(sizeof(struct writeRF_parm), GFP_ATOMIC);
+
+ if (!pwriterfparm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
+
+ pwriterfparm->offset = offset;
+ pwriterfparm->value = val;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_getrfreg_cmd(struct adapter *padapter, u8 offset, u8 *pval)
+{
+ struct cmd_obj *ph2c;
+ struct readRF_parm *prdrfparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ prdrfparm = kzalloc(sizeof(struct readRF_parm), GFP_ATOMIC);
+ if (!prdrfparm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ INIT_LIST_HEAD(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
+ ph2c->parmbuf = (unsigned char *)prdrfparm;
+ ph2c->cmdsz = sizeof(struct readRF_parm);
+ ph2c->rsp = pval;
+ ph2c->rspsz = sizeof(struct readRF_rsp);
+
+ prdrfparm->offset = offset;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+
+
+ kfree(pcmd->parmbuf);
+ kfree(pcmd);
+
+ if (padapter->registrypriv.mp_mode == 1)
+ padapter->mppriv.workparam.bcompleted = true;
+
+}
+
+void rtw_readtssi_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+
+
+ kfree(pcmd->parmbuf);
+ kfree(pcmd);
+
+ if (padapter->registrypriv.mp_mode == 1)
+ padapter->mppriv.workparam.bcompleted = true;
+
+}
+
+u8 rtw_createbss_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
+ u8 res = _SUCCESS;
+
+ rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmd) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ INIT_LIST_HEAD(&pcmd->list);
+ pcmd->cmdcode = _CreateBss_CMD_;
+ pcmd->parmbuf = (unsigned char *)pdev_network;
+ pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+ pdev_network->Length = pcmd->cmdsz;
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+
+ return res;
+}
+
+u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, unsigned int sz)
+{
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmd) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ INIT_LIST_HEAD(&pcmd->list);
+ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
+ pcmd->parmbuf = pbss;
+ pcmd->cmdsz = sz;
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
+{
+ u8 res = _SUCCESS;
+ uint t_len = 0;
+ struct wlan_bssid_ex *psecnetwork;
+ struct cmd_obj *pcmd;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+ enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+ rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmd) {
+ res = _FAIL;
+ goto exit;
+ }
+ /* for IEs is fix buf size */
+ t_len = sizeof(struct wlan_bssid_ex);
+
+ /* for hidden ap to set fw_state here */
+ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
+ switch (ndis_network_mode) {
+ case Ndis802_11IBSS:
+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+ break;
+ case Ndis802_11Infrastructure:
+ set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+ break;
+ case Ndis802_11APMode:
+ case Ndis802_11AutoUnknown:
+ case Ndis802_11InfrastructureMax:
+ break;
+ }
+ }
+
+ psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
+ if (!psecnetwork) {
+ kfree(pcmd);
+ res = _FAIL;
+ goto exit;
+ }
+
+ memset(psecnetwork, 0, t_len);
+
+ memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
+
+ psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
+
+ if (psecnetwork->IELength - 12 < 255) {
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12);
+ } else {
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], 255);
+ }
+
+ psecnetwork->IELength = 0;
+ /* Added by Albert 2009/02/18 */
+ /* If the the driver wants to use the bssid to create the connection. */
+ /* If not, we have to copy the connecting AP's MAC address to it so that */
+ /* the driver just has the bssid information for PMKIDList searching. */
+
+ if (!pmlmepriv->assoc_by_bssid)
+ memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
+
+ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
+
+ pqospriv->qos_option = 0;
+
+ if (pregistrypriv->wmm_enable) {
+ u32 tmp_len;
+
+ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
+
+ if (psecnetwork->IELength != tmp_len) {
+ psecnetwork->IELength = tmp_len;
+ pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
+ } else {
+ pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
+ }
+ }
+
+ phtpriv->ht_option = false;
+ if (pregistrypriv->ht_enable) {
+ /* Added by Albert 2010/06/23 */
+ /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
+ /* Especially for Realtek 8192u SoftAP. */
+ if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
+ (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
+ (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
+ /* rtw_restructure_ht_ie */
+ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
+ pnetwork->network.IELength, &psecnetwork->IELength);
+ }
+ }
+
+ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
+ padapter->pwrctrlpriv.smart_ps = 0;
+ else
+ padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
+
+ DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
+
+ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
+
+ INIT_LIST_HEAD(&pcmd->list);
+ pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
+ pcmd->parmbuf = (unsigned char *)psecnetwork;
+ pcmd->rsp = NULL;
+ pcmd->rspsz = 0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
+{
+ struct cmd_obj *cmdobj = NULL;
+ struct disconnect_parm *param = NULL;
+ struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ /* prepare cmd parameter */
+ param = kzalloc(sizeof(*param), GFP_ATOMIC);
+ if (!param) {
+ res = _FAIL;
+ goto exit;
+ }
+ param->deauth_timeout_ms = deauth_timeout_ms;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC);
+ if (!cmdobj) {
+ res = _FAIL;
+ kfree(param);
+ goto exit;
+ }
+ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+ res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
+ res = _FAIL;
+ kfree(param);
+ }
+
+exit:
+
+ return res;
+}
+
+u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype)
+{
+ struct cmd_obj *ph2c;
+ struct setopmode_parm *psetop;
+
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!ph2c) {
+ res = false;
+ goto exit;
+ }
+ psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL);
+
+ if (!psetop) {
+ kfree(ph2c);
+ res = false;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+ psetop->mode = (u8)networktype;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
+{
+ struct cmd_obj *ph2c;
+ struct set_stakey_parm *psetstakey_para;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct set_stakey_rsp *psetstakey_rsp = NULL;
+
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct sta_info *sta = (struct sta_info *)psta;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
+ if (!psetstakey_para) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL);
+ if (!psetstakey_rsp) {
+ kfree(ph2c);
+ kfree(psetstakey_para);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ ph2c->rsp = (u8 *)psetstakey_rsp;
+ ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+ psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm;
+ else
+ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
+
+ if (unicast_key)
+ memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+ else
+ memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+
+ /* jeff: set this because at least sw key is ready */
+ padapter->securitypriv.busetkipkey = true;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct set_stakey_parm *psetstakey_para;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct set_stakey_rsp *psetstakey_rsp = NULL;
+ struct sta_info *sta = (struct sta_info *)psta;
+ u8 res = _SUCCESS;
+
+ if (!enqueue) {
+ clear_cam_entry(padapter, entry);
+ } else {
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm),
+ GFP_ATOMIC);
+ if (!psetstakey_para) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp),
+ GFP_ATOMIC);
+ if (!psetstakey_rsp) {
+ kfree(ph2c);
+ kfree(psetstakey_para);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+ ph2c->rsp = (u8 *)psetstakey_rsp;
+ ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+ psetstakey_para->algorithm = _NO_PRIVACY_;
+
+ psetstakey_para->id = entry;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ }
+exit:
+
+ return res;
+}
+
+u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table)
+{
+ struct cmd_obj *ph2c;
+ struct setratable_parm *psetrttblparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ psetrttblparm = kzalloc(sizeof(struct setratable_parm), GFP_KERNEL);
+
+ if (!psetrttblparm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+ memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval)
+{
+ struct cmd_obj *ph2c;
+ struct getratable_parm *pgetrttblparm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+ pgetrttblparm = kzalloc(sizeof(struct getratable_parm), GFP_KERNEL);
+
+ if (!pgetrttblparm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+/* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */
+
+ INIT_LIST_HEAD(&ph2c->list);
+ ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable);
+ ph2c->parmbuf = (unsigned char *)pgetrttblparm;
+ ph2c->cmdsz = sizeof(struct getratable_parm);
+ ph2c->rsp = (u8 *)pval;
+ ph2c->rspsz = sizeof(struct getratable_rsp);
+
+ pgetrttblparm->rsvd = 0x0;
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr)
+{
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct cmd_obj *ph2c;
+ struct set_assocsta_parm *psetassocsta_para;
+ struct set_stakey_rsp *psetassocsta_rsp = NULL;
+
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetassocsta_para = kzalloc(sizeof(struct set_assocsta_parm), GFP_ATOMIC);
+ if (!psetassocsta_para) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ psetassocsta_rsp = kzalloc(sizeof(struct set_assocsta_rsp), GFP_ATOMIC);
+ if (!psetassocsta_rsp) {
+ kfree(ph2c);
+ kfree(psetassocsta_para);
+ return _FAIL;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
+ ph2c->rsp = (u8 *)psetassocsta_rsp;
+ ph2c->rspsz = sizeof(struct set_assocsta_rsp);
+
+ memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN);
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+ }
+
+u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
+{
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ struct cmd_obj *ph2c;
+ struct addBaReq_parm *paddbareq_parm;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
+ if (!paddbareq_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ paddbareq_parm->tid = tid;
+ memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+ /* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */
+
+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+ pdrvextra_cmd_parm->type_size = 0;
+ pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue)
+{
+ struct cmd_obj *pcmdobj;
+ struct set_ch_parm *set_ch_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+ FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+ /* check input parameter */
+
+ /* prepare cmd parameter */
+ set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_ATOMIC);
+ if (!set_ch_parm) {
+ res = _FAIL;
+ goto exit;
+ }
+ set_ch_parm->ch = ch;
+ set_ch_parm->bw = bw;
+ set_ch_parm->ch_offset = ch_offset;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmdobj) {
+ kfree(set_ch_parm);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm))
+ res = _FAIL;
+
+ kfree(set_ch_parm);
+ }
+
+ /* do something based on res... */
+
+exit:
+
+ DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+ return res;
+}
+
+u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
+{
+ struct cmd_obj *pcmdobj;
+ struct SetChannelPlan_param *setChannelPlan_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ /* check input parameter */
+ if (!rtw_is_channel_plan_valid(chplan)) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ /* prepare cmd parameter */
+ setChannelPlan_param = kzalloc(sizeof(struct SetChannelPlan_param),
+ GFP_KERNEL);
+ if (!setChannelPlan_param) {
+ res = _FAIL;
+ goto exit;
+ }
+ setChannelPlan_param->channel_plan = chplan;
+
+ if (enqueue) {
+ /* need enqueue, prepare cmd_obj and enqueue */
+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!pcmdobj) {
+ kfree(setChannelPlan_param);
+ res = _FAIL;
+ goto exit;
+ }
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+ } else {
+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+ if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param))
+ res = _FAIL;
+
+ kfree(setChannelPlan_param);
+ }
+
+ /* do something based on res... */
+ if (res == _SUCCESS)
+ padapter->mlmepriv.ChannelPlan = chplan;
+
+exit:
+
+ return res;
+}
+
+u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed)
+{
+ struct cmd_obj *pcmdobj;
+ struct LedBlink_param *ledBlink_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmdobj) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ ledBlink_param = kzalloc(sizeof(struct LedBlink_param), GFP_ATOMIC);
+ if (!ledBlink_param) {
+ kfree(pcmdobj);
+ res = _FAIL;
+ goto exit;
+ }
+
+ ledBlink_param->pLed = pLed;
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no)
+{
+ struct cmd_obj *pcmdobj;
+ struct SetChannelSwitch_param *setChannelSwitch_param;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!pcmdobj) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ setChannelSwitch_param = kzalloc(sizeof(struct SetChannelSwitch_param),
+ GFP_ATOMIC);
+ if (!setChannelSwitch_param) {
+ kfree(pcmdobj);
+ res = _FAIL;
+ goto exit;
+ }
+
+ setChannelSwitch_param->new_ch_no = new_ch_no;
+
+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch));
+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+ return res;
+}
+
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option)
+{
+ return _SUCCESS;
+}
+
+static void traffic_status_watchdog(struct adapter *padapter)
+{
+ u8 bEnterPS;
+ u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
+ u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ /* */
+ /* Determine if our traffic is busy now */
+ /* */
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
+ bBusyTraffic = true;
+
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+ bRxBusyTraffic = true;
+ else
+ bTxBusyTraffic = true;
+ }
+
+ /* Higher Tx/Rx data. */
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
+ bHigherBusyTraffic = true;
+
+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+ bHigherBusyRxTraffic = true;
+ else
+ bHigherBusyTxTraffic = true;
+ }
+
+ /* check traffic for powersaving. */
+ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
+ bEnterPS = false;
+ else
+ bEnterPS = true;
+
+ /* LeisurePS only work in infra mode. */
+ if (bEnterPS)
+ LPS_Enter(padapter);
+ else
+ LPS_Leave(padapter);
+ } else {
+ LPS_Leave(padapter);
+ }
+
+ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+}
+
+static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+ struct mlme_priv *pmlmepriv;
+
+ padapter = (struct adapter *)pbuf;
+ pmlmepriv = &padapter->mlmepriv;
+
+#ifdef CONFIG_88EU_AP_MODE
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ expire_timeout_chk(padapter);
+#endif
+
+ rtw_hal_sreset_xmit_status_check(padapter);
+
+ linked_status_chk(padapter);
+ traffic_status_watchdog(padapter);
+
+ rtw_hal_dm_watchdog(padapter);
+}
+
+static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
+{
+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ u8 mstatus;
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
+ return;
+
+ switch (lps_ctrl_type) {
+ case LPS_CTRL_SCAN:
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ /* connect */
+ LPS_Leave(padapter);
+ }
+ break;
+ case LPS_CTRL_JOINBSS:
+ LPS_Leave(padapter);
+ break;
+ case LPS_CTRL_CONNECT:
+ mstatus = 1;/* connect */
+ /* Reset LPS Setting */
+ padapter->pwrctrlpriv.LpsIdleCount = 0;
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+ break;
+ case LPS_CTRL_DISCONNECT:
+ mstatus = 0;/* disconnect */
+ LPS_Leave(padapter);
+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+ break;
+ case LPS_CTRL_SPECIAL_PACKET:
+ /* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */
+ pwrpriv->DelayLPSLastTimeStamp = jiffies;
+ LPS_Leave(padapter);
+ break;
+ case LPS_CTRL_LEAVE:
+ LPS_Leave(padapter);
+ break;
+ default:
+ break;
+ }
+
+}
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
+ u8 res = _SUCCESS;
+
+ /* if (!pwrctrlpriv->bLeisurePs) */
+ /* return res; */
+
+ if (enqueue) {
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+ GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+ pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+ pdrvextra_cmd_parm->pbuf = NULL;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ } else {
+ lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+ }
+
+exit:
+
+ return res;
+}
+
+static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
+}
+
+u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+ GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
+ pdrvextra_cmd_parm->type_size = min_time;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+ return res;
+}
+
+static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
+{
+ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
+}
+
+u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 support_ant_div;
+ u8 res = _SUCCESS;
+
+ rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
+ if (!support_ant_div)
+ return res;
+
+ if (enqueue) {
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+ GFP_KERNEL);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
+ pdrvextra_cmd_parm->type_size = antenna;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+ } else {
+ antenna_select_wk_hdl(padapter, antenna);
+ }
+exit:
+
+ return res;
+}
+
+static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+ rtw_ps_processor(padapter);
+}
+
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ return res;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+ pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */
+ pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+#endif /* CONFIG_88EU_P2P */
+
+u8 rtw_ps_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ppscmd;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+ u8 res = _SUCCESS;
+
+ ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ppscmd) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ppscmd);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+ pdrvextra_cmd_parm->pbuf = NULL;
+ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
+
+exit:
+
+ return res;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
+{
+ int cnt = 0;
+ struct sta_info *psta_bmc;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ psta_bmc = rtw_get_bcmc_stainfo(padapter);
+ if (!psta_bmc)
+ return;
+
+ if (psta_bmc->sleepq_len == 0) {
+ u8 val = 0;
+
+ /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */
+ /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+
+ while (!val) {
+ msleep(100);
+
+ cnt++;
+
+ if (cnt > 10)
+ break;
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+ }
+
+ if (cnt <= 10) {
+ pstapriv->tim_bitmap &= ~BIT(0);
+ pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+ update_beacon(padapter, _TIM_IE_, NULL, false);
+ } else { /* re check again */
+ rtw_chk_hi_queue_cmd(padapter);
+ }
+ }
+}
+
+u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+ pdrvextra_cmd_parm->type_size = 0;
+ pdrvextra_cmd_parm->pbuf = NULL;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+ return res;
+}
+#endif
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
+{
+ struct cmd_obj *ph2c;
+ struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 res = _SUCCESS;
+
+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+ if (!ph2c) {
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+ if (!pdrvextra_cmd_parm) {
+ kfree(ph2c);
+ res = _FAIL;
+ goto exit;
+ }
+
+ pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+ pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
+ pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+ res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+ return res;
+}
+
+static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
+{
+ s32 ret = _FAIL;
+ u8 buf[16];
+
+ if (!c2h_evt) {
+ /* No c2h event in cmd_obj, read c2h event before handling*/
+ if (c2h_evt_read(adapter, buf) == _SUCCESS) {
+ c2h_evt = (struct c2h_evt_hdr *)buf;
+
+ if (filter && !filter(c2h_evt->id))
+ goto exit;
+
+ ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+ }
+ } else {
+ if (filter && !filter(c2h_evt->id))
+ goto exit;
+
+ ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+ }
+exit:
+ return ret;
+}
+
+static void c2h_wk_callback(struct work_struct *work)
+{
+ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
+ struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
+ struct c2h_evt_hdr *c2h_evt;
+ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
+
+ evtpriv->c2h_wk_alive = true;
+
+ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
+ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+ /* This C2H event is read, clear it */
+ c2h_evt_clear(adapter);
+ } else {
+ c2h_evt = kmalloc(16, GFP_KERNEL);
+ if (c2h_evt) {
+ /* This C2H event is not read, read & clear now */
+ if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS) {
+ kfree(c2h_evt);
+ continue;
+ }
+ } else {
+ return;
+ }
+ }
+
+ /* Special pointer to trigger c2h_evt_clear only */
+ if ((void *)c2h_evt == (void *)evtpriv)
+ continue;
+
+ if (!c2h_evt_exist(c2h_evt)) {
+ kfree(c2h_evt);
+ continue;
+ }
+
+ if (ccx_id_filter(c2h_evt->id)) {
+ /* Handle CCX report here */
+ rtw_hal_c2h_handler(adapter, c2h_evt);
+ kfree(c2h_evt);
+ } else {
+#ifdef CONFIG_88EU_P2P
+ /* Enqueue into cmd_thread for others */
+ rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
+#endif
+ }
+ }
+
+ evtpriv->c2h_wk_alive = false;
+}
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+ struct drvextra_cmd_parm *pdrvextra_cmd;
+
+ if (!pbuf)
+ return H2C_PARAMETERS_ERROR;
+
+ pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
+
+ switch (pdrvextra_cmd->ec_id) {
+ case DYNAMIC_CHK_WK_CID:
+ dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+ break;
+ case POWER_SAVING_CTRL_WK_CID:
+ power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+ break;
+ case LPS_CTRL_WK_CID:
+ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
+ break;
+ case RTP_TIMER_CFG_WK_CID:
+ rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+ case ANT_SELECT_WK_CID:
+ antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+#ifdef CONFIG_88EU_P2P
+ case P2P_PS_WK_CID:
+ p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+ case P2P_PROTO_WK_CID:
+ /* Commented by Albert 2011/07/01 */
+ /* I used the type_size as the type command */
+ p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
+ break;
+#endif
+#ifdef CONFIG_88EU_AP_MODE
+ case CHECK_HIQ_WK_CID:
+ rtw_chk_hi_queue_hdl(padapter);
+ break;
+#endif /* CONFIG_88EU_AP_MODE */
+ case C2H_WK_CID:
+ c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
+ break;
+ default:
+ break;
+ }
+
+ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
+ kfree(pdrvextra_cmd->pbuf);
+
+ return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (pcmd->res == H2C_DROPPED) {
+ /* TODO: cancel timer and do timeout handler directly... */
+ /* need to make timeout handlerOS independent */
+ _set_timer(&pmlmepriv->scan_to_timer, 1);
+ } else if (pcmd->res != H2C_SUCCESS) {
+ _set_timer(&pmlmepriv->scan_to_timer, 1);
+ }
+
+ /* free cmd */
+ rtw_free_cmd_obj(pcmd);
+
+}
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (pcmd->res != H2C_SUCCESS) {
+ spin_lock_bh(&pmlmepriv->lock);
+ set_fwstate(pmlmepriv, _FW_LINKED);
+ spin_unlock_bh(&pmlmepriv->lock);
+
+ return;
+ } else /* clear bridge database */
+ nat25_db_cleanup(padapter);
+
+ /* free cmd */
+ rtw_free_cmd_obj(pcmd);
+}
+
+void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (pcmd->res == H2C_DROPPED) {
+ /* TODO: cancel timer and do timeout handler directly... */
+ /* need to make timeout handlerOS independent */
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ } else if (pcmd->res != H2C_SUCCESS) {
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+ }
+
+ rtw_free_cmd_obj(pcmd);
+}
+
+void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ u8 timer_cancelled;
+ struct sta_info *psta = NULL;
+ struct wlan_network *pwlan = NULL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
+ struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+ if (pcmd->res != H2C_SUCCESS)
+ _set_timer(&pmlmepriv->assoc_timer, 1);
+
+ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+ spin_lock_bh(&pmlmepriv->lock);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+ if (!psta) {
+ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+ if (!psta)
+ goto createbss_cmd_fail;
+ }
+
+ rtw_indicate_connect(padapter);
+ } else {
+
+ pwlan = _rtw_alloc_network(pmlmepriv);
+ spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+ if (!pwlan) {
+ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
+ if (!pwlan) {
+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+ goto createbss_cmd_fail;
+ }
+ pwlan->last_scanned = jiffies;
+ } else {
+ list_add_tail(&pwlan->list, &pmlmepriv->scanned_queue.queue);
+ }
+
+ pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
+ memcpy(&pwlan->network, pnetwork, pnetwork->Length);
+
+ memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+ /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
+ }
+
+createbss_cmd_fail:
+
+ spin_unlock_bh(&pmlmepriv->lock);
+
+ rtw_free_cmd_obj(pcmd);
+
+}
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
+ struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
+
+ if (!psta)
+ goto exit;
+exit:
+ rtw_free_cmd_obj(pcmd);
+
+}
+
+void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
+ struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
+ struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
+
+ if (!psta)
+ goto exit;
+
+ psta->aid = passocsta_rsp->cam_id;
+ psta->mac_id = passocsta_rsp->cam_id;
+
+ spin_lock_bh(&pmlmepriv->lock);
+
+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+ set_fwstate(pmlmepriv, _FW_LINKED);
+ spin_unlock_bh(&pmlmepriv->lock);
+
+exit:
+ rtw_free_cmd_obj(pcmd);
+
+}
diff --git a/drivers/staging/r8188eu/core/rtw_debug.c b/drivers/staging/r8188eu/core/rtw_debug.c
new file mode 100644
index 000000000000..2ee64cef73f7
--- /dev/null
+++ b/drivers/staging/r8188eu/core/rtw_debug.c
@@ -0,0 +1,904 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2012 Realtek Corporation. */
+
+#define _RTW_DEBUG_C_
+
+#include "../include/rtw_debug.h"
+#include "../include/drv_types.h"
+
+int proc_get_drv_version(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_write_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ *eof = 1;
+ return 0;
+}
+
+int proc_set_write_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 addr, val, len;
+
+ if (count < 3) {
+ DBG_88E("argument size is less than 3\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
+
+ if (num != 3) {
+ DBG_88E("invalid write_reg parameter!\n");
+ return count;
+ }
+ switch (len) {
+ case 1:
+ rtw_write8(padapter, addr, (u8)val);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)val);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, val);
+ break;
+ default:
+ DBG_88E("error write length =%d", len);
+ break;
+ }
+ }
+ return count;
+}
+
+static u32 proc_get_read_addr = 0xeeeeeeee;
+static u32 proc_get_read_len = 0x4;
+
+int proc_get_read_reg(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ int len = 0;
+
+ if (proc_get_read_addr == 0xeeeeeeee) {
+ *eof = 1;
+ return len;
+ }
+
+ switch (proc_get_read_len) {
+ case 1:
+ len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr));
+ break;
+ case 2:
+ len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr));
+ break;
+ case 4:
+ len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr));
+ break;
+ default:
+ len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len);
+ break;
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_read_reg(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char tmp[16];
+ u32 addr, len;
+
+ if (count < 2) {
+ DBG_88E("argument size is less than 2\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x %x", &addr, &len);
+
+ if (num != 2) {
+ DBG_88E("invalid read_reg parameter!\n");
+ return count;
+ }
+
+ proc_get_read_addr = addr;
+
+ proc_get_read_len = len;
+ }
+
+ return count;
+}
+
+int proc_get_fwstate(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv));
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_sec_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n",
+ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mlmext_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_qos_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_ht_option(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ int len = 0;
+ len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option);
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n",
+ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ *eof = 1;
+ return len;
+}
+
+int proc_get_ap_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct sta_info *psta;
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct wlan_network *cur_network = &pmlmepriv->cur_network;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int len = 0;
+
+ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+ if (psta) {
+ int i;
+ struct recv_reorder_ctrl *preorder_ctrl;
+
+ len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid);
+ len += snprintf(page + len, count - len, "sta's macaddr:%pM\n", psta->hwaddr);
+ len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+ for (i = 0; i < 16; i++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[i];
+ if (preorder_ctrl->enable)
+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq);
+ }
+ } else {
+ len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr: %pM\n", cur_network->network.MacAddress);
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_adapter_state(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
+ padapter->bSurpriseRemoved, padapter->bDriverStopped);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_trx_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d, free_ext_xmitbuf_cnt=%d, free_recvframe_cnt=%d\n",
+ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt, precvpriv->free_recvframe_cnt);
+ len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt);
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+ for (i = 0x0; i < 0x300; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+ memset(page, 0, count);
+ for (i = 0x300; i < 0x600; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_mac_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+ for (i = 0x600; i < 0x800; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0x800; i < 0xB00; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0xB00; i < 0xE00; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_bb_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1;
+
+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+ for (i = 0xE00; i < 0x1000; i += 4) {
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump1(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 1;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0; i < 0xC0; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump2(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 1;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0xC0; i < 0x100; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump3(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 2;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0; i < 0xC0; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rf_reg_dump4(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+ int i, j = 1, path;
+ u32 value;
+
+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+ path = 2;
+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+ for (i = 0xC0; i < 0x100; i++) {
+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+ if (j % 4 == 1)
+ len += snprintf(page + len, count - len, "0x%02x ", i);
+ len += snprintf(page + len, count - len, " 0x%08x ", value);
+ if ((j++) % 4 == 0)
+ len += snprintf(page + len, count - len, "\n");
+ }
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rx_signal(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ int len = 0;
+
+ len = snprintf(page + len, count,
+ "rssi:%d\n"
+ "rxpwdb:%d\n"
+ "signal_strength:%u\n"
+ "signal_qual:%u\n"
+ "noise:%u\n",
+ padapter->recvpriv.rssi,
+ padapter->recvpriv.rxpwdb,
+ padapter->recvpriv.signal_strength,
+ padapter->recvpriv.signal_qual,
+ padapter->recvpriv.noise
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_rx_signal(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 is_signal_dbg;
+ s32 signal_strength;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength);
+ is_signal_dbg = is_signal_dbg == 0 ? 0 : 1;
+ if (is_signal_dbg && num != 2)
+ return count;
+
+ signal_strength = signal_strength > 100 ? 100 : signal_strength;
+ signal_strength = signal_strength < 0 ? 0 : signal_strength;
+
+ padapter->recvpriv.is_signal_dbg = is_signal_dbg;
+ padapter->recvpriv.signal_strength_dbg = signal_strength;
+
+ if (is_signal_dbg)
+ DBG_88E("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength);
+ else
+ DBG_88E("set %s\n", "HW_SIGNAL_STRENGTH");
+ }
+ return count;
+}
+
+int proc_get_ht_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->ht_enable
+ );
+ *eof = 1;
+ return len;
+}
+
+int proc_set_ht_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->ht_enable = mode;
+ pr_info("ht_enable=%d\n", pregpriv->ht_enable);
+ }
+ }
+
+ return count;
+}
+
+int proc_get_cbw40_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->cbw40_enable
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_cbw40_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->cbw40_enable = mode;
+ pr_info("cbw40_enable=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_ampdu_enable(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->ampdu_enable
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_ampdu_enable(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ s32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->ampdu_enable = mode;
+ pr_info("ampdu_enable=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_two_path_rssi(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+ int len = 0;
+
+ if (padapter)
+ len += snprintf(page + len, count - len,
+ "%d %d\n",
+ padapter->recvpriv.RxRssi[0],
+ padapter->recvpriv.RxRssi[1]
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_get_rx_stbc(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ int len = 0;
+
+ if (pregpriv)
+ len += snprintf(page + len, count - len,
+ "%d\n",
+ pregpriv->rx_stbc
+ );
+
+ *eof = 1;
+ return len;
+}
+
+int proc_set_rx_stbc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ char tmp[32];
+ u32 mode = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ if (pregpriv) {
+ pregpriv->rx_stbc = mode;
+ printk("rx_stbc=%d\n", mode);
+ }
+ }
+ return count;
+}
+
+int proc_get_rssi_disp(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ *eof = 1;
+ return 0;
+}
+
+int proc_set_rssi_disp(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 enable = 0;
+
+ if (count < 1) {
+ DBG_88E("argument size is less than 1\n");
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+ int num = sscanf(tmp, "%x", &enable);
+
+ if (num != 1) {
+ DBG_88E("invalid set_rssi_disp parameter!\n");
+ return count;
+ }
+
+ if (enable) {
+ DBG_88E("Turn On Rx RSSI Display Function\n");
+ padapter->bRxRSSIDisplay = enable;
+ } else {
+ DBG_88E("Turn Off Rx RSSI Display Function\n");
+ padapter->bRxRSSIDisplay = 0;
+ }
+ }
+ return count;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+int proc_get_all_sta_info(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct sta_info *psta;
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int i, j;
+ struct list_head *plist, *phead;
+ struct recv_reorder_ctrl *preorder_ctrl;
+ int len = 0;
+
+ len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+
+ spin_lock_bh(&pstapriv->sta_hash_lock);
+
+ for (i = 0; i < NUM_STA; i++) {
+ phead = &pstapriv->sta_hash[i];
+ plist = phead->next;
+
+ while (phead != plist) {
+ psta = container_of(plist, struct sta_info, hash_list);
+
+ plist = plist->next;
+
+ len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr);
+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+ len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len);
+ len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability);
+ len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags);
+ len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk);
+ len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher);
+ len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher);
+ len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info);
+ len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy);
+
+ for (j = 0; j < 16; j++) {
+ preorder_ctrl = &psta->recvreorder_ctrl[j];
+ if (preorder_ctrl->enable)
+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq);
+ }
+ }
+ }
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+ *eof = 1;
+ return len;
+}
+#endif
+
+int proc_get_best_channel(char *page, char **start,
+ off_t offset, int count,
+ int *eof, void *data)
+{
+ struct net_device *dev = data;
+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ int len = 0;
+ u32 i, best_channel_24G = 1, index_24G = 0;
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ if (pmlmeext->channel_set[i].ChannelNum == 1)
+ index_24G = i;
+ }
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ /* 2.4G */
+ if (pmlmeext->channel_set[i].ChannelNum == 6) {
+ if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) {
+ index_24G = i;
+ best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+
+ /* debug */
+ len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
+ pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
+ }
+
+ len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
+
+ *eof = 1;
+ return len;
+}
diff --git a/drivers/staging/r8188eu/core/rtw_efuse.c b/drivers/staging/r8188eu/core/rtw_efuse.c
new file mode 100644
index 000000000000..c1c70648f5bc
--- /dev/null
+++ b/drivers/staging/r8188eu/core/rtw_efuse.c
@@ -0,0 +1,848 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2011 Realtek Corporation. */
+
+#define _RTW_EFUSE_C_
+
+#include "../include/osdep_service.h"
+#include "../include/drv_types.h"
+#include "../include/rtw_efuse.h"
+
+/*------------------------Define local variable------------------------------*/
+u8 fakeEfuseBank;
+u32 fakeEfuseUsedBytes;
+u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
+u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
+u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
+
+u32 BTEfuseUsedBytes;
+u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+
+u32 fakeBTEfuseUsedBytes;
+u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+/*------------------------Define local variable------------------------------*/
+
+/* */
+#define REG_EFUSE_CTRL 0x0030
+#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */
+/* */
+static bool Efuse_Read1ByteFromFakeContent(struct adapter *pAdapter,
+ u16 Offset,
+ u8 *Value)
+{
+ if (Offset >= EFUSE_MAX_HW_SIZE)
+ return false;
+ if (fakeEfuseBank == 0)
+ *Value = fakeEfuseContent[Offset];
+ else
+ *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset];
+ return true;
+}
+
+static bool
+Efuse_Write1ByteToFakeContent(
+ struct adapter *pAdapter,
+ u16 Offset,
+ u8 Value)
+{
+ if (Offset >= EFUSE_MAX_HW_SIZE)
+ return false;
+ if (fakeEfuseBank == 0) {
+ fakeEfuseContent[Offset] = Value;
+ } else {
+ fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value;
+ }
+ return true;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: Efuse_PowerSwitch
+ *
+ * Overview: When we want to enable write operation, we should change to
+ * pwr on state. When we stop write, we should switch to 500k mode
+ * and disable LDO 2.5V.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/17/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+Efuse_PowerSwitch(
+ struct adapter *pAdapter,
+ u8 write,
+ u8 PwrState)
+{
+ pAdapter->HalFunc.EfusePowerSwitch(pAdapter, write, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: efuse_GetCurrentSize
+ *
+ * Overview: Get current efuse size!!!
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/16/2008 MHC Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize(
+ struct adapter *pAdapter,
+ u8 efuseType,
+ bool pseudo)
+{
+ u16 ret = 0;
+
+ ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, pseudo);
+
+ return ret;
+}
+
+/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(u8 word_en)
+{
+ u8 word_cnts = 0;
+ if (!(word_en & BIT(0)))
+ word_cnts++; /* 0 : write enable */
+ if (!(word_en & BIT(1)))
+ word_cnts++;
+ if (!(word_en & BIT(2)))
+ word_cnts++;
+ if (!(word_en & BIT(3)))
+ word_cnts++;
+ return word_cnts;
+}
+
+/* */
+/* Description: */
+/* Execute E-Fuse read byte operation. */
+/* Referred from SD1 Richard. */
+/* */
+/* Assumption: */
+/* 1. Boot from E-Fuse and successfully auto-load. */
+/* 2. PASSIVE_LEVEL (USB interface) */
+/* */
+/* Created by Roger, 2008.10.21. */
+/* */
+void
+ReadEFuseByte(
+ struct adapter *Adapter,
+ u16 _offset,
+ u8 *pbuf,
+ bool pseudo)
+{
+ u32 value32;
+ u8 readbyte;
+ u16 retry;
+
+ if (pseudo) {
+ Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf);
+ return;
+ }
+
+ /* Write Address */
+ rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff));
+ readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2);
+ rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+ /* Write bit 32 0 */
+ readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3);
+ rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f));
+
+ /* Check bit 32 read-ready */
+ retry = 0;
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) {
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+ retry++;
+ }
+
+ /* 20100205 Joseph: Add delay suggested by SD1 Victor. */
+ /* This fix the problem that Efuse read error in high temperature condition. */
+ /* Designer says that there shall be some delay after ready bit is set, or the */
+ /* result will always stay on last data we read. */
+ udelay(50);
+ value32 = rtw_read32(Adapter, EFUSE_CTRL);
+
+ *pbuf = (u8)(value32 & 0xff);
+}
+
+/* */
+/* Description: */
+/* 1. Execute E-Fuse read byte operation according as map offset and */
+/* save to E-Fuse table. */
+/* 2. Referred from SD1 Richard. */
+/* */
+/* Assumption: */
+/* 1. Boot from E-Fuse and successfully auto-load. */
+/* 2. PASSIVE_LEVEL (USB interface) */
+/* */
+/* Created by Roger, 2008.10.21. */
+/* */
+/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */
+/* 2. Add efuse utilization collect. */
+/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */
+/* write addr must be after sec5. */
+/* */
+
+static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo)
+{
+ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, pseudo);
+}
+
+void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool pseudo
+ )
+{
+ pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, pseudo);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: EFUSE_Read1Byte
+ *
+ * Overview: Copy from WMAC fot EFUSE read 1 byte.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 09/23/2008 MHC Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+u8 EFUSE_Read1Byte(struct adapter *Adapter, u16 Address)
+{
+ u8 data;
+ u8 Bytetemp = {0x00};
+ u8 temp = {0x00};
+ u32 k = 0;
+ u16 contentLen = 0;
+
+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false);
+
+ if (Address < contentLen) { /* E-fuse 512Byte */
+ /* Write E-fuse Register address bit0~7 */
+ temp = Address & 0xFF;
+ rtw_write8(Adapter, EFUSE_CTRL + 1, temp);
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 2);
+ /* Write E-fuse Register address bit8~9 */
+ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
+ rtw_write8(Adapter, EFUSE_CTRL + 2, temp);
+
+ /* Write 0x30[31]= 0 */
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3);
+ temp = Bytetemp & 0x7F;
+ rtw_write8(Adapter, EFUSE_CTRL + 3, temp);
+
+ /* Wait Write-ready (0x30[31]= 1) */
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3);
+ while (!(Bytetemp & 0x80)) {
+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3);
+ k++;
+ if (k == 1000) {
+ k = 0;
+ break;
+ }
+ }
+ data = rtw_read8(Adapter, EFUSE_CTRL);
+ return data;
+ } else {
+ return 0xFF;
+ }
+
+} /* EFUSE_Read1Byte */
+
+/* 11/16/2008 MH Read one byte from real Efuse. */
+u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo)
+{
+ u8 tmpidx = 0;
+ u8 result;
+
+ if (pseudo) {
+ result = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data);
+ return result;
+ }
+ /* -----------------e-fuse reg ctrl --------------------------------- */
+ /* address */
+ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff));
+ rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) |
+ (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC));
+
+ rtw_write8(pAdapter, EFUSE_CTRL + 3, 0x72);/* read cmd */
+
+ while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100))
+ tmpidx++;
+ if (tmpidx < 100) {
+ *data = rtw_read8(pAdapter, EFUSE_CTRL);
+ result = true;
+ } else {
+ *data = 0xff;
+ result = false;
+ }
+ return result;
+}
+
+/* 11/16/2008 MH Write one byte to reald Efuse. */
+u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo)
+{
+ u8 tmpidx = 0;
+ u8 result;
+
+ if (pseudo) {
+ result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data);
+ return result;
+ }
+
+ /* -----------------e-fuse reg ctrl --------------------------------- */
+ /* address */
+ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff));
+ rtw_write8(pAdapter, EFUSE_CTRL + 2,
+ (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC) |
+ (u8)((addr >> 8) & 0x03));
+ rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */
+
+ rtw_write8(pAdapter, EFUSE_CTRL + 3, 0xF2);/* write cmd */
+
+ while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100))
+ tmpidx++;
+
+ if (tmpidx < 100)
+ result = true;
+ else
+ result = false;
+
+ return result;
+}
+
+int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool pseudo)
+{
+ int ret = 0;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, pseudo);
+
+ return ret;
+}
+
+int Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+ int ret;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, pseudo);
+
+ return ret;
+}
+
+static int Efuse_PgPacketWrite_BT(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+ int ret;
+
+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, pseudo);
+
+ return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function: efuse_WordEnableDataRead
+ *
+ * Overview: Read allowed word in current efuse section data.
+ *
+ * Input: NONE
+ *
+ * Output: NONE
+ *
+ * Return: NONE
+ *
+ * Revised History:
+ * When Who Remark
+ * 11/16/2008 MHC Create Version 0.
+ * 11/21/2008 MHC Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
+{
+ if (!(word_en & BIT(0))) {
+ targetdata[0] = sourdata[0];
+ targetdata[1] = sourdata[1];
+ }
+ if (!(word_en & BIT(1))) {
+ targetdata[2] = sourdata[2];
+ targetdata[3] = sourdata[3];
+ }
+ if (!(word_en & BIT(2))) {
+ targetdata[4] = sourdata[4];
+ targetdata[5] = sourdata[5];
+ }
+ if (!(word_en & BIT(3))) {
+ targetdata[6] = sourdata[6];
+ targetdata[7] = sourdata[7];
+ }
+}
+
+u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool pseudo)
+{
+ u8 ret = 0;
+
+ ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, pseudo);
+
+ return ret;
+}
+
+static u8 efuse_read8(struct adapter *padapter, u16 address, u8 *value)
+{
+ return efuse_OneByteRead(padapter, address, value, false);
+}
+
+static u8 efuse_write8(struct adapter *padapter, u16 address, u8 *value)
+{
+ ret