aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio21
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-sps3028
-rw-r--r--Documentation/devicetree/bindings/iio/accel/mma8452.txt4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt65
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt41
-rw-r--r--Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt48
-rw-r--r--Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt (renamed from Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt)0
-rw-r--r--Documentation/devicetree/bindings/iio/adc/nuvoton,npcm-adc.txt24
-rw-r--r--Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti-ads124s08.txt25
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/bme680.txt11
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt20
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/sensirion,sgp30.txt15
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt12
-rw-r--r--Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt28
-rw-r--r--Documentation/devicetree/bindings/iio/impedance-analyzer/ad5933.txt26
-rw-r--r--Documentation/devicetree/bindings/iio/imu/bmi160.txt6
-rw-r--r--Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt1
-rw-r--r--Documentation/devicetree/bindings/iio/light/max44009.txt24
-rw-r--r--Documentation/devicetree/bindings/iio/st-sensors.txt1
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--MAINTAINERS28
-rw-r--r--drivers/iio/accel/adxl345_core.c4
-rw-r--r--drivers/iio/accel/mma8452.c105
-rw-r--r--drivers/iio/accel/st_accel_core.c171
-rw-r--r--drivers/iio/adc/Kconfig80
-rw-r--r--drivers/iio/adc/Makefile7
-rw-r--r--drivers/iio/adc/ad7476.c20
-rw-r--r--drivers/iio/adc/ad7606.c (renamed from drivers/staging/iio/adc/ad7606.c)272
-rw-r--r--drivers/iio/adc/ad7606.h (renamed from drivers/staging/iio/adc/ad7606.h)17
-rw-r--r--drivers/iio/adc/ad7606_par.c (renamed from drivers/staging/iio/adc/ad7606_par.c)46
-rw-r--r--drivers/iio/adc/ad7606_spi.c (renamed from drivers/staging/iio/adc/ad7606_spi.c)35
-rw-r--r--drivers/iio/adc/ad7768-1.c655
-rw-r--r--drivers/iio/adc/exynos_adc.c19
-rw-r--r--drivers/iio/adc/ingenic-adc.c364
-rw-r--r--drivers/iio/adc/lpc32xx_adc.c15
-rw-r--r--drivers/iio/adc/meson_saradc.c33
-rw-r--r--drivers/iio/adc/npcm_adc.c335
-rw-r--r--drivers/iio/adc/ti-ads124s08.c376
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c4
-rw-r--r--drivers/iio/chemical/Kconfig21
-rw-r--r--drivers/iio/chemical/Makefile3
-rw-r--r--drivers/iio/chemical/bme680_i2c.c7
-rw-r--r--drivers/iio/chemical/bme680_spi.c8
-rw-r--r--drivers/iio/chemical/pms7003.c340
-rw-r--r--drivers/iio/chemical/sgp30.c591
-rw-r--r--drivers/iio/chemical/sps30.c548
-rw-r--r--drivers/iio/dac/Kconfig16
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5686-spi.c9
-rw-r--r--drivers/iio/dac/ad5686.c44
-rw-r--r--drivers/iio/dac/ad5686.h4
-rw-r--r--drivers/iio/dac/ad5696-i2c.c2
-rw-r--r--drivers/iio/dac/ad5758.c2
-rw-r--r--drivers/iio/dac/ti-dac7612.c184
-rw-r--r--drivers/iio/frequency/ad9523.c7
-rw-r--r--drivers/iio/imu/bmi160/bmi160.h11
-rw-r--r--drivers/iio/imu/bmi160/bmi160_core.c317
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c5
-rw-r--r--drivers/iio/imu/bmi160/bmi160_spi.c4
-rw-r--r--drivers/iio/imu/inv_mpu6050/Kconfig8
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c31
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h8
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c12
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c2
-rw-r--r--drivers/iio/industrialio-core.c5
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/isl29018.c46
-rw-r--r--drivers/iio/light/max44009.c555
-rw-r--r--drivers/iio/magnetometer/mag3110.c94
-rw-r--r--drivers/iio/pressure/Kconfig2
-rw-r--r--drivers/iio/pressure/st_pressure.h2
-rw-r--r--drivers/iio/pressure/st_pressure_core.c69
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c5
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c5
-rw-r--r--drivers/staging/Kconfig6
-rw-r--r--drivers/staging/Makefile13
-rw-r--r--drivers/staging/android/ashmem.c70
-rw-r--r--drivers/staging/android/ion/Makefile2
-rw-r--r--drivers/staging/android/ion/ion-ioctl.c98
-rw-r--r--drivers/staging/android/ion/ion.c84
-rw-r--r--drivers/staging/android/ion/ion.h42
-rw-r--r--drivers/staging/android/ion/ion_carveout_heap.c19
-rw-r--r--drivers/staging/android/ion/ion_chunk_heap.c25
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c6
-rw-r--r--drivers/staging/android/ion/ion_heap.c8
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c2
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c10
-rw-r--r--drivers/staging/android/uapi/ion.h2
-rw-r--r--drivers/staging/android/vsoc.c1
-rw-r--r--drivers/staging/comedi/comedi_fops.c3
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c444
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c71
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.h4
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c2
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c31
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.h2
-rw-r--r--drivers/staging/erofs/Documentation/filesystems/erofs.txt208
-rw-r--r--drivers/staging/erofs/Makefile2
-rw-r--r--drivers/staging/erofs/data.c37
-rw-r--r--drivers/staging/erofs/dir.c12
-rw-r--r--drivers/staging/erofs/inode.c41
-rw-r--r--drivers/staging/erofs/internal.h147
-rw-r--r--drivers/staging/erofs/namei.c194
-rw-r--r--drivers/staging/erofs/super.c29
-rw-r--r--drivers/staging/erofs/unzip_vle.c165
-rw-r--r--drivers/staging/erofs/unzip_vle.h23
-rw-r--r--drivers/staging/erofs/unzip_vle_lz4.c21
-rw-r--r--drivers/staging/erofs/utils.c58
-rw-r--r--drivers/staging/erofs/xattr.c115
-rw-r--r--drivers/staging/erofs/xattr.h10
-rw-r--r--drivers/staging/fbtft/fb_agm1264k-fl.c52
-rw-r--r--drivers/staging/fbtft/fb_bd663474.c6
-rw-r--r--drivers/staging/fbtft/fb_ili9163.c6
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c2
-rw-r--r--drivers/staging/fbtft/fb_ili9325.c6
-rw-r--r--drivers/staging/fbtft/fb_ili9340.c2
-rw-r--r--drivers/staging/fbtft/fb_pcd8544.c4
-rw-r--r--drivers/staging/fbtft/fb_ra8875.c4
-rw-r--r--drivers/staging/fbtft/fb_s6d1121.c6
-rw-r--r--drivers/staging/fbtft/fb_sh1106.c2
-rw-r--r--drivers/staging/fbtft/fb_ssd1289.c6
-rw-r--r--drivers/staging/fbtft/fb_ssd1305.c4
-rw-r--r--drivers/staging/fbtft/fb_ssd1306.c4
-rw-r--r--drivers/staging/fbtft/fb_ssd1325.c6
-rw-r--r--drivers/staging/fbtft/fb_ssd1331.c10
-rw-r--r--drivers/staging/fbtft/fb_ssd1351.c4
-rw-r--r--drivers/staging/fbtft/fb_tinylcd.c2
-rw-r--r--drivers/staging/fbtft/fb_tls8204.c6
-rw-r--r--drivers/staging/fbtft/fb_uc1611.c4
-rw-r--r--drivers/staging/fbtft/fb_uc1701.c6
-rw-r--r--drivers/staging/fbtft/fb_upd161704.c6
-rw-r--r--drivers/staging/fbtft/fb_watterott.c4
-rw-r--r--drivers/staging/fbtft/fbtft-bus.c6
-rw-r--r--drivers/staging/fbtft/fbtft-core.c178
-rw-r--r--drivers/staging/fbtft/fbtft-io.c26
-rw-r--r--drivers/staging/fbtft/fbtft.h21
-rw-r--r--drivers/staging/fbtft/fbtft_device.c344
-rw-r--r--drivers/staging/fbtft/flexfb.c12
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h2
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/dpsw.h2
-rw-r--r--drivers/staging/fsl-dpaa2/ethsw/ethsw.h2
-rw-r--r--drivers/staging/fwserial/fwserial.c1
-rw-r--r--drivers/staging/gasket/gasket_interrupt.c1
-rw-r--r--drivers/staging/goldfish/goldfish_audio.c10
-rw-r--r--drivers/staging/greybus/Kconfig1
-rw-r--r--drivers/staging/greybus/TODO2
-rw-r--r--drivers/staging/greybus/arche-apb-ctrl.c152
-rw-r--r--drivers/staging/greybus/arche-platform.c124
-rw-r--r--drivers/staging/greybus/audio_topology.c1
-rw-r--r--drivers/staging/greybus/bundle.c2
-rw-r--r--drivers/staging/greybus/connection.h2
-rw-r--r--drivers/staging/greybus/control.c1
-rw-r--r--drivers/staging/greybus/core.c2
-rw-r--r--drivers/staging/greybus/gpio.c156
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.c12
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.h12
-rw-r--r--drivers/staging/gs_fpgaboot/io.c16
-rw-r--r--drivers/staging/gs_fpgaboot/io.h12
-rw-r--r--drivers/staging/iio/adc/Kconfig34
-rw-r--r--drivers/staging/iio/adc/Makefile4
-rw-r--r--drivers/staging/iio/adc/ad7280a.c243
-rw-r--r--drivers/staging/iio/adc/ad7816.c7
-rw-r--r--drivers/staging/iio/addac/adt7316-i2c.c6
-rw-r--r--drivers/staging/iio/addac/adt7316-spi.c4
-rw-r--r--drivers/staging/iio/addac/adt7316.c143
-rw-r--r--drivers/staging/iio/cdc/Kconfig10
-rw-r--r--drivers/staging/iio/cdc/Makefile1
-rw-r--r--drivers/staging/iio/cdc/ad7152.c552
-rw-r--r--drivers/staging/iio/frequency/ad9834.c54
-rw-r--r--drivers/staging/iio/frequency/ad9834.h28
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c57
-rw-r--r--drivers/staging/ks7010/Makefile2
-rw-r--r--drivers/staging/ks7010/TODO2
-rw-r--r--drivers/staging/ks7010/ks_hostif.c119
-rw-r--r--drivers/staging/ks7010/ks_wlan_net.c2
-rw-r--r--drivers/staging/ks7010/michael_mic.c127
-rw-r--r--drivers/staging/ks7010/michael_mic.h21
-rw-r--r--drivers/staging/media/davinci_vpfe/Makefile2
-rw-r--r--drivers/staging/most/Makefile2
-rw-r--r--drivers/staging/most/cdev/Makefile2
-rw-r--r--drivers/staging/most/cdev/cdev.c5
-rw-r--r--drivers/staging/most/dim2/Makefile2
-rw-r--r--drivers/staging/most/i2c/Makefile2
-rw-r--r--drivers/staging/most/net/Makefile2
-rw-r--r--drivers/staging/most/sound/Makefile2
-rw-r--r--drivers/staging/most/usb/Makefile2
-rw-r--r--drivers/staging/most/video/Makefile2
-rw-r--r--drivers/staging/mt7621-dma/Kconfig6
-rw-r--r--drivers/staging/mt7621-dma/Makefile1
-rw-r--r--drivers/staging/mt7621-dma/mtk-hsdma.c11
-rw-r--r--drivers/staging/mt7621-dts/gbpc1.dts4
-rw-r--r--drivers/staging/mt7621-dts/mt7621.dtsi59
-rw-r--r--drivers/staging/mt7621-eth/ethtool.c1
-rw-r--r--drivers/staging/mt7621-eth/ethtool.h11
-rw-r--r--drivers/staging/mt7621-mmc/Kconfig2
-rw-r--r--drivers/staging/mt7621-mmc/dbg.c1
-rw-r--r--drivers/staging/mt7621-mmc/mt6575_sd.h2
-rw-r--r--drivers/staging/mt7621-pci-phy/Kconfig7
-rw-r--r--drivers/staging/mt7621-pci-phy/Makefile1
-rw-r--r--drivers/staging/mt7621-pci-phy/TODO4
-rw-r--r--drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.txt54
-rw-r--r--drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c387
-rw-r--r--drivers/staging/mt7621-pci/Makefile2
-rw-r--r--drivers/staging/mt7621-pci/TODO8
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c300
-rw-r--r--drivers/staging/mt7621-pinctrl/Kconfig1
-rw-r--r--drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c49
-rw-r--r--drivers/staging/mt7621-spi/spi-mt7621.c72
-rw-r--r--drivers/staging/netlogic/Kconfig2
-rw-r--r--drivers/staging/netlogic/platform_net.c51
-rw-r--r--drivers/staging/netlogic/platform_net.h32
-rw-r--r--drivers/staging/netlogic/xlr_net.c31
-rw-r--r--drivers/staging/netlogic/xlr_net.h33
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.h2
-rw-r--r--drivers/staging/ralink-gdma/Kconfig6
-rw-r--r--drivers/staging/ralink-gdma/Makefile3
-rw-r--r--drivers/staging/ralink-gdma/ralink-gdma.c (renamed from drivers/staging/mt7621-dma/ralink-gdma.c)6
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c8
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c12
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c4
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c10
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ioctl_set.c12
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c44
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c38
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c18
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c11
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c67
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c4
-rw-r--r--drivers/staging/rtl8188eu/include/odm.h1
-rw-r--r--drivers/staging/rtl8188eu/include/odm_hwconfig.h9
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h12
-rw-r--r--drivers/staging/rtl8188eu/include/wlan_bssdef.h6
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c34
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c72
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c26
-rw-r--r--drivers/staging/rtl8188eu/os_dep/rtw_android.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c6
-rw-r--r--drivers/staging/rtl8192e/dot11d.c120
-rw-r--r--drivers/staging/rtl8192e/dot11d.h77
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c23
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c8
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c6
-rw-r--r--drivers/staging/rtl8192e/rtllib.h6
-rw-r--r--drivers/staging/rtl8192e/rtllib_crypt_tkip.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c22
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c4
-rw-r--r--drivers/staging/rtl8192u/Makefile2
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c24
-rw-r--r--drivers/staging/rtl8712/ieee80211.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c8
-rw-r--r--drivers/staging/rtl8712/usb_intf.c16
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c8
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_xmit.c2
-rw-r--r--drivers/staging/rtl8723bs/include/drv_types.h1
-rw-r--r--drivers/staging/rtlwifi/Kconfig2
-rw-r--r--drivers/staging/rtlwifi/efuse.c6
-rw-r--r--drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c5
-rw-r--r--drivers/staging/rtlwifi/pci.h3
-rw-r--r--drivers/staging/rtlwifi/phydm/phydm_rainfo.c2
-rw-r--r--drivers/staging/rtlwifi/rtl8822be/fw.c2
-rw-r--r--drivers/staging/rts5208/ms.c5
-rw-r--r--drivers/staging/rts5208/sd.c7
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c6
-rw-r--r--drivers/staging/speakup/Kconfig32
-rw-r--r--drivers/staging/speakup/kobjects.c2
-rw-r--r--drivers/staging/speakup/main.c14
-rw-r--r--drivers/staging/speakup/speakup_decext.c3
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c3
-rw-r--r--drivers/staging/speakup/speakup_soft.c4
-rw-r--r--drivers/staging/speakup/spk_priv_keyinfo.h9
-rw-r--r--drivers/staging/speakup/spk_ttyio.c20
-rw-r--r--drivers/staging/speakup/varhandlers.c4
-rw-r--r--drivers/staging/unisys/visorhba/Makefile3
-rw-r--r--drivers/staging/unisys/visornic/Makefile3
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c4
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/Makefile3
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/Makefile2
-rw-r--r--drivers/staging/vt6655/baseband.c10
-rw-r--r--drivers/staging/vt6655/baseband.h2
-rw-r--r--drivers/staging/vt6655/card.c16
-rw-r--r--drivers/staging/vt6655/card.h2
-rw-r--r--drivers/staging/vt6655/device_main.c4
-rw-r--r--drivers/staging/vt6656/key.c4
-rw-r--r--drivers/staging/vt6656/mac.h2
-rw-r--r--drivers/staging/wilc1000/Makefile2
-rw-r--r--drivers/staging/wilc1000/host_interface.c1164
-rw-r--r--drivers/staging/wilc1000/host_interface.h165
-rw-r--r--drivers/staging/wilc1000/wilc_mon.c (renamed from drivers/staging/wilc1000/linux_mon.c)77
-rw-r--r--drivers/staging/wilc1000/wilc_netdev.c (renamed from drivers/staging/wilc1000/linux_wlan.c)430
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c187
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c4
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c644
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h7
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h14
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c52
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h38
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c39
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h40
-rw-r--r--drivers/staging/wlan-ng/Kconfig2
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c3
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c5
-rw-r--r--drivers/staging/xgifb/Kconfig11
-rw-r--r--drivers/staging/xgifb/Makefile4
-rw-r--r--drivers/staging/xgifb/TODO13
-rw-r--r--drivers/staging/xgifb/XGI_main.h365
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c2084
-rw-r--r--drivers/staging/xgifb/XGIfb.h109
-rw-r--r--drivers/staging/xgifb/vb_def.h257
-rw-r--r--drivers/staging/xgifb/vb_init.c1367
-rw-r--r--drivers/staging/xgifb/vb_init.h6
-rw-r--r--drivers/staging/xgifb/vb_setmode.c5528
-rw-r--r--drivers/staging/xgifb/vb_setmode.h24
-rw-r--r--drivers/staging/xgifb/vb_struct.h165
-rw-r--r--drivers/staging/xgifb/vb_table.h2513
-rw-r--r--drivers/staging/xgifb/vb_util.h46
-rw-r--r--drivers/staging/xgifb/vgatypes.h51
-rw-r--r--include/dt-bindings/iio/adc/ingenic,adc.h10
-rw-r--r--include/linux/iio/common/st_sensors.h1
-rw-r--r--include/uapi/linux/iio/types.h7
-rw-r--r--tools/iio/iio_event_monitor.c14
335 files changed, 9603 insertions, 18624 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 8127a08e366d..864f8efd12e5 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1554,6 +1554,10 @@ What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
KernelVersion: 4.3
@@ -1684,4 +1688,19 @@ KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled) phase difference reading from channel Y
- that can be processed to radians. \ No newline at end of file
+ that can be processed to radians.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm1_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm1_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm2p5_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm2p5_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm4_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm4_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm10_input
+What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm10_input
+KernelVersion: 4.22
+Contact: linux-iio@vger.kernel.org
+Description:
+ Mass concentration reading of particulate matter in ug / m3.
+ pmX consists of particles with aerodynamic diameter less or
+ equal to X micrometers.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-sps30 b/Documentation/ABI/testing/sysfs-bus-iio-sps30
new file mode 100644
index 000000000000..143df8e89d08
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-sps30
@@ -0,0 +1,28 @@
+What: /sys/bus/iio/devices/iio:deviceX/start_cleaning
+Date: December 2018
+KernelVersion: 4.22
+Contact: linux-iio@vger.kernel.org
+Description:
+ Writing 1 starts sensor self cleaning. Internal fan accelerates
+ to its maximum speed and keeps spinning for about 10 seconds in
+ order to blow out accumulated dust.
+
+What: /sys/bus/iio/devices/iio:deviceX/cleaning_period
+Date: January 2019
+KernelVersion: 5.1
+Contact: linux-iio@vger.kernel.org
+Description:
+ Sensor is capable of triggering self cleaning periodically.
+ Period can be changed by writing a new value here. Upon reading
+ the current one is returned. Units are seconds.
+
+ Writing 0 disables periodical self cleaning entirely.
+
+What: /sys/bus/iio/devices/iio:deviceX/cleaning_period_available
+Date: January 2019
+KernelVersion: 5.1
+Contact: linux-iio@vger.kernel.org
+Description:
+ The range of available values in seconds represented as the
+ minimum value, the step and the maximum value, all enclosed in
+ square brackets.
diff --git a/Documentation/devicetree/bindings/iio/accel/mma8452.txt b/Documentation/devicetree/bindings/iio/accel/mma8452.txt
index 2100e9af379c..e132394375a1 100644
--- a/Documentation/devicetree/bindings/iio/accel/mma8452.txt
+++ b/Documentation/devicetree/bindings/iio/accel/mma8452.txt
@@ -20,6 +20,10 @@ Optional properties:
- interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's
interrupt line in use.
+ - vdd-supply: phandle to the regulator that provides vdd power to the accelerometer.
+
+ - vddio-supply: phandle to the regulator that provides vddio power to the accelerometer.
+
Example:
mma8453fc@1d {
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt
new file mode 100644
index 000000000000..d7b6241ca881
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt
@@ -0,0 +1,65 @@
+Analog Devices AD7606 Simultaneous Sampling ADC
+
+Required properties for the AD7606:
+
+- compatible: Must be one of
+ * "adi,ad7605-4"
+ * "adi,ad7606-8"
+ * "adi,ad7606-6"
+ * "adi,ad7606-4"
+- reg: SPI chip select number for the device
+- spi-max-frequency: Max SPI frequency to use
+ see: Documentation/devicetree/bindings/spi/spi-bus.txt
+- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt
+- avcc-supply: phandle to the Avcc power supply
+- interrupts: IRQ line for the ADC
+ see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin.
+ This logic input is used to initiate conversions on the analog
+ input channels. As the line is active high, it should be marked
+ GPIO_ACTIVE_HIGH.
+
+Optional properties:
+
+- reset-gpios: must be the device tree identifier of the RESET pin. If specified,
+ it will be asserted during driver probe. As the line is active high,
+ it should be marked GPIO_ACTIVE_HIGH.
+- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used
+ to place the AD7606 into one of two power-down modes, Standby mode or
+ Shutdown mode. As the line is active low, it should be marked
+ GPIO_ACTIVE_LOW.
+- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin.
+ The FRSTDATA output indicates when the first channel, V1, is
+ being read back on either the parallel, byte or serial interface.
+ As the line is active high, it should be marked GPIO_ACTIVE_HIGH.
+- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on
+ this pin determines the input range of the analog input channels. If
+ this pin is tied to a logic high, the analog input range is ±10V for
+ all channels. If this pin is tied to a logic low, the analog input range
+ is ±5V for all channels. As the line is active high, it should be marked
+ GPIO_ACTIVE_HIGH.
+- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling
+ mode pins. As the line is active high, it should be marked
+ GPIO_ACTIVE_HIGH.
+
+Example:
+
+ adc@0 {
+ compatible = "adi,ad7606-8";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ spi-cpol;
+
+ avcc-supply = <&adc_vref>;
+
+ interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpio>;
+
+ adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
+ adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
+ adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH
+ &gpio 23 GPIO_ACTIVE_HIGH
+ &gpio 26 GPIO_ACTIVE_HIGH>;
+ standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
new file mode 100644
index 000000000000..9f5b88cf680d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
@@ -0,0 +1,41 @@
+Analog Devices AD7768-1 ADC device driver
+
+Required properties for the AD7768-1:
+
+- compatible: Must be "adi,ad7768-1"
+- reg: SPI chip select number for the device
+- spi-max-frequency: Max SPI frequency to use
+ see: Documentation/devicetree/bindings/spi/spi-bus.txt
+- clocks: phandle to the master clock (mclk)
+ see: Documentation/devicetree/bindings/clock/clock-bindings.txt
+- clock-names: Must be "mclk".
+- interrupts: IRQ line for the ADC
+ see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+- vref-supply: vref supply can be used as reference for conversion
+- adi,sync-in-gpios: must be the device tree identifier of the SYNC-IN pin. Enables
+ synchronization of multiple devices that require simultaneous sampling.
+ A pulse is always required if the configuration is changed in any way, for example
+ if the filter decimation rate changes. As the line is active low, it should
+ be marked GPIO_ACTIVE_LOW.
+
+Optional properties:
+
+ - reset-gpios : GPIO spec for the RESET pin. If specified, it will be asserted during
+ driver probe. As the line is active low, it should be marked GPIO_ACTIVE_LOW.
+
+Example:
+
+ adc@0 {
+ compatible = "adi,ad7768-1";
+ reg = <0>;
+ spi-max-frequency = <2000000>;
+ spi-cpol;
+ spi-cpha;
+ vref-supply = <&adc_vref>;
+ interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+ interrupt-parent = <&gpio>;
+ adi,sync-in-gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
+ clocks = <&ad7768_mclk>;
+ clock-names = "mclk";
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
index 325090e43ce6..75c775954102 100644
--- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
@@ -23,6 +23,10 @@ Required properties:
- #io-channel-cells: must be 1, see ../iio-bindings.txt
Optional properties:
+- amlogic,hhi-sysctrl: phandle to the syscon which contains the 5th bit
+ of the TSC (temperature sensor coefficient) on
+ Meson8b and Meson8m2 (which used to calibrate the
+ temperature sensor)
- nvmem-cells: phandle to the temperature_calib eFuse cells
- nvmem-cell-names: if present (to enable the temperature sensor
calibration) this must contain "temperature_calib"
diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
new file mode 100644
index 000000000000..f01159f20d87
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
@@ -0,0 +1,48 @@
+* Ingenic JZ47xx ADC controller IIO bindings
+
+Required properties:
+
+- compatible: Should be one of:
+ * ingenic,jz4725b-adc
+ * ingenic,jz4740-adc
+- reg: ADC controller registers location and length.
+- clocks: phandle to the SoC's ADC clock.
+- clock-names: Must be set to "adc".
+- #io-channel-cells: Must be set to <1> to indicate channels are selected
+ by index.
+
+ADC clients must use the format described in iio-bindings.txt, giving
+a phandle and IIO specifier pair ("io-channels") to the ADC controller.
+
+Example:
+
+#include <dt-bindings/iio/adc/ingenic,adc.h>
+
+adc: adc@10070000 {
+ compatible = "ingenic,jz4740-adc";
+ #io-channel-cells = <1>;
+
+ reg = <0x10070000 0x30>;
+
+ clocks = <&cgu JZ4740_CLK_ADC>;
+ clock-names = "adc";
+
+ interrupt-parent = <&intc>;
+ interrupts = <18>;
+};
+
+adc-keys {
+ ...
+ compatible = "adc-keys";
+ io-channels = <&adc INGENIC_ADC_AUX>;
+ io-channel-names = "buttons";
+ ...
+};
+
+battery {
+ ...
+ compatible = "ingenic,jz4740-battery";
+ io-channels = <&adc INGENIC_ADC_BATTERY>;
+ io-channel-names = "battery";
+ ...
+};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt b/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt
index b3629d3a9adf..b3629d3a9adf 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/lpc32xx-adc.txt
diff --git a/Documentation/devicetree/bindings/iio/adc/nuvoton,npcm-adc.txt b/Documentation/devicetree/bindings/iio/adc/nuvoton,npcm-adc.txt
new file mode 100644
index 000000000000..eb939fe77836
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/nuvoton,npcm-adc.txt
@@ -0,0 +1,24 @@
+Nuvoton NPCM Analog to Digital Converter (ADC)
+
+The NPCM ADC is a 10-bit converter for eight channel inputs.
+
+Required properties:
+- compatible: "nuvoton,npcm750-adc" for the NPCM7XX BMC.
+- reg: specifies physical base address and size of the registers.
+- interrupts: Contain the ADC interrupt with flags for falling edge.
+
+Optional properties:
+- clocks: phandle of ADC reference clock, in case the clock is not
+ added the ADC will use the default ADC sample rate.
+- vref-supply: The regulator supply ADC reference voltage, in case the
+ vref-supply is not added the ADC will use internal voltage
+ reference.
+
+Example:
+
+adc: adc@f000c000 {
+ compatible = "nuvoton,npcm750-adc";
+ reg = <0xf000c000 0x8>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_ADC>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt
index a10c1f89037d..e1fe02f3e3e9 100644
--- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt
@@ -11,11 +11,13 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
- for exynos4412/5250 controllers.
+ for Exynos5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
+ Must be "samsung,exynos4212-adc" for
+ controllers compatible with ADC of Exynos4212 and Exynos4412.
Must be "samsung,exynos7-adc" for
the ADC in Exynos7 and compatibles
Must be "samsung,s3c2410-adc" for
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-ads124s08.txt b/Documentation/devicetree/bindings/iio/adc/ti-ads124s08.txt
new file mode 100644
index 000000000000..ecf807bb32f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti-ads124s08.txt
@@ -0,0 +1,25 @@
+* Texas Instruments' ads124s08 and ads124s06 ADC chip
+
+Required properties:
+ - compatible :
+ "ti,ads124s08"
+ "ti,ads124s06"
+ - reg : spi chip select number for the device
+
+Recommended properties:
+ - spi-max-frequency : Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+ - spi-cpha : Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+ - reset-gpios : GPIO pin used to reset the device.
+
+Example:
+adc@0 {
+ compatible = "ti,ads124s08";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ spi-cpha;
+ reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
+};
diff --git a/Documentation/devicetree/bindings/iio/chemical/bme680.txt b/Documentation/devicetree/bindings/iio/chemical/bme680.txt
new file mode 100644
index 000000000000..7f3827cfb2ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/bme680.txt
@@ -0,0 +1,11 @@
+Bosch Sensortec BME680 pressure/temperature/humidity/voc sensors
+
+Required properties:
+- compatible: must be "bosch,bme680"
+
+Example:
+
+bme680@76 {
+ compatible = "bosch,bme680";
+ reg = <0x76>;
+};
diff --git a/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
new file mode 100644
index 000000000000..7b5f06f324c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.txt
@@ -0,0 +1,20 @@
+* Plantower PMS7003 particulate matter sensor
+
+Required properties:
+- compatible: must be "plantower,pms7003"
+- vcc-supply: phandle to the regulator that provides power to the sensor
+
+Optional properties:
+- plantower,set-gpios: phandle to the GPIO connected to the SET line
+- reset-gpios: phandle to the GPIO connected to the RESET line
+
+Refer to serial/slave-device.txt for generic serial attached device bindings.
+
+Example:
+
+&uart0 {
+ air-pollution-sensor {
+ compatible = "plantower,pms7003";
+ vcc-supply = <&reg_vcc5v0>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,sgp30.txt b/Documentation/devicetree/bindings/iio/chemical/sensirion,sgp30.txt
new file mode 100644
index 000000000000..5844ed58173c
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,sgp30.txt
@@ -0,0 +1,15 @@
+* Sensirion SGP30/SGPC3 multi-pixel Gas Sensor
+
+Required properties:
+
+ - compatible: must be one of
+ "sensirion,sgp30"
+ "sensirion,sgpc3"
+ - reg: the I2C address of the sensor
+
+Example:
+
+gas@58 {
+ compatible = "sensirion,sgp30";
+ reg = <0x58>;
+};
diff --git a/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt
new file mode 100644
index 000000000000..6eee2709b5b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.txt
@@ -0,0 +1,12 @@
+* Sensirion SPS30 particulate matter sensor
+
+Required properties:
+- compatible: must be "sensirion,sps30"
+- reg: the I2C address of the sensor
+
+Example:
+
+sps30@69 {
+ compatible = "sensirion,sps30";
+ reg = <0x69>;
+};
diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt b/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
new file mode 100644
index 000000000000..639c94ed83e9
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
@@ -0,0 +1,28 @@
+* Texas Instruments Dual, 12-Bit Serial Input Digital-to-Analog Converter
+
+The DAC7612 is a dual, 12-bit digital-to-analog converter (DAC) with guaranteed
+12-bit monotonicity performance over the industrial temperature range.
+Is is programmable through an SPI interface.
+
+The internal DACs are loaded when the LOADDACS pin is pulled down.
+
+http://www.ti.com/lit/ds/sbas106/sbas106.pdf
+
+Required Properties:
+- compatible: Should be one of:
+ "ti,dac7612"
+ "ti,dac7612u"
+ "ti,dac7612ub"
+- reg: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional Properties:
+- ti,loaddacs-gpios: GPIO descriptor for the LOADDACS pin.
+- spi-*: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+ dac@1 {
+ compatible = "ti,dac7612";
+ reg = <0x1>;
+ ti,loaddacs-gpios = <&msmgpio 25 GPIO_ACTIVE_LOW>;
+ };
diff --git a/Documentation/devicetree/bindings/iio/impedance-analyzer/ad5933.txt b/Documentation/devicetree/bindings/iio/impedance-analyzer/ad5933.txt
new file mode 100644
index 000000000000..5ff38728ff91
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/impedance-analyzer/ad5933.txt
@@ -0,0 +1,26 @@
+Analog Devices AD5933/AD5934 Impedance Converter, Network Analyzer
+
+https://www.analog.com/media/en/technical-documentation/data-sheets/AD5933.pdf
+https://www.analog.com/media/en/technical-documentation/data-sheets/AD5934.pdf
+
+Required properties:
+ - compatible : should be one of
+ "adi,ad5933"
+ "adi,ad5934"
+ - reg : the I2C address.
+ - vdd-supply : The regulator supply for DVDD, AVDD1 and AVDD2 when they
+ are connected together.
+
+Optional properties:
+- clocks : external clock reference.
+- clock-names : must be "mclk" if clocks is set.
+
+Example for a I2C device node:
+
+ impedance-analyzer@0d {
+ compatible = "adi,adxl345";
+ reg = <0x0d>;
+ vdd-supply = <&vdd_supply>;
+ clocks = <&ref_clk>;
+ clock-names = "mclk";
+ };
diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
index 0c1c105fb503..900c169de00f 100644
--- a/Documentation/devicetree/bindings/iio/imu/bmi160.txt
+++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt
@@ -9,9 +9,11 @@ Required properties:
- spi-max-frequency : set maximum clock frequency (only for SPI)
Optional properties:
- - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW
+ - interrupts : interrupt mapping for IRQ
- interrupt-names : set to "INT1" if INT1 pin should be used as interrupt
input, set to "INT2" if INT2 pin should be used instead
+ - drive-open-drain : set if the specified interrupt pin should be configured as
+ open drain. If not set, defaults to push-pull.
Examples:
@@ -20,7 +22,7 @@ bmi160@68 {
reg = <0x68>;
interrupt-parent = <&gpio4>;
- interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+ interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
index 6ab9a9d196b0..268bf7568e19 100644
--- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
+++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
@@ -11,6 +11,7 @@ Required properties:
"invensense,mpu9250"
"invensense,mpu9255"
"invensense,icm20608"
+ "invensense,icm20602"
- reg : the I2C address of the sensor
- interrupts: interrupt mapping for IRQ. It should be configured with flags
IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
diff --git a/Documentation/devicetree/bindings/iio/light/max44009.txt b/Documentation/devicetree/bindings/iio/light/max44009.txt
new file mode 100644
index 000000000000..4a98848e35c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/max44009.txt
@@ -0,0 +1,24 @@
+* MAX44009 Ambient Light Sensor
+
+Required properties:
+
+- compatible: should be "maxim,max44009"
+- reg: the I2C address of the device (default is <0x4a>)
+
+Optional properties:
+
+- interrupts: interrupt mapping for GPIO IRQ. Should be configured with
+ IRQ_TYPE_EDGE_FALLING.
+
+Refer to interrupt-controller/interrupts.txt for generic interrupt client
+node bindings.
+
+Example:
+
+light-sensor@4a {
+ compatible = "maxim,max44009";
+ reg = <0x4a>;
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
+};
diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt
index ddcb95509599..52ee4baec6f0 100644
--- a/Documentation/devicetree/bindings/iio/st-sensors.txt
+++ b/Documentation/devicetree/bindings/iio/st-sensors.txt
@@ -77,3 +77,4 @@ Pressure sensors:
- st,lps22hb-press
- st,lps33hw
- st,lps35hw
+- st,lps22hh
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 542bbf304f13..e604e7f73629 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -310,6 +310,7 @@ phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
pine64 Pine64
pixcir PIXCIR MICROELECTRONICS Co., Ltd
+plantower Plantower Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
plx Broadcom Corporation (formerly PLX Technology)
diff --git a/MAINTAINERS b/MAINTAINERS
index 108f3b1b7a79..060f4ff8da58 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -854,6 +854,22 @@ S: Supported
F: drivers/iio/adc/ad7124.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
+ANALOG DEVICES INC AD7606 DRIVER
+M: Stefan Popa <stefan.popa@analog.com>
+L: linux-iio@vger.kernel.org
+W: http://ez.analog.com/community/linux-device-drivers
+S: Supported
+F: drivers/iio/adc/ad7606.c
+F: Documentation/devicetree/bindings/iio/adc/ad7606.txt
+
+ANALOG DEVICES INC AD7768-1 DRIVER
+M: Stefan Popa <stefan.popa@analog.com>
+L: linux-iio@vger.kernel.org
+W: http://ez.analog.com/community/linux-device-drivers
+S: Supported
+F: drivers/iio/adc/ad7768-1.c
+F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
+
ANALOG DEVICES INC AD9389B DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
@@ -14619,11 +14635,6 @@ L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/staging/wilc1000/
-STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER
-M: Arnaud Patard <arnaud.patard@rtp-net.org>
-S: Odd Fixes
-F: drivers/staging/xgifb/
-
STAGING SUBSYSTEM
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
@@ -15218,6 +15229,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/ti/
+Texas Instruments' DAC7612 DAC Driver
+M: Ricardo Ribalda <ricardo@ribalda.com>
+L: linux-iio@vger.kernel.org
+S: Supported
+F: drivers/iio/dac/ti-dac7612.c
+F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
+
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 780f87f72338..f03ed00685ea 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -150,8 +150,8 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
}
static int adxl345_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
s64 n;
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 421a0a8a1379..302781126bc6 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -31,6 +31,7 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@@ -107,6 +108,8 @@ struct mma8452_data {
u8 data_cfg;
const struct mma_chip_info *chip_info;
int sleep_val;
+ struct regulator *vdd_reg;
+ struct regulator *vddio_reg;
};
/**
@@ -1534,9 +1537,39 @@ static int mma8452_probe(struct i2c_client *client,
mutex_init(&data->lock);
data->chip_info = match->data;
+ data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(data->vdd_reg)) {
+ if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_err(&client->dev, "failed to get VDD regulator!\n");
+ return PTR_ERR(data->vdd_reg);
+ }
+
+ data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
+ if (IS_ERR(data->vddio_reg)) {
+ if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_err(&client->dev, "failed to get VDDIO regulator!\n");
+ return PTR_ERR(data->vddio_reg);
+ }
+
+ ret = regulator_enable(data->vdd_reg);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable VDD regulator!\n");
+ return ret;
+ }
+
+ ret = regulator_enable(data->vddio_reg);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable VDDIO regulator!\n");
+ goto disable_regulator_vdd;
+ }
+
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
if (ret < 0)
- return ret;
+ goto disable_regulators;
switch (ret) {
case MMA8451_DEVICE_ID:
@@ -1549,7 +1582,8 @@ static int mma8452_probe(struct i2c_client *client,
break;
/* else: fall through */
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto disable_regulators;
}
dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
@@ -1566,13 +1600,13 @@ static int mma8452_probe(struct i2c_client *client,
ret = mma8452_reset(client);
if (ret < 0)
- return ret;
+ goto disable_regulators;
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
data->data_cfg);
if (ret < 0)
- return ret;
+ goto disable_regulators;
/*
* By default set transient threshold to max to avoid events if
@@ -1581,7 +1615,7 @@ static int mma8452_probe(struct i2c_client *client,
ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
MMA8452_TRANSIENT_THS_MASK);
if (ret < 0)
- return ret;
+ goto disable_regulators;
if (client->irq) {
int irq2;
@@ -1595,7 +1629,7 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_CTRL_REG5,
data->chip_info->all_events);
if (ret < 0)
- return ret;
+ goto disable_regulators;
dev_dbg(&client->dev, "using interrupt line INT1\n");
}
@@ -1604,11 +1638,11 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_CTRL_REG4,
data->chip_info->enabled_events);
if (ret < 0)
- return ret;
+ goto disable_regulators;
ret = mma8452_trigger_setup(indio_dev);
if (ret < 0)
- return ret;
+ goto disable_regulators;
}
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
@@ -1661,12 +1695,19 @@ buffer_cleanup:
trigger_cleanup:
mma8452_trigger_cleanup(indio_dev);
+disable_regulators:
+ regulator_disable(data->vddio_reg);
+
+disable_regulator_vdd:
+ regulator_disable(data->vdd_reg);
+
return ret;
}
static int mma8452_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mma8452_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
@@ -1678,6 +1719,9 @@ static int mma8452_remove(struct i2c_client *client)
mma8452_trigger_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
+ regulator_disable(data->vddio_reg);
+ regulator_disable(data->vdd_reg);
+
return 0;
}
@@ -1696,6 +1740,18 @@ static int mma8452_runtime_suspend(struct device *dev)
return -EAGAIN;
}
+ ret = regulator_disable(data->vddio_reg);
+ if (ret) {
+ dev_err(dev, "failed to disable VDDIO regulator\n");
+ return ret;
+ }
+
+ ret = regulator_disable(data->vdd_reg);
+ if (ret) {
+ dev_err(dev, "failed to disable VDD regulator\n");
+ return ret;
+ }
+
return 0;
}
@@ -1705,9 +1761,22 @@ static int mma8452_runtime_resume(struct device *dev)
struct mma8452_data *data = iio_priv(indio_dev);
int ret, sleep_val;
+ ret = regulator_enable(data->vdd_reg);
+ if (ret) {
+ dev_err(dev, "failed to enable VDD regulator\n");
+ return ret;
+ }
+
+ ret = regulator_enable(data->vddio_reg);
+ if (ret) {
+ dev_err(dev, "failed to enable VDDIO regulator\n");
+ regulator_disable(data->vdd_reg);
+ return ret;
+ }
+
ret = mma8452_active(data);
if (ret < 0)
- return ret;
+ goto runtime_resume_failed;
ret = mma8452_get_odr_index(data);
sleep_val = 1000 / mma8452_samp_freq[ret][0];
@@ -1717,25 +1786,17 @@ static int mma8452_runtime_resume(struct device *dev)
msleep_interruptible(sleep_val);
return 0;
-}
-#endif
-#ifdef CONFIG_PM_SLEEP
-static int mma8452_suspend(struct device *dev)
-{
- return mma8452_standby(iio_priv(i2c_get_clientdata(
- to_i2c_client(dev))));
-}
+runtime_resume_failed:
+ regulator_disable(data->vddio_reg);
+ regulator_disable(data->vdd_reg);
-static int mma8452_resume(struct device *dev)
-{
- return mma8452_active(iio_priv(i2c_get_clientdata(
- to_i2c_client(dev))));
+ return ret;
}
#endif
static const struct dev_pm_ops mma8452_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
mma8452_runtime_resume, NULL)
};
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index f7b471121508..a3c0916479fa 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
@@ -918,12 +919,167 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#define ST_ACCEL_TRIGGER_OPS NULL
#endif
+static const struct iio_mount_matrix *
+get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+
+ return adata->mount_matrix;
+}
+
+static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix),
+ { },
+};
+
+/* Read ST-specific _ONT orientation data from ACPI and generate an
+ * appropriate mount matrix.
+ */
+static int apply_acpi_orientation(struct iio_dev *indio_dev,
+ struct iio_chan_spec *channels)
+{
+#ifdef CONFIG_ACPI
+ struct st_sensor_data *adata = iio_priv(indio_dev);
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_device *adev;
+ union acpi_object *ont;
+ union acpi_object *elements;
+ acpi_status status;
+ int ret = -EINVAL;
+ unsigned int val;
+ int i, j;
+ int final_ont[3][3] = { { 0 }, };
+
+ /* For some reason, ST's _ONT translation does not apply directly
+ * to the data read from the sensor. Another translation must be
+ * performed first, as described by the matrix below. Perhaps
+ * ST required this specific translation for the first product
+ * where the device was mounted?
+ */
+ const int default_ont[3][3] = {
+ { 0, 1, 0 },
+ { -1, 0, 0 },
+ { 0, 0, -1 },
+ };
+
+
+ adev = ACPI_COMPANION(adata->dev);
+ if (!adev)
+ return 0;
+
+ /* Read _ONT data, which should be a package of 6 integers. */
+ status = acpi_evaluate_object(adev->handle, "_ONT", NULL, &buffer);
+ if (status == AE_NOT_FOUND) {
+ return 0;
+ } else if (ACPI_FAILURE(status)) {
+ dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n",
+ status);
+ return status;
+ }
+
+ ont = buffer.pointer;
+ if (ont->type != ACPI_TYPE_PACKAGE || ont->package.count != 6)
+ goto out;
+
+ /* The first 3 integers provide axis order information.
+ * e.g. 0 1 2 would indicate normal X,Y,Z ordering.
+ * e.g. 1 0 2 indicates that data arrives in order Y,X,Z.
+ */
+ elements = ont->package.elements;
+ for (i = 0; i < 3; i++) {
+ if (elements[i].type != ACPI_TYPE_INTEGER)
+ goto out;
+
+ val = elements[i].integer.value;
+ if (val < 0 || val > 2)
+ goto out;
+
+ /* Avoiding full matrix multiplication, we simply reorder the
+ * columns in the default_ont matrix according to the
+ * ordering provided by _ONT.
+ */
+ final_ont[0][i] = default_ont[0][val];
+ final_ont[1][i] = default_ont[1][val];
+ final_ont[2][i] = default_ont[2][val];
+ }
+
+ /* The final 3 integers provide sign flip information.
+ * 0 means no change, 1 means flip.
+ * e.g. 0 0 1 means that Z data should be sign-flipped.
+ * This is applied after the axis reordering from above.
+ */
+ elements += 3;
+ for (i = 0; i < 3; i++) {
+ if (elements[i].type != ACPI_TYPE_INTEGER)
+ goto out;
+
+ val = elements[i].integer.value;
+ if (val != 0 && val != 1)
+ goto out;
+ if (!val)
+ continue;
+
+ /* Flip the values in the indicated column */
+ final_ont[0][i] *= -1;
+ final_ont[1][i] *= -1;
+ final_ont[2][i] *= -1;
+ }
+
+ /* Convert our integer matrix to a string-based iio_mount_matrix */
+ adata->mount_matrix = devm_kmalloc(&indio_dev->dev,
+ sizeof(*adata->mount_matrix),
+ GFP_KERNEL);
+ if (!adata->mount_matrix) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ int matrix_val = final_ont[i][j];
+ char *str_value;
+
+ switch (matrix_val) {
+ case -1:
+ str_value = "-1";
+ break;
+ case 0:
+ str_value = "0";
+ break;
+ case 1:
+ str_value = "1";
+ break;
+ default:
+ goto out;
+ }
+ adata->mount_matrix->rotation[i * 3 + j] = str_value;
+ }
+ }
+
+ /* Expose the mount matrix via ext_info */
+ for (i = 0; i < indio_dev->num_channels; i++)
+ channels[i].ext_info = mount_matrix_ext_info;
+
+ ret = 0;
+ dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
+
+out:
+ kfree(buffer.pointer);
+ return ret;
+#else /* !CONFIG_ACPI */
+ return 0;
+#endif
+}
+
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev);
+ struct iio_chan_spec *channels;
+ size_t channels_size;
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -942,9 +1098,22 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor_settings->multi_read_bit;
- indio_dev->channels = adata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
+ channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
+ channels = devm_kmemdup(&indio_dev->dev,
+ adata->sensor_settings->ch,
+ channels_size, GFP_KERNEL);
+ if (!channels) {
+ err = -ENOMEM;
+ goto st_accel_power_off;
+ }
+
+ if (apply_acpi_orientation(indio_dev, channels))
+ dev_warn(&indio_dev->dev,
+ "failed to apply ACPI orientation data: %d\n", err);
+
+ indio_dev->channels = channels;
adata->current_fullscale = (struct st_sensor_fullscale_avl *)
&adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 7a3ca4ec0cb7..5debc67df70a 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -57,18 +57,48 @@ config AD7298
module will be called ad7298.
config AD7476
- tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
+ tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD an TI"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
- AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
- AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
+ Say yes here to build support for the following SPI analog to
+ digital converters (ADCs):
+ Analog Devices: AD7273, AD7274, AD7276, AD7277, AD7278, AD7475,
+ AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495, AD7910,
+ AD7920.
+ Texas Instruments: ADS7866, ADS7867, ADS7868.
To compile this driver as a module, choose M here: the
module will be called ad7476.
+config AD7606
+ tristate
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+
+config AD7606_IFACE_PARALLEL
+ tristate "Analog Devices AD7606 ADC driver with parallel interface support"
+ depends on HAS_IOMEM
+ select AD7606
+ help
+ Say yes here to build parallel interface support for Analog Devices:
+ ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7606_parallel.
+
+config AD7606_IFACE_SPI
+ tristate "Analog Devices AD7606 ADC driver with spi interface support"
+ depends on SPI
+ select AD7606
+ help
+ Say yes here to build spi interface support for Analog Devices:
+ ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7606_spi.
+
config AD7766
tristate "Analog Devices AD7766/AD7767 ADC driver"
depends on SPI_MASTER
@@ -81,6 +111,19 @@ config AD7766
To compile this driver as a module, choose M here: the module will be
called ad7766.
+config AD7768_1
+ tristate "Analog Devices AD7768-1 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices AD7768-1 SPI
+ simultaneously sampling sigma-delta analog to digital converter (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7768-1.
+
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
@@ -367,6 +410,15 @@ config INA2XX_ADC
Say yes here to build support for TI INA2xx family of Power Monitors.
This driver is mutually exclusive with the HWMON version.
+config INGENIC_ADC
+ tristate "Ingenic JZ47xx SoCs ADC driver"
+ depends on MIPS || COMPILE_TEST
+ help
+ Say yes here to build support for the Ingenic JZ47xx SoCs ADC unit.
+
+ This driver can also be built as a module. If so, the module will be
+ called ingenic_adc.
+
config IMX7D_ADC
tristate "Freescale IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
@@ -576,6 +628,16 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
+config NPCM_ADC
+ tristate "Nuvoton NPCM ADC driver"
+ depends on ARCH_NPCM || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Say yes here to build support for Nuvoton NPCM ADC.
+
+ This driver can also be built as a module. If so, the module
+ will be called npcm_adc.
+
config PALMAS_GPADC
tristate "TI Palmas General Purpose ADC"
depends on MFD_PALMAS
@@ -908,6 +970,16 @@ config TI_ADS8688
This driver can also be built as a module. If so, the module will be
called ti-ads8688.
+config TI_ADS124S08
+ tristate "Texas Instruments ADS124S08"
+ depends on SPI && OF
+ help
+ If you say yes here you get support for Texas Instruments ADS124S08
+ and ADS124S06 ADC chips
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads124s08.
+
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC && HAS_DMA
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 07df37f621bd..d50eb47da484 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -11,7 +11,11 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
+obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
+obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
+obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7766) += ad7766.o
+obj-$(CONFIG_AD7768_1) += ad7768-1.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
@@ -36,6 +40,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
+obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
@@ -55,6 +60,7 @@ obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
+obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
@@ -81,6 +87,7 @@ obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
+obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 0549686b9ef8..76747488044b 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -59,6 +59,9 @@ enum ad7476_supported_device_ids {
ID_ADC081S,
ID_ADC101S,
ID_ADC121S,
+ ID_ADS7866,
+ ID_ADS7867,
+ ID_ADS7868,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
@@ -157,6 +160,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
+#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
+ BIT(IIO_CHAN_INFO_RAW))
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7091R] = {
@@ -209,6 +214,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = ADC081S_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
+ [ID_ADS7866] = {
+ .channel[0] = ADS786X_CHAN(12),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
+ [ID_ADS7867] = {
+ .channel[0] = ADS786X_CHAN(10),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
+ [ID_ADS7868] = {
+ .channel[0] = ADS786X_CHAN(8),
+ .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
+ },
};
static const struct iio_info ad7476_info = {
@@ -314,6 +331,9 @@ static const struct spi_device_id ad7476_id[] = {
{"adc081s", ID_ADC081S},
{"adc101s", ID_ADC101S},
{"adc121s", ID_ADC121S},
+ {"ads7866", ID_ADS7866},
+ {"ads7867", ID_ADS7867},
+ {"ads7868", ID_ADS7868},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 7308fa8fbb4c..ebb8de03bbce 100644
--- a/drivers/staging/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -1,28 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
-#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/util_macros.h>
#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7606.h"
@@ -30,8 +31,12 @@
* Scales are computed as 5000/32768 and 10000/32768 respectively,
* so that when applied to the raw values they provide mV values
*/
-static const unsigned int scale_avail[2][2] = {
- {0, 152588}, {0, 305176}
+static const unsigned int scale_avail[2] = {
+ 152588, 305176
+};
+
+static const unsigned int ad7606_oversampling_avail[7] = {
+ 1, 2, 4, 8, 16, 32, 64,
};
static int ad7606_reset(struct ad7606_state *st)
@@ -82,36 +87,24 @@ static int ad7606_read_samples(struct ad7606_state *st)
static irqreturn_t ad7606_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
- struct ad7606_state *st = iio_priv(pf->indio_dev);
-
- gpiod_set_value(st->gpio_convst, 1);
-
- return IRQ_HANDLED;
-}
-
-/**
- * ad7606_poll_bh_to_ring() bh of trigger launched polling to ring buffer
- * @work_s: the work struct through which this was scheduled
- *
- * Currently there is no option in this driver to disable the saving of
- * timestamps within the ring.
- * I think the one copy of this at a time was to avoid problems if the
- * trigger was set far too high and the reads then locked up the computer.
- **/
-static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
-{
- struct ad7606_state *st = container_of(work_s, struct ad7606_state,
- poll_work);
- struct iio_dev *indio_dev = iio_priv_to_dev(st);
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7606_state *st = iio_priv(indio_dev);
int ret;
+ mutex_lock(&st->lock);
+
ret = ad7606_read_samples(st);
if (ret == 0)
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
iio_get_time_ns(indio_dev));
- gpiod_set_value(st->gpio_convst, 0);
iio_trigger_notify_done(indio_dev->trig);
+ /* The rising edge of the CONVST signal starts a new conversion. */
+ gpiod_set_value(st->gpio_convst, 1);
+
+ mutex_unlock(&st->lock);
+
+ return IRQ_HANDLED;
}
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
@@ -119,12 +112,13 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
- st->done = false;
gpiod_set_value(st->gpio_convst, 1);
-
- ret = wait_event_interruptible(st->wq_data_avail, st->done);
- if (ret)
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret) {
+ ret = -ETIMEDOUT;
goto error_ret;
+ }
ret = ad7606_read_samples(st);
if (ret == 0)
@@ -159,8 +153,8 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
*val = (short)ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = scale_avail[st->range][0];
- *val2 = scale_avail[st->range][1];
+ *val = 0;
+ *val2 = scale_avail[st->range];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
@@ -176,8 +170,8 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
- len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
- scale_avail[i][0], scale_avail[i][1]);
+ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+ scale_avail[i]);
buf[len - 1] = '\n';
@@ -186,18 +180,6 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
-static int ad7606_oversampling_get_index(unsigned int val)
-{
- unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64};
- int i;
-
- for (i = 0; i < ARRAY_SIZE(supported); i++)
- if (val == supported[i])
- return i;
-
- return -EINVAL;
-}
-
static int ad7606_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
@@ -206,36 +188,29 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
{
struct ad7606_state *st = iio_priv(indio_dev);
DECLARE_BITMAP(values, 3);
- int ret, i;
+ int i;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = -EINVAL;
mutex_lock(&st->lock);
- for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
- if (val2 == scale_avail[i][1]) {
- gpiod_set_value(st->gpio_range, i);
- st->range = i;
-
- ret = 0;
- break;
- }
+ i = find_closest(val2, scale_avail, ARRAY_SIZE(scale_avail));
+ gpiod_set_value(st->gpio_range, i);
+ st->range = i;
mutex_unlock(&st->lock);
- return ret;
+ return 0;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
if (val2)
return -EINVAL;
- ret = ad7606_oversampling_get_index(val);
- if (ret < 0)
- return ret;
+ i = find_closest(val, ad7606_oversampling_avail,
+ ARRAY_SIZE(ad7606_oversampling_avail));
- values[0] = ret;
+ values[0] = i;
mutex_lock(&st->lock);
- gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info,
- values);
- st->oversampling = val;
+ gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
+ st->gpio_os->info, values);
+ st->oversampling = ad7606_oversampling_avail[i];
mutex_unlock(&st->lock);
return 0;
@@ -274,8 +249,7 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
-#define AD760X_CHANNEL(num, mask) \
- { \
+#define AD760X_CHANNEL(num, mask) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = num, \
@@ -290,7 +264,7 @@ static const struct attribute_group ad7606_attribute_group_range = {
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
- }
+}
#define AD7605_CHANNEL(num) \
AD760X_CHANNEL(num, 0)
@@ -319,9 +293,7 @@ static const struct iio_chan_spec ad7606_channels[] = {
};
static const struct ad7606_chip_info ad7606_chip_info_tbl[] = {
- /*
- * More devices added in future
- */
+ /* More devices added in future */
[ID_AD7605_4] = {
.channels = ad7605_channels,
.num_channels = 5,
@@ -347,7 +319,7 @@ static int ad7606_request_gpios(struct ad7606_state *st)
{
struct device *dev = st->dev;
- st->gpio_convst = devm_gpiod_get(dev, "conversion-start",
+ st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_convst))
return PTR_ERR(st->gpio_convst);
@@ -356,7 +328,8 @@ static int ad7606_request_gpios(struct ad7606_state *st)
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
- st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW);
+ st->gpio_range = devm_gpiod_get_optional(dev, "adi,range",
+ GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_range))
return PTR_ERR(st->gpio_range);
@@ -365,7 +338,7 @@ static int ad7606_request_gpios(struct ad7606_state *st)
if (IS_ERR(st->gpio_standby))
return PTR_ERR(st->gpio_standby);
- st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data",
+ st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data",
GPIOD_IN);
if (IS_ERR(st->gpio_frstdata))
return PTR_ERR(st->gpio_frstdata);
@@ -373,13 +346,17 @@ static int ad7606_request_gpios(struct ad7606_state *st)
if (!st->chip_info->has_oversampling)
return 0;
- st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio",
+ st->gpio_os = devm_gpiod_get_array_optional(dev,
+ "adi,oversampling-ratio",
GPIOD_OUT_LOW);
return PTR_ERR_OR_ZERO(st->gpio_os);
}
-/**
- * Interrupt handler
+/*
+ * The BUSY signal indicates when conversions are in progress, so when a rising
+ * edge of CONVST is applied, BUSY goes logic high and transitions low at the
+ * end of the entire conversion process. The falling edge of the BUSY signal
+ * triggers this interrupt.
*/
static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
{
@@ -387,37 +364,87 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
struct ad7606_state *st = iio_priv(indio_dev);
if (iio_buffer_enabled(indio_dev)) {
- schedule_work(&st->poll_work);
+ gpiod_set_value(st->gpio_convst, 0);
+ iio_trigger_poll_chained(st->trig);
} else {
- st->done = true;
- wake_up_interruptible(&st->wq_data_avail);
+ complete(&st->completion);
}
return IRQ_HANDLED;
};
+static int ad7606_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ if (st->trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ad7606_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ iio_triggered_buffer_postenable(indio_dev);
+ gpiod_set_value(st->gpio_convst, 1);
+
+ return 0;
+}
+
+static int ad7606_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ gpiod_set_value(st->gpio_convst, 0);
+
+ return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops ad7606_buffer_ops = {
+ .postenable = &ad7606_buffer_postenable,
+ .predisable = &ad7606_buffer_predisable,
+};
+
static const struct iio_info ad7606_info_no_os_or_range = {
.read_raw = &ad7606_read_raw,
+ .validate_trigger = &ad7606_validate_trigger,
};
static const struct iio_info ad7606_info_os_and_range = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os_and_range,
+ .validate_trigger = &ad7606_validate_trigger,
};
static const struct iio_info ad7606_info_os = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_os,
+ .validate_trigger = &ad7606_validate_trigger,
};
static const struct iio_info ad7606_info_range = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_range,
+ .validate_trigger = &ad7606_validate_trigger,
+};
+
+static const struct iio_trigger_ops ad7606_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
};
+static void ad7606_regulator_disable(void *data)
+{
+ struct ad7606_state *st = data;
+
+ regulator_disable(st->reg);
+}
+
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_bus_ops *bops)
@@ -431,6 +458,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return -ENOMEM;
st = iio_priv(indio_dev);
+ dev_set_drvdata(dev, indio_dev);
st->dev = dev;
mutex_init(&st->lock);
@@ -439,7 +467,6 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
/* tied to logic low, analog input range is +/- 5V */
st->range = 0;
st->oversampling = 1;
- INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
st->reg = devm_regulator_get(dev, "avcc");
if (IS_ERR(st->reg))
@@ -451,11 +478,15 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return ret;
}
+ ret = devm_add_action_or_reset(dev, ad7606_regulator_disable, st);
+ if (ret)
+ return ret;
+
st->chip_info = &ad7606_chip_info_tbl[id];
ret = ad7606_request_gpios(st);
if (ret)
- goto error_disable_reg;
+ return ret;
indio_dev->dev.parent = dev;
if (st->gpio_os) {
@@ -474,56 +505,45 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
- init_waitqueue_head(&st->wq_data_avail);
+ init_completion(&st->completion);
ret = ad7606_reset(st);
if (ret)
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
- ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name,
- indio_dev);
- if (ret)
- goto error_disable_reg;
-
- ret = iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler,
- NULL, NULL);
- if (ret)
- goto error_free_irq;
+ st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!st->trig)
+ return -ENOMEM;
- ret = iio_device_register(indio_dev);
+ st->trig->ops = &ad7606_trigger_ops;
+ st->trig->dev.parent = dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, st->trig);
if (ret)
- goto error_unregister_ring;
+ return ret;
- dev_set_drvdata(dev, indio_dev);
+ indio_dev->trig = iio_trigger_get(st->trig);
- return 0;
-error_unregister_ring:
- iio_triggered_buffer_cleanup(indio_dev);
+ ret = devm_request_threaded_irq(dev, irq,
+ NULL,
+ &ad7606_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ name, indio_dev);
+ if (ret)
+ return ret;
-error_free_irq:
- free_irq(irq, indio_dev);
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7606_trigger_handler,
+ &ad7606_buffer_ops);
+ if (ret)
+ return ret;
-error_disable_reg:
- regulator_disable(st->reg);
- return ret;
+ return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(ad7606_probe);
-int ad7606_remove(struct device *dev, int irq)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad7606_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- iio_triggered_buffer_cleanup(indio_dev);
-
- free_irq(irq, indio_dev);
- regulator_disable(st->reg);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ad7606_remove);
-
#ifdef CONFIG_PM_SLEEP
static int ad7606_suspend(struct device *dev)
diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 86188054b60b..5d12410f68e1 100644
--- a/drivers/staging/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* AD7606 ADC driver
*
* Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#ifndef IIO_ADC_AD7606_H_
@@ -15,7 +14,6 @@
* @num_channels: number of channels
* @has_oversampling: whether the device has oversampling support
*/
-
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
@@ -27,13 +25,9 @@ struct ad7606_chip_info {
* @dev pointer to kernel device
* @chip_info entry in the table of chips that describes this device
* @reg regulator info for the the power supply of the device
- * @poll_work work struct for continuously reading data from the device
- * into an IIO triggered buffer
- * @wq_data_avail wait queue struct for buffer mode
* @bops bus operations (SPI or parallel)
* @range voltage range selection, selects which scale to apply
* @oversampling oversampling selection
- * @done marks whether reading data is done
* @base_address address from where to read data in parallel operation
* @lock protect sensor state from concurrent accesses to GPIOs
* @gpio_convst GPIO descriptor for conversion start signal (CONVST)
@@ -44,19 +38,17 @@ struct ad7606_chip_info {
* @gpio_frstdata GPIO descriptor for reading from device when data
* is being read on the first channel
* @gpio_os GPIO descriptors to control oversampling on the device
+ * @complete completion to indicate end of conversion
+ * @trig The IIO trigger associated with the device.
* @data buffer for reading data from the device
*/
-
struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
struct regulator *reg;
- struct work_struct poll_work;
- wait_queue_head_t wq_data_avail;
const struct ad7606_bus_ops *bops;
unsigned int range;
unsigned int oversampling;
- bool done;
void __iomem *base_address;
struct mutex lock; /* protect sensor state */
@@ -66,6 +58,8 @@ struct ad7606_state {
struct gpio_desc *gpio_standby;
struct gpio_desc *gpio_frstdata;
struct gpio_descs *gpio_os;
+ struct iio_trigger *trig;
+ struct completion completion;
/*
* DMA (thus cache coherency maintenance) requires the
@@ -87,7 +81,6 @@ struct ad7606_bus_ops {
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_bus_ops *bops);
-int ad7606_remove(struct device *dev, int irq);
enum ad7606_supported_device_ids {
ID_AD7605_4,
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index 8bd86e727b02..1b08028facde 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 Parallel Interface ADC driver
*
* Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#include <linux/module.h>
@@ -27,7 +26,7 @@ static int ad7606_par16_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_par16_bops = {
- .read_block = ad7606_par16_read_block,
+ .read_block = ad7606_par16_read_block,
};
static int ad7606_par8_read_block(struct device *dev,
@@ -42,7 +41,7 @@ static int ad7606_par8_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_par8_bops = {
- .read_block = ad7606_par8_read_block,
+ .read_block = ad7606_par8_read_block,
};
static int ad7606_par_probe(struct platform_device *pdev)
@@ -72,40 +71,33 @@ static int ad7606_par_probe(struct platform_device *pdev)
&ad7606_par8_bops);
}
-static int ad7606_par_remove(struct platform_device *pdev)
-{
- return ad7606_remove(&pdev->dev, platform_get_irq(pdev, 0));
-}
-
static const struct platform_device_id ad7606_driver_ids[] = {
- {
- .name = "ad7605-4",
- .driver_data = ID_AD7605_4,
- }, {
- .name = "ad7606-8",
- .driver_data = ID_AD7606_8,
- }, {
- .name = "ad7606-6",
- .driver_data = ID_AD7606_6,
- }, {
- .name = "ad7606-4",
- .driver_data = ID_AD7606_4,
- },
+ { .name = "ad7605-4", .driver_data = ID_AD7605_4, },
+ { .name = "ad7606-4", .driver_data = ID_AD7606_4, },
+ { .name = "ad7606-6", .driver_data = ID_AD7606_6, },
+ { .name = "ad7606-8", .driver_data = ID_AD7606_8, },
{ }
};
-
MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
+static const struct of_device_id ad7606_of_match[] = {
+ { .compatible = "adi,ad7605-4" },
+ { .compatible = "adi,ad7606-4" },
+ { .compatible = "adi,ad7606-6" },
+ { .compatible = "adi,ad7606-8" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ad7606_of_match);
+
static struct platform_driver ad7606_driver = {
.probe = ad7606_par_probe,
- .remove = ad7606_par_remove,
.id_table = ad7606_driver_ids,
.driver = {
- .name = "ad7606",
- .pm = AD7606_PM_OPS,
+ .name = "ad7606",
+ .pm = AD7606_PM_OPS,
+ .of_match_table = ad7606_of_match,
},
};
-
module_platform_driver(ad7606_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index b76ca5a8c059..4fd0ec36a086 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#include <linux/module.h>
@@ -37,7 +36,7 @@ static int ad7606_spi_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_spi_bops = {
- .read_block = ad7606_spi_read_block,
+ .read_block = ad7606_spi_read_block,
};
static int ad7606_spi_probe(struct spi_device *spi)
@@ -49,28 +48,32 @@ static int ad7606_spi_probe(struct spi_device *spi)
&ad7606_spi_bops);
}
-static int ad7606_spi_remove(struct spi_device *spi)
-{
- return ad7606_remove(&spi->dev, spi->irq);
-}
-
-static const struct spi_device_id ad7606_id[] = {
- {"ad7605-4", ID_AD7605_4},
- {"ad7606-8", ID_AD7606_8},
- {"ad7606-6", ID_AD7606_6},
- {"ad7606-4", ID_AD7606_4},
+static const struct spi_device_id ad7606_id_table[] = {
+ { "ad7605-4", ID_AD7605_4 },
+ { "ad7606-4", ID_AD7606_4 },
+ { "ad7606-6", ID_AD7606_6 },
+ { "ad7606-8", ID_AD7606_8 },
{}
};
-MODULE_DEVICE_TABLE(spi, ad7606_id);
+MODULE_DEVICE_TABLE(spi, ad7606_id_table);
+
+static const struct of_device_id ad7606_of_match[] = {
+ { .compatible = "adi,ad7605-4" },
+ { .compatible = "adi,ad7606-4" },
+ { .compatible = "adi,ad7606-6" },
+ { .compatible = "adi,ad7606-8" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ad7606_of_match);
static struct spi_driver ad7606_driver = {
.driver = {
.name = "ad7606",
+ .of_match_table = ad7606_of_match,
.pm = AD7606_PM_OPS,
},
.probe = ad7606_spi_probe,
- .remove = ad7606_spi_remove,
- .id_table = ad7606_id,
+ .id_table = ad7606_id_table,
};
module_spi_driver(ad7606_driver);
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
new file mode 100644
index 000000000000..0d132708c429
--- /dev/null
+++ b/drivers/iio/adc/ad7768-1.c
@@ -0,0 +1,655 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices AD7768-1 SPI ADC driver
+ *
+ * Copyright 2017 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+/* AD7768 registers definition */
+#define AD7768_REG_CHIP_TYPE 0x3
+#define AD7768_REG_PROD_ID_L 0x4
+#define AD7768_REG_PROD_ID_H 0x5
+#define AD7768_REG_CHIP_GRADE 0x6
+#define AD7768_REG_SCRATCH_PAD 0x0A
+#define AD7768_REG_VENDOR_L 0x0C
+#define AD7768_REG_VENDOR_H 0x0D
+#define AD7768_REG_INTERFACE_FORMAT 0x14
+#define AD7768_REG_POWER_CLOCK 0x15
+#define AD7768_REG_ANALOG 0x16
+#define AD7768_REG_ANALOG2 0x17
+#define AD7768_REG_CONVERSION 0x18
+#define AD7768_REG_DIGITAL_FILTER 0x19
+#define AD7768_REG_SINC3_DEC_RATE_MSB 0x1A
+#define AD7768_REG_SINC3_DEC_RATE_LSB 0x1B
+#define AD7768_REG_DUTY_CYCLE_RATIO 0x1C
+#define AD7768_REG_SYNC_RESET 0x1D
+#define AD7768_REG_GPIO_CONTROL 0x1E
+#define AD7768_REG_GPIO_WRITE 0x1F
+#define AD7768_REG_GPIO_READ 0x20
+#define AD7768_REG_OFFSET_HI 0x21
+#define AD7768_REG_OFFSET_MID 0x22
+#define AD7768_REG_OFFSET_LO 0x23
+#define AD7768_REG_GAIN_HI 0x24
+#define AD7768_REG_GAIN_MID 0x25
+#define AD7768_REG_GAIN_LO 0x26
+#define AD7768_REG_SPI_DIAG_ENABLE 0x28
+#define AD7768_REG_ADC_DIAG_ENABLE 0x29
+#define AD7768_REG_DIG_DIAG_ENABLE 0x2A
+#define AD7768_REG_ADC_DATA 0x2C
+#define AD7768_REG_MASTER_STATUS 0x2D
+#define AD7768_REG_SPI_DIAG_STATUS 0x2E
+#define AD7768_REG_ADC_DIAG_STATUS 0x2F
+#define AD7768_REG_DIG_DIAG_STATUS 0x30
+#define AD7768_REG_MCLK_COUNTER 0x31
+
+/* AD7768_REG_POWER_CLOCK */
+#define AD7768_PWR_MCLK_DIV_MSK GENMASK(5, 4)
+#define AD7768_PWR_MCLK_DIV(x) FIELD_PREP(AD7768_PWR_MCLK_DIV_MSK, x)
+#define AD7768_PWR_PWRMODE_MSK GENMASK(1, 0)
+#define AD7768_PWR_PWRMODE(x) FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x)
+
+/* AD7768_REG_DIGITAL_FILTER */
+#define AD7768_DIG_FIL_FIL_MSK GENMASK(6, 4)
+#define AD7768_DIG_FIL_FIL(x) FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x)
+#define AD7768_DIG_FIL_DEC_MSK GENMASK(2, 0)
+#define AD7768_DIG_FIL_DEC_RATE(x) FIELD_PREP(AD7768_DIG_FIL_DEC_MSK, x)
+
+/* AD7768_REG_CONVERSION */
+#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
+#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
+
+#define AD7768_RD_FLAG_MSK(x) (BIT(6) | ((x) & 0x3F))
+#define AD7768_WR_FLAG_MSK(x) ((x) & 0x3F)
+
+enum ad7768_conv_mode {
+ AD7768_CONTINUOUS,
+ AD7768_ONE_SHOT,
+ AD7768_SINGLE,
+ AD7768_PERIODIC,
+ AD7768_STANDBY
+};
+
+enum ad7768_pwrmode {
+ AD7768_ECO_MODE = 0,
+ AD7768_MED_MODE = 2,
+ AD7768_FAST_MODE = 3
+};
+
+enum ad7768_mclk_div {
+ AD7768_MCLK_DIV_16,
+ AD7768_MCLK_DIV_8,
+ AD7768_MCLK_DIV_4,
+ AD7768_MCLK_DIV_2
+};
+
+enum ad7768_dec_rate {
+ AD7768_DEC_RATE_32 = 0,
+ AD7768_DEC_RATE_64 = 1,
+ AD7768_DEC_RATE_128 = 2,
+ AD7768_DEC_RATE_256 = 3,
+ AD7768_DEC_RATE_512 = 4,
+ AD7768_DEC_RATE_1024 = 5,
+ AD7768_DEC_RATE_8 = 9,
+ AD7768_DEC_RATE_16 = 10
+};
+
+struct ad7768_clk_configuration {
+ enum ad7768_mclk_div mclk_div;
+ enum ad7768_dec_rate dec_rate;
+ unsigned int clk_div;
+ enum ad7768_pwrmode pwrmode;
+};
+
+static const struct ad7768_clk_configuration ad7768_clk_config[] = {
+ { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE },
+ { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE },
+ { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE },
+ { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE },
+ { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE },
+ { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE },
+ { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE },
+ { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE },
+ { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE },
+ { AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE },
+ { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE },
+};
+
+static const struct iio_chan_spec ad7768_channels[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ .endianness = IIO_BE,
+ },
+ },
+};
+
+struct ad7768_state {
+ struct spi_device *spi;
+ struct regulator *vref;
+ struct mutex lock;
+ struct clk *mclk;
+ unsigned int mclk_freq;
+ unsigned int samp_freq;
+ struct completion completion;
+ struct iio_trigger *trig;
+ struct gpio_desc *gpio_sync_in;
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ union {
+ __be32 d32;
+ u8 d8[2];
+ } data ____cacheline_aligned;
+};
+
+static int ad7768_spi_reg_read(struct ad7768_state *st, unsigned int addr,
+ unsigned int len)
+{
+ unsigned int shift;
+ int ret;
+
+ shift = 32 - (8 * len);
+ st->data.d8[0] = AD7768_RD_FLAG_MSK(addr);
+
+ ret = spi_write_then_read(st->spi, st->data.d8, 1,
+ &st->data.d32, len);
+ if (ret < 0)
+ return ret;
+
+ return (be32_to_cpu(st->data.d32) >> shift);
+}
+
+static int ad7768_spi_reg_write(struct ad7768_state *st,
+ unsigned int addr,
+ unsigned int val)
+{
+ st->data.d8[0] = AD7768_WR_FLAG_MSK(addr);
+ st->data.d8[1] = val & 0xFF;
+
+ return spi_write(st->spi, st->data.d8, 2);
+}
+
+static int ad7768_set_mode(struct ad7768_state *st,
+ enum ad7768_conv_mode mode)
+{
+ int regval;
+
+ regval = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, 1);
+ if (regval < 0)
+ return regval;
+
+ regval &= ~AD7768_CONV_MODE_MSK;
+ regval |= AD7768_CONV_MODE(mode);
+
+ return ad7768_spi_reg_write(st, AD7768_REG_CONVERSION, regval);
+}
+
+static int ad7768_scan_direct(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int readval, ret;
+
+ reinit_completion(&st->completion);
+
+ ret = ad7768_set_mode(st, AD7768_ONE_SHOT);
+ if (ret < 0)
+ return ret;
+
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ readval = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3);
+ if (readval < 0)
+ return readval;
+ /*
+ * Any SPI configuration of the AD7768-1 can only be
+ * performed in continuous conversion mode.
+ */
+ ret = ad7768_set_mode(st, AD7768_CONTINUOUS);
+ if (ret < 0)
+ return ret;
+
+ return readval;
+}
+
+static int ad7768_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+ if (readval) {
+ ret = ad7768_spi_reg_read(st, reg, 1);
+ if (ret < 0)
+ goto err_unlock;
+ *readval = ret;
+ ret = 0;
+ } else {
+ ret = ad7768_spi_reg_write(st, reg, writeval);
+ }
+err_unlock:
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int ad7768_set_dig_fil(struct ad7768_state *st,
+ enum ad7768_dec_rate dec_rate)
+{
+ unsigned int mode;
+ int ret;
+
+ if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16)
+ mode = AD7768_DIG_FIL_FIL(dec_rate);
+ else
+ mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
+
+ ret = ad7768_spi_reg_write(st, AD7768_REG_DIGITAL_FILTER, mode);
+ if (ret < 0)
+ return ret;
+
+ /* A sync-in pulse is required every time the filter dec rate changes */
+ gpiod_set_value(st->gpio_sync_in, 1);
+ gpiod_set_value(st->gpio_sync_in, 0);
+
+ return 0;
+}
+
+static int ad7768_set_freq(struct ad7768_state *st,
+ unsigned int freq)
+{
+ unsigned int diff_new, diff_old, pwr_mode, i, idx;
+ int res, ret;
+
+ diff_old = U32_MAX;
+ idx = 0;
+
+ res = DIV_ROUND_CLOSEST(st->mclk_freq, freq);
+
+ /* Find the closest match for the desired sampling frequency */
+ for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
+ diff_new = abs(res - ad7768_clk_config[i].clk_div);
+ if (diff_new < diff_old) {
+ diff_old = diff_new;
+ idx = i;
+ }
+ }
+
+ /*
+ * Set both the mclk_div and pwrmode with a single write to the
+ * POWER_CLOCK register
+ */
+ pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
+ AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
+ ret = ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK, pwr_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate);
+ if (ret < 0)
+ return ret;
+
+ st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
+ ad7768_clk_config[idx].clk_div);
+
+ return 0;
+}
+
+static ssize_t ad7768_sampling_freq_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int freq;
+ int i, len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
+ freq = DIV_ROUND_CLOSEST(st->mclk_freq,
+ ad7768_clk_config[i].clk_div);
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", freq);
+ }
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ad7768_sampling_freq_avail);
+
+static int ad7768_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int scale_uv, ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad7768_scan_direct(indio_dev);
+ if (ret >= 0)
+ *val = ret;
+
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ scale_uv = regulator_get_voltage(st->vref);
+ if (scale_uv < 0)
+ return scale_uv;
+
+ *val = (scale_uv * 2) / 1000;
+ *val2 = chan->scan_type.realbits;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->samp_freq;
+
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static int ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad7768_set_freq(st, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct attribute *ad7768_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ad7768_group = {
+ .attrs = ad7768_attributes,
+};
+
+static const struct iio_info ad7768_info = {
+ .attrs = &ad7768_group,
+ .read_raw = &ad7768_read_raw,
+ .write_raw = &ad7768_write_raw,
+ .debugfs_reg_access = &ad7768_reg_access,
+};
+
+static int ad7768_setup(struct ad7768_state *st)
+{
+ int ret;
+
+ /*
+ * Two writes to the SPI_RESET[1:0] bits are required to initiate
+ * a software reset. The bits must first be set to 11, and then
+ * to 10. When the sequence is detected, the reset occurs.
+ * See the datasheet, page 70.
+ */
+ ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x3);
+ if (ret)
+ return ret;
+
+ ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x2);
+ if (ret)
+ return ret;
+
+ st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->gpio_sync_in))
+ return PTR_ERR(st->gpio_sync_in);
+
+ /* Set the default sampling frequency to 32000 kSPS */
+ return ad7768_set_freq(st, 32000);
+}
+
+static irqreturn_t ad7768_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = spi_read(st->spi, &st->data.d32, 3);
+ if (ret < 0)
+ goto err_unlock;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &st->data.d32,
+ iio_get_time_ns(indio_dev));
+
+ iio_trigger_notify_done(indio_dev->trig);
+err_unlock:
+ mutex_unlock(&st->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ad7768_interrupt(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll(st->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+};
+
+static int ad7768_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+
+ iio_triggered_buffer_postenable(indio_dev);
+ /*
+ * Write a 1 to the LSB of the INTERFACE_FORMAT register to enter
+ * continuous read mode. Subsequent data reads do not require an
+ * initial 8-bit write to query the ADC_DATA register.
+ */
+ return ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01);
+}
+
+static int ad7768_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ /*
+ * To exit continuous read mode, perform a single read of the ADC_DATA
+ * reg (0x2C), which allows further configuration of the device.
+ */
+ ret = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3);
+ if (ret < 0)
+ return ret;
+
+ return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
+ .postenable = &ad7768_buffer_postenable,
+ .predisable = &ad7768_buffer_predisable,
+};
+
+static const struct iio_trigger_ops ad7768_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static void ad7768_regulator_disable(void *data)
+{
+ struct ad7768_state *st = data;
+
+ regulator_disable(st->vref);
+}
+
+static void ad7768_clk_disable(void *data)
+{
+ struct ad7768_state *st = data;
+
+ clk_disable_unprepare(st->mclk);
+}
+
+static int ad7768_probe(struct spi_device *spi)
+{
+ struct ad7768_state *st;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ st->vref = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->vref))
+ return PTR_ERR(st->vref);
+
+ ret = regulator_enable(st->vref);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable specified vref supply\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7768_regulator_disable, st);
+ if (ret)
+ return ret;
+
+ st->mclk = devm_clk_get(&spi->dev, "mclk");
+ if (IS_ERR(st->mclk))
+ return PTR_ERR(st->mclk);
+
+ ret = clk_prepare_enable(st->mclk);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, ad7768_clk_disable, st);
+ if (ret)
+ return ret;
+
+ st->mclk_freq = clk_get_rate(st->mclk);
+
+ spi_set_drvdata(spi, indio_dev);
+ mutex_init(&st->lock);
+
+ indio_dev->channels = ad7768_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7768_channels);
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->info = &ad7768_info;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED;
+
+ ret = ad7768_setup(st);
+ if (ret < 0) {
+ dev_err(&spi->dev, "AD7768 setup failed\n");
+ return ret;
+ }
+
+ st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad7768_trigger_ops;
+ st->trig->dev.parent = &spi->dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(&spi->dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ init_completion(&st->completion);
+
+ ret = devm_request_irq(&spi->dev, spi->irq,
+ &ad7768_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7768_trigger_handler,
+ &ad7768_buffer_ops);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ad7768_id_table[] = {
+ { "ad7768-1", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7768_id_table);
+
+static const struct of_device_id ad7768_of_match[] = {
+ { .compatible = "adi,ad7768-1" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ad7768_of_match);
+
+static struct spi_driver ad7768_driver = {
+ .driver = {
+ .name = "ad7768-1",
+ .of_match_table = ad7768_of_match,
+ },
+ .probe = ad7768_probe,
+ .id_table = ad7768_id_table,
+};
+module_spi_driver(ad7768_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7768-1 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index fa2d2b5767f3..1ca2c4d39f87 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -115,6 +115,7 @@
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
+#define MAX_EXYNOS4212_ADC_CHANNELS 4
#define MAX_S5PV210_ADC_CHANNELS 10
/* Bit definitions common for ADC_V1 and ADC_V2 */
@@ -271,6 +272,19 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
+/* Exynos4212 and 4412 is like ADCv1 but with four channels only */
+static const struct exynos_adc_data exynos4212_adc_data = {
+ .num_channels = MAX_EXYNOS4212_ADC_CHANNELS,
+ .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
+ .needs_adc_phy = true,
+ .phy_offset = EXYNOS_ADCV1_PHY_OFFSET,
+
+ .init_hw = exynos_adc_v1_init_hw,
+ .exit_hw = exynos_adc_v1_exit_hw,
+ .clear_irq = exynos_adc_v1_clear_irq,
+ .start_conv = exynos_adc_v1_start_conv,
+};
+
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
@@ -493,6 +507,9 @@ static const struct of_device_id exynos_adc_match[] = {
.compatible = "samsung,s5pv210-adc",
.data = &exynos_adc_s5pv210_data,
}, {
+ .compatible = "samsung,exynos4212-adc",
+ .data = &exynos4212_adc_data,
+ }, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
}, {
@@ -929,7 +946,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
- if (IS_REACHABLE(CONFIG_INPUT)) {
+ if (IS_REACHABLE(CONFIG_INPUT) && info->input) {
free_irq(info->tsirq, info);
input_unregister_device(info->input);
}
diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
new file mode 100644
index 000000000000..6ee1673deb0d
--- /dev/null
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADC driver for the Ingenic JZ47xx SoCs
+ * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
+ *
+ * based on drivers/mfd/jz4740-adc.c
+ */
+
+#include <dt-bindings/iio/adc/ingenic,adc.h>
+#include <linux/clk.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define JZ_ADC_REG_ENABLE 0x00
+#define JZ_ADC_REG_CFG 0x04
+#define JZ_ADC_REG_CTRL 0x08
+#define JZ_ADC_REG_STATUS 0x0c
+#define JZ_ADC_REG_ADTCH 0x18
+#define JZ_ADC_REG_ADBDAT 0x1c
+#define JZ_ADC_REG_ADSDAT 0x20
+
+#define JZ_ADC_REG_CFG_BAT_MD BIT(4)
+
+#define JZ_ADC_AUX_VREF 3300
+#define JZ_ADC_AUX_VREF_BITS 12
+#define JZ_ADC_BATTERY_LOW_VREF 2500
+#define JZ_ADC_BATTERY_LOW_VREF_BITS 12
+#define JZ4725B_ADC_BATTERY_HIGH_VREF 7500
+#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
+
+struct ingenic_adc_soc_data {
+ unsigned int battery_high_vref;
+ unsigned int battery_high_vref_bits;
+ const int *battery_raw_avail;
+ size_t battery_raw_avail_size;
+ const int *battery_scale_avail;
+ size_t battery_scale_avail_size;
+};
+
+struct ingenic_adc {
+ void __iomem *base;
+ struct clk *clk;
+ struct mutex lock;
+ const struct ingenic_adc_soc_data *soc_data;
+ bool low_vref_mode;
+};
+
+static void ingenic_adc_set_config(struct ingenic_adc *adc,
+ uint32_t mask,
+ uint32_t val)
+{
+ uint32_t cfg;
+
+ clk_enable(adc->clk);
+ mutex_lock(&adc->lock);
+
+ cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
+ cfg |= val;
+ writel(cfg, adc->base + JZ_ADC_REG_CFG);
+
+ mutex_unlock(&adc->lock);
+ clk_disable(adc->clk);
+}
+
+static void ingenic_adc_enable(struct ingenic_adc *adc,
+ int engine,
+ bool enabled)
+{
+ u8 val;
+
+ mutex_lock(&adc->lock);
+ val = readb(adc->base + JZ_ADC_REG_ENABLE);
+
+ if (enabled)
+ val |= BIT(engine);
+ else
+ val &= ~BIT(engine);
+
+ writeb(val, adc->base + JZ_ADC_REG_ENABLE);
+ mutex_unlock(&adc->lock);
+}
+
+static int ingenic_adc_capture(struct ingenic_adc *adc,
+ int engine)
+{
+ u8 val;
+ int ret;
+
+ ingenic_adc_enable(adc, engine, true);
+ ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
+ !(val & BIT(engine)), 250, 1000);
+ if (ret)
+ ingenic_adc_enable(adc, engine, false);
+
+ return ret;
+}
+
+static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long m)
+{
+ struct ingenic_adc *adc = iio_priv(iio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel) {
+ case INGENIC_ADC_BATTERY:
+ if (val > JZ_ADC_BATTERY_LOW_VREF) {
+ ingenic_adc_set_config(adc,
+ JZ_ADC_REG_CFG_BAT_MD,
+ 0);
+ adc->low_vref_mode = false;
+ } else {
+ ingenic_adc_set_config(adc,
+ JZ_ADC_REG_CFG_BAT_MD,
+ JZ_ADC_REG_CFG_BAT_MD);
+ adc->low_vref_mode = true;
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const int jz4725b_adc_battery_raw_avail[] = {
+ 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
+};
+
+static const int jz4725b_adc_battery_scale_avail[] = {
+ JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
+ JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
+};
+
+static const int jz4740_adc_battery_raw_avail[] = {
+ 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
+};
+
+static const int jz4740_adc_battery_scale_avail[] = {
+ JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
+ JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
+};
+
+static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
+ .battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
+ .battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
+ .battery_raw_avail = jz4725b_adc_battery_raw_avail,
+ .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
+ .battery_scale_avail = jz4725b_adc_battery_scale_avail,
+ .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
+};
+
+static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
+ .battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
+ .battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
+ .battery_raw_avail = jz4740_adc_battery_raw_avail,
+ .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
+ .battery_scale_avail = jz4740_adc_battery_scale_avail,
+ .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
+};
+
+static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals,
+ int *type,
+ int *length,
+ long m)
+{
+ struct ingenic_adc *adc = iio_priv(iio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ *type = IIO_VAL_INT;
+ *length = adc->soc_data->battery_raw_avail_size;
+ *vals = adc->soc_data->battery_raw_avail;
+ return IIO_AVAIL_RANGE;
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_FRACTIONAL_LOG2;
+ *length = adc->soc_data->battery_scale_avail_size;
+ *vals = adc->soc_data->battery_scale_avail;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ };
+}
+
+static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ struct ingenic_adc *adc = iio_priv(iio_dev);
+ int ret;
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ clk_enable(adc->clk);
+ ret = ingenic_adc_capture(adc, chan->channel);
+ if (ret) {
+ clk_disable(adc->clk);
+ return ret;
+ }
+
+ switch (chan->channel) {
+ case INGENIC_ADC_AUX:
+ *val = readw(adc->base + JZ_ADC_REG_ADSDAT);
+ break;
+ case INGENIC_ADC_BATTERY:
+ *val = readw(adc->base + JZ_ADC_REG_ADBDAT);
+ break;
+ }
+
+ clk_disable(adc->clk);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel) {
+ case INGENIC_ADC_AUX:
+ *val = JZ_ADC_AUX_VREF;
+ *val2 = JZ_ADC_AUX_VREF_BITS;
+ break;
+ case INGENIC_ADC_BATTERY:
+ if (adc->low_vref_mode) {
+ *val = JZ_ADC_BATTERY_LOW_VREF;
+ *val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
+ } else {
+ *val = adc->soc_data->battery_high_vref;
+ *val2 = adc->soc_data->battery_high_vref_bits;
+ }
+ break;
+ }
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void ingenic_adc_clk_cleanup(void *data)
+{
+ clk_unprepare(data);
+}
+
+static const struct iio_info ingenic_adc_info = {
+ .write_raw = ingenic_adc_write_raw,
+ .read_raw = ingenic_adc_read_raw,
+ .read_avail = ingenic_adc_read_avail,
+};
+
+static const struct iio_chan_spec ingenic_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_AUX,
+ },
+ {
+ .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,
+ },
+};
+
+static int ingenic_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *iio_dev;
+ struct ingenic_adc *adc;
+ struct resource *mem_base;
+ const struct ingenic_adc_soc_data *soc_data;
+ int ret;
+
+ soc_data = device_get_match_data(dev);
+ if (!soc_data)
+ return -EINVAL;
+
+ iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ adc = iio_priv(iio_dev);
+ mutex_init(&adc->lock);
+ adc->soc_data = soc_data;
+
+ mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ adc->base = devm_ioremap_resource(dev, mem_base);
+ if (IS_ERR(adc->base)) {
+ dev_err(dev, "Unable to ioremap mmio resource\n");
+ return PTR_ERR(adc->base);
+ }
+
+ adc->clk = devm_clk_get(dev, "adc");
+ if (IS_ERR(adc->clk)) {
+ dev_err(dev, "Unable to get clock\n");
+ return PTR_ERR(adc->clk);
+ }
+
+ ret = clk_prepare_enable(adc->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ /* Put hardware in a known passive state. */
+ writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
+ writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
+ clk_disable(adc->clk);
+
+ ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
+ if (ret) {
+ dev_err(dev, "Unable to add action\n");
+ return ret;
+ }
+
+ iio_dev->dev.parent = dev;
+ iio_dev->name = "jz-adc";
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->channels = ingenic_channels;
+ iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
+ iio_dev->info = &ingenic_adc_info;
+
+ ret = devm_iio_device_register(dev, iio_dev);
+ if (ret)
+ dev_err(dev, "Unable to register IIO device\n");
+
+ return ret;
+}
+
+#ifdef CONFIG_OF
+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, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
+#endif
+
+static struct platform_driver ingenic_adc_driver = {
+ .driver = {
+ .name = "ingenic-adc",
+ .of_match_table = of_match_ptr(ingenic_adc_of_match),
+ },
+ .probe = ingenic_adc_probe,
+};
+module_platform_driver(ingenic_adc_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c
index 20b36690fa4f..e361c1532a75 100644
--- a/drivers/iio/adc/lpc32xx_adc.c
+++ b/drivers/iio/adc/lpc32xx_adc.c
@@ -1,23 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/*
* lpc32xx_adc.c - Support for ADC in LPC32XX
*
* 3-channel, 10-bit ADC
*
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 729becb2d3d9..f8600fbcdfe3 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/mfd/syscon.h>
#define MESON_SAR_ADC_REG0 0x00
#define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
@@ -174,6 +175,9 @@
#define MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL GENMASK(6, 0)
#define MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED BIT(7)
+#define MESON_HHI_DPLL_TOP_0 0x318
+#define MESON_HHI_DPLL_TOP_0_TSC_BIT4 BIT(9)
+
/* for use with IIO_VAL_INT_PLUS_MICRO */
#define MILLION 1000000
@@ -280,6 +284,7 @@ struct meson_sar_adc_priv {
struct completion done;
int calibbias;
int calibscale;
+ struct regmap *tsc_regmap;
bool temperature_sensor_calibrated;
u8 temperature_sensor_coefficient;
u16 temperature_sensor_adc_val;
@@ -727,6 +732,15 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
return ret;
}
+ priv->tsc_regmap =
+ syscon_regmap_lookup_by_phandle(indio_dev->dev.parent->of_node,
+ "amlogic,hhi-sysctrl");
+ if (IS_ERR(priv->tsc_regmap)) {
+ dev_err(indio_dev->dev.parent,
+ "failed to get amlogic,hhi-sysctrl regmap\n");
+ return PTR_ERR(priv->tsc_regmap);
+ }
+
read_len = MESON_SAR_ADC_EFUSE_BYTES;
buf = nvmem_cell_read(temperature_calib, &read_len);
if (IS_ERR(buf)) {
@@ -861,6 +875,22 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
priv->temperature_sensor_coefficient);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_C_MASK, regval);
+
+ if (priv->param->temperature_trimming_bits == 5) {
+ if (priv->temperature_sensor_coefficient & BIT(4))
+ regval = MESON_HHI_DPLL_TOP_0_TSC_BIT4;
+ else
+ regval = 0;
+
+ /*
+ * bit [4] (the 5th bit when starting to count at 1)
+ * of the TSC is located in the HHI register area.
+ */
+ regmap_update_bits(priv->tsc_regmap,
+ MESON_HHI_DPLL_TOP_0,
+ MESON_HHI_DPLL_TOP_0_TSC_BIT4,
+ regval);
+ }
} else {
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
@@ -1064,6 +1094,9 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
.bandgap_reg = MESON_SAR_ADC_DELTA_10,
.regmap_config = &meson_sar_adc_regmap_config_meson8,
.resolution = 10,
+ .temperature_trimming_bits = 5,
+ .temperature_multiplier = 10,
+ .temperature_divider = 32,
};
static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
new file mode 100644
index 000000000000..9e25bbec9c70
--- /dev/null
+++ b/drivers/iio/adc/npcm_adc.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Nuvoton Technology corporation.
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+struct npcm_adc {
+ bool int_status;
+ u32 adc_sample_hz;
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *adc_clk;
+ wait_queue_head_t wq;
+ struct regulator *vref;
+ struct regmap *rst_regmap;
+};
+
+/* NPCM7xx reset module */
+#define NPCM7XX_IPSRST1_OFFSET 0x020
+#define NPCM7XX_IPSRST1_ADC_RST BIT(27)
+
+/* ADC registers */
+#define NPCM_ADCCON 0x00
+#define NPCM_ADCDATA 0x04
+
+/* ADCCON Register Bits */
+#define NPCM_ADCCON_ADC_INT_EN BIT(21)
+#define NPCM_ADCCON_REFSEL BIT(19)
+#define NPCM_ADCCON_ADC_INT_ST BIT(18)
+#define NPCM_ADCCON_ADC_EN BIT(17)
+#define NPCM_ADCCON_ADC_RST BIT(16)
+#define NPCM_ADCCON_ADC_CONV BIT(13)
+
+#define NPCM_ADCCON_CH_MASK GENMASK(27, 24)
+#define NPCM_ADCCON_CH(x) ((x) << 24)
+#define NPCM_ADCCON_DIV_SHIFT 1
+#define NPCM_ADCCON_DIV_MASK GENMASK(8, 1)
+#define NPCM_ADC_DATA_MASK(x) ((x) & GENMASK(9, 0))
+
+#define NPCM_ADC_ENABLE (NPCM_ADCCON_ADC_EN | NPCM_ADCCON_ADC_INT_EN)
+
+/* ADC General Definition */
+#define NPCM_RESOLUTION_BITS 10
+#define NPCM_INT_VREF_MV 2000
+
+#define NPCM_ADC_CHAN(ch) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = ch, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec npcm_adc_iio_channels[] = {
+ NPCM_ADC_CHAN(0),
+ NPCM_ADC_CHAN(1),
+ NPCM_ADC_CHAN(2),
+ NPCM_ADC_CHAN(3),
+ NPCM_ADC_CHAN(4),
+ NPCM_ADC_CHAN(5),
+ NPCM_ADC_CHAN(6),
+ NPCM_ADC_CHAN(7),
+};
+
+static irqreturn_t npcm_adc_isr(int irq, void *data)
+{
+ u32 regtemp;
+ struct iio_dev *indio_dev = data;
+ struct npcm_adc *info = iio_priv(indio_dev);
+
+ regtemp = ioread32(info->regs + NPCM_ADCCON);
+ if (regtemp & NPCM_ADCCON_ADC_INT_ST) {
+ iowrite32(regtemp, info->regs + NPCM_ADCCON);
+ wake_up_interruptible(&info->wq);
+ info->int_status = true;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int npcm_adc_read(struct npcm_adc *info, int *val, u8 channel)
+{
+ int ret;
+ u32 regtemp;
+
+ /* Select ADC channel */
+ regtemp = ioread32(info->regs + NPCM_ADCCON);
+ regtemp &= ~NPCM_ADCCON_CH_MASK;
+ info->int_status = false;
+ iowrite32(regtemp | NPCM_ADCCON_CH(channel) |
+ NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);
+
+ ret = wait_event_interruptible_timeout(info->wq, info->int_status,
+ msecs_to_jiffies(10));
+ if (ret == 0) {
+ regtemp = ioread32(info->regs + NPCM_ADCCON);
+ if ((regtemp & NPCM_ADCCON_ADC_CONV) && info->rst_regmap) {
+ /* if conversion failed - reset ADC module */
+ regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
+ NPCM7XX_IPSRST1_ADC_RST);
+ msleep(100);
+ regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
+ 0x0);
+ msleep(100);
+
+ /* Enable ADC and start conversion module */
+ iowrite32(NPCM_ADC_ENABLE | NPCM_ADCCON_ADC_CONV,
+ info->regs + NPCM_ADCCON);
+ dev_err(info->dev, "RESET ADC Complete\n");
+ }
+ return -ETIMEDOUT;
+ }
+ if (ret < 0)
+ return ret;
+
+ *val = NPCM_ADC_DATA_MASK(ioread32(info->regs + NPCM_ADCDATA));
+
+ return 0;
+}
+
+static int npcm_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ int vref_uv;
+ struct npcm_adc *info = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ ret = npcm_adc_read(info, val, chan->channel);
+ mutex_unlock(&indio_dev->mlock);
+ if (ret) {
+ dev_err(info->dev, "NPCM ADC read failed\n");
+ return ret;
+ }
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ if (info->vref) {
+ vref_uv = regulator_get_voltage(info->vref);
+ *val = vref_uv / 1000;
+ } else {
+ *val = NPCM_INT_VREF_MV;
+ }
+ *val2 = NPCM_RESOLUTION_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = info->adc_sample_hz;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct iio_info npcm_adc_iio_info = {
+ .read_raw = &npcm_adc_read_raw,
+};
+
+static const struct of_device_id npcm_adc_match[] = {
+ { .compatible = "nuvoton,npcm750-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, npcm_adc_match);
+
+static int npcm_adc_probe(struct platform_device *pdev)
+{
+ int ret;
+ int irq;
+ u32 div;
+ u32 reg_con;
+ struct resource *res;
+ struct npcm_adc *info;
+ struct iio_dev *indio_dev;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+ info = iio_priv(indio_dev);
+
+ info->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ info->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
+
+ info->adc_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(info->adc_clk)) {
+ dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
+ return PTR_ERR(info->adc_clk);
+ }
+
+ /* calculate ADC clock sample rate */
+ reg_con = ioread32(info->regs + NPCM_ADCCON);
+ div = reg_con & NPCM_ADCCON_DIV_MASK;
+ div = div >> NPCM_ADCCON_DIV_SHIFT;
+ info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
+
+ if (of_device_is_compatible(np, "nuvoton,npcm750-adc")) {
+ info->rst_regmap = syscon_regmap_lookup_by_compatible
+ ("nuvoton,npcm750-rst");
+ if (IS_ERR(info->rst_regmap)) {
+ dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-rst\n");
+ ret = PTR_ERR(info->rst_regmap);
+ goto err_disable_clk;
+ }
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "failed getting interrupt resource\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
+ "NPCM_ADC", indio_dev);
+ if (ret < 0) {
+ dev_err(dev, "failed requesting interrupt\n");
+ goto err_disable_clk;
+ }
+
+ reg_con = ioread32(info->regs + NPCM_ADCCON);
+ info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
+ if (!IS_ERR(info->vref)) {
+ ret = regulator_enable(info->vref);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
+ goto err_disable_clk;
+ }
+
+ iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
+ info->regs + NPCM_ADCCON);
+ } else {
+ /*
+ * Any error which is not ENODEV indicates the regulator
+ * has been specified and so is a failure case.
+ */
+ if (PTR_ERR(info->vref) != -ENODEV) {
+ ret = PTR_ERR(info->vref);
+ goto err_disable_clk;
+ }
+
+ /* Use internal reference */
+ iowrite32(reg_con | NPCM_ADCCON_REFSEL,
+ info->regs + NPCM_ADCCON);
+ }
+
+ init_waitqueue_head(&info->wq);
+
+ reg_con = ioread32(info->regs + NPCM_ADCCON);
+ reg_con |= NPCM_ADC_ENABLE;
+
+ /* Enable the ADC Module */
+ iowrite32(reg_con, info->regs + NPCM_ADCCON);
+
+ /* Start ADC conversion */
+ iowrite32(reg_con | NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);
+
+ platform_set_drvdata(pdev, indio_dev);
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &npcm_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = npcm_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(npcm_adc_iio_channels);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto err_iio_register;
+ }
+
+ pr_info("NPCM ADC driver probed\n");
+
+ return 0;
+
+err_iio_register:
+ iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
+ if (!IS_ERR(info->vref))
+ regulator_disable(info->vref);
+err_disable_clk:
+ clk_disable_unprepare(info->adc_clk);
+
+ return ret;
+}
+
+static int npcm_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct npcm_adc *info = iio_priv(indio_dev);
+ u32 regtemp;
+
+ iio_device_unregister(indio_dev);
+
+ regtemp = ioread32(info->regs + NPCM_ADCCON);
+ iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
+ if (!IS_ERR(info->vref))
+ regulator_disable(info->vref);
+ clk_disable_unprepare(info->adc_clk);
+
+ return 0;
+}
+
+static struct platform_driver npcm_adc_driver = {
+ .probe = npcm_adc_probe,
+ .remove = npcm_adc_remove,
+ .driver = {
+ .name = "npcm_adc",
+ .of_match_table = npcm_adc_match,
+ },
+};
+
+module_platform_driver(npcm_adc_driver);
+
+MODULE_DESCRIPTION("Nuvoton NPCM ADC Driver");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
new file mode 100644
index 000000000000..53f17e4f2f23
--- /dev/null
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+/* TI ADS124S0X chip family driver
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/sysfs.h>
+
+/* Commands */
+#define ADS124S08_CMD_NOP 0x00
+#define ADS124S08_CMD_WAKEUP 0x02
+#define ADS124S08_CMD_PWRDWN 0x04
+#define ADS124S08_CMD_RESET 0x06
+#define ADS124S08_CMD_START 0x08
+#define ADS124S08_CMD_STOP 0x0a
+#define ADS124S08_CMD_SYOCAL 0x16
+#define ADS124S08_CMD_SYGCAL 0x17
+#define ADS124S08_CMD_SFOCAL 0x19
+#define ADS124S08_CMD_RDATA 0x12
+#define ADS124S08_CMD_RREG 0x20
+#define ADS124S08_CMD_WREG 0x40
+
+/* Registers */
+#define ADS124S08_ID_REG 0x00
+#define ADS124S08_STATUS 0x01
+#define ADS124S08_INPUT_MUX 0x02
+#define ADS124S08_PGA 0x03
+#define ADS124S08_DATA_RATE 0x04
+#define ADS124S08_REF 0x05
+#define ADS124S08_IDACMAG 0x06
+#define ADS124S08_IDACMUX 0x07
+#define ADS124S08_VBIAS 0x08
+#define ADS124S08_SYS 0x09
+#define ADS124S08_OFCAL0 0x0a
+#define ADS124S08_OFCAL1 0x0b
+#define ADS124S08_OFCAL2 0x0c
+#define ADS124S08_FSCAL0 0x0d
+#define ADS124S08_FSCAL1 0x0e
+#define ADS124S08_FSCAL2 0x0f
+#define ADS124S08_GPIODAT 0x10
+#define ADS124S08_GPIOCON 0x11
+
+/* ADS124S0x common channels */
+#define ADS124S08_AIN0 0x00
+#define ADS124S08_AIN1 0x01
+#define ADS124S08_AIN2 0x02
+#define ADS124S08_AIN3 0x03
+#define ADS124S08_AIN4 0x04
+#define ADS124S08_AIN5 0x05
+#define ADS124S08_AINCOM 0x0c
+/* ADS124S08 only channels */
+#define ADS124S08_AIN6 0x06
+#define ADS124S08_AIN7 0x07
+#define ADS124S08_AIN8 0x08
+#define ADS124S08_AIN9 0x09
+#define ADS124S08_AIN10 0x0a
+#define ADS124S08_AIN11 0x0b
+#define ADS124S08_MAX_CHANNELS 12
+
+#define ADS124S08_POS_MUX_SHIFT 0x04
+#define ADS124S08_INT_REF 0x09
+
+#define ADS124S08_START_REG_MASK 0x1f
+#define ADS124S08_NUM_BYTES_MASK 0x1f
+
+#define ADS124S08_START_CONV 0x01
+#define ADS124S08_STOP_CONV 0x00
+
+enum ads124s_id {
+ ADS124S08_ID,
+ ADS124S06_ID,
+};
+
+struct ads124s_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct ads124s_private {
+ const struct ads124s_chip_info *chip_info;
+ struct gpio_desc *reset_gpio;
+ struct spi_device *spi;
+ struct mutex lock;
+ u8 data[5] ____cacheline_aligned;
+};
+
+#define ADS124S08_CHAN(index) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 32, \
+ .storagebits = 32, \
+ }, \
+}
+
+static const struct iio_chan_spec ads124s06_channels[] = {
+ ADS124S08_CHAN(0),
+ ADS124S08_CHAN(1),
+ ADS124S08_CHAN(2),
+ ADS124S08_CHAN(3),
+ ADS124S08_CHAN(4),
+ ADS124S08_CHAN(5),
+};
+
+static const struct iio_chan_spec ads124s08_channels[] = {
+ ADS124S08_CHAN(0),
+ ADS124S08_CHAN(1),
+ ADS124S08_CHAN(2),
+ ADS124S08_CHAN(3),
+ ADS124S08_CHAN(4),
+ ADS124S08_CHAN(5),
+ ADS124S08_CHAN(6),
+ ADS124S08_CHAN(7),
+ ADS124S08_CHAN(8),
+ ADS124S08_CHAN(9),
+ ADS124S08_CHAN(10),
+ ADS124S08_CHAN(11),
+};
+
+static const struct ads124s_chip_info ads124s_chip_info_tbl[] = {
+ [ADS124S08_ID] = {
+ .channels = ads124s08_channels,
+ .num_channels = ARRAY_SIZE(ads124s08_channels),
+ },
+ [ADS124S06_ID] = {
+ .channels = ads124s06_channels,
+ .num_channels = ARRAY_SIZE(ads124s06_channels),
+ },
+};
+
+static int ads124s_write_cmd(struct iio_dev *indio_dev, u8 command)
+{
+ struct ads124s_private *priv = iio_priv(indio_dev);
+
+ priv->data[0] = command;
+
+ return spi_write(priv->spi, &priv->data[0], 1);
+}
+
+static int ads124s_write_reg(struct iio_dev *indio_dev, u8 reg, u8 data)
+{
+ struct ads124s_private *priv = iio_priv(indio_dev);
+
+ priv->data[0] = ADS124S08_CMD_WREG | reg;
+ priv->data[1] = 0x0;
+ priv->data[2] = data;
+
+ return spi_write(priv->spi, &priv->data[0], 3);
+}
+
+static int ads124s_reset(struct iio_dev *indio_dev)
+{
+ struct ads124s_private *priv = iio_priv(indio_dev);
+
+ if (priv->reset_gpio) {
+ gpiod_set_value(priv->reset_gpio, 0);
+ udelay(200);
+ gpiod_set_value(priv->reset_gpio, 1);
+ } else {
+ return ads124s_write_cmd(indio_dev, ADS124S08_CMD_RESET);
+ }
+
+ return 0;
+};
+
+static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan)
+{
+ struct ads124s_private *priv = iio_priv(indio_dev);
+ int ret;
+ u32 tmp;
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &priv->data[0],
+ .len = 4,
+ .cs_change = 1,
+ }, {
+ .tx_buf = &priv->data[1],
+ .rx_buf = &priv->data[1],
+ .len = 4,
+ },
+ };
+
+ priv->data[0] = ADS124S08_CMD_RDATA;
+ memset(&priv->data[1], ADS124S08_CMD_NOP, sizeof(priv->data));
+
+ ret = spi_sync_transfer(priv->spi, t, ARRAY_SIZE(t));
+ if (ret < 0)
+ return ret;
+
+ tmp = priv->data[2] << 16 | priv->data[3] << 8 | priv->data[4];
+
+ return tmp;
+}
+
+static int ads124s_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long m)
+{
+ struct ads124s_private *priv = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&priv->lock);
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX,
+ chan->channel);
+ if (ret) {
+ dev_err(&priv->spi->dev, "Set ADC CH failed\n");
+ goto out;
+ }
+
+ ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
+ if (ret) {
+ dev_err(&priv->spi->dev, "Start conversions failed\n");
+ goto out;
+ }
+
+ ret = ads124s_read(indio_dev, chan->channel);
+ if (ret < 0) {
+ dev_err(&priv->spi->dev, "Read ADC failed\n");
+ goto out;
+ }
+
+ *val = ret;
+
+ ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
+ if (ret) {
+ dev_err(&priv->spi->dev, "Stop conversions failed\n");
+ goto out;
+ }
+
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+out:
+ mutex_unlock(&priv->lock);
+ return ret;
+}
+
+static const struct iio_info ads124s_info = {
+ .read_raw = &ads124s_read_raw,
+};
+
+static irqreturn_t ads124s_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ads124s_private *priv = iio_priv(indio_dev);
+ u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
+ int scan_index, j = 0;
+ int ret;
+
+ for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+ ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX,
+ scan_index);
+ if (ret)
+ dev_err(&priv->spi->dev, "Set ADC CH failed\n");
+
+ ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
+ if (ret)
+ dev_err(&priv->spi->dev, "Start ADC conversions failed\n");
+
+ buffer[j] = ads124s_read(indio_dev, scan_index);
+ ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
+ if (ret)
+ dev_err(&priv->spi->dev, "Stop ADC conversions failed\n");
+
+ j++;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ pf->timestamp);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ads124s_probe(struct spi_device *spi)
+{
+ struct ads124s_private *ads124s_priv;
+ struct iio_dev *indio_dev;
+ const struct spi_device_id *spi_id = spi_get_device_id(spi);
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ads124s_priv));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ ads124s_priv = iio_priv(indio_dev);
+
+ ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ads124s_priv->reset_gpio))
+ dev_info(&spi->dev, "Reset GPIO not defined\n");
+
+ ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];
+
+ spi_set_drvdata(spi, indio_dev);
+
+ ads124s_priv->spi = spi;
+
+ indio_dev->name = spi_id->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->dev.of_node = spi->dev.of_node;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ads124s_priv->chip_info->channels;
+ indio_dev->num_channels = ads124s_priv->chip_info->num_channels;
+ indio_dev->info = &ads124s_info;
+
+ mutex_init(&ads124s_priv->lock);
+
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+ ads124s_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&spi->dev, "iio triggered buffer setup failed\n");
+ return ret;
+ }
+
+ ads124s_reset(indio_dev);
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ads124s_id[] = {
+ { "ads124s06", ADS124S06_ID },
+ { "ads124s08", ADS124S08_ID },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ads124s_id);
+
+static const struct of_device_id ads124s_of_table[] = {
+ { .compatible = "ti,ads124s06" },
+ { .compatible = "ti,ads124s08" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ads124s_of_table);
+
+static struct spi_driver ads124s_driver = {
+ .driver = {
+ .name = "ads124s08",
+ .of_match_table = ads124s_of_table,
+ },
+ .probe = ads124s_probe,
+ .id_table = ads124s_id,
+};
+module_spi_driver(ads124s_driver);
+
+MODULE_AUTHOR("Dan Murphy <dmuprhy@ti.com>");
+MODULE_DESCRIPTION("TI TI_ADS12S0X ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index 3f6be5ac049a..b13c61539d46 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -1273,8 +1273,10 @@ static int xadc_probe(struct platform_device *pdev)
xadc->threshold[i] = 0xffff;
else
xadc->threshold[i] = 0;
- xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
+ ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
xadc->threshold[i]);
+ if (ret)
+ goto err_free_irq;
}
/* Go to non-buffered mode */
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index b8e005be4f87..d5d146e9e372 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -61,6 +61,27 @@ config IAQCORE
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
sensors
+config PMS7003
+ tristate "Plantower PMS7003 particulate matter sensor"
+ depends on SERIAL_DEV_BUS
+ help
+ Say Y here to build support for the Plantower PMS7003 particulate
+ matter sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called pms7003.
+
+config SPS30
+ tristate "SPS30 particulate matter sensor"
+ depends on I2C
+ select CRC8
+ help
+ Say Y here to build support for the Sensirion SPS30 particulate
+ matter sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called sps30.
+
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 2f4c4ba4d781..f5d1365acb49 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -9,4 +9,7 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
+obj-$(CONFIG_PMS7003) += pms7003.o
+obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
+obj-$(CONFIG_SPS30) += sps30.o
obj-$(CONFIG_VZ89X) += vz89x.o
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index 06d4be539d2e..b2f805b6b36a 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -70,10 +70,17 @@ static const struct acpi_device_id bme680_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
+static const struct of_device_id bme680_of_i2c_match[] = {
+ { .compatible = "bosch,bme680", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bme680_of_i2c_match);
+
static struct i2c_driver bme680_i2c_driver = {
.driver = {
.name = "bme680_i2c",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
+ .of_match_table = bme680_of_i2c_match,
},
.probe = bme680_i2c_probe,
.id_table = bme680_i2c_id,
diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c
index c9fb05e8d0b9..d0b7bdd3f066 100644
--- a/drivers/iio/chemical/bme680_spi.c
+++ b/drivers/iio/chemical/bme680_spi.c
@@ -6,6 +6,7 @@
*/
#include <linux/acpi.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -110,10 +111,17 @@ static const struct acpi_device_id bme680_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
+static const struct of_device_id bme680_of_spi_match[] = {
+ { .compatible = "bosch,bme680", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
+
static struct spi_driver bme680_spi_driver = {
.driver = {
.name = "bme680_spi",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
+ .of_match_table = bme680_of_spi_match,
},
.probe = bme680_spi_probe,
.id_table = bme680_spi_id,
diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c
new file mode 100644
index 000000000000..db8e7b2327b3
--- /dev/null
+++ b/drivers/iio/chemical/pms7003.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Plantower PMS7003 particulate matter sensor driver
+ *
+ * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/serdev.h>
+
+#define PMS7003_DRIVER_NAME "pms7003"
+
+#define PMS7003_MAGIC 0x424d
+/* last 2 data bytes hold frame checksum */
+#define PMS7003_MAX_DATA_LENGTH 28
+#define PMS7003_CHECKSUM_LENGTH 2
+#define PMS7003_PM10_OFFSET 10
+#define PMS7003_PM2P5_OFFSET 8
+#define PMS7003_PM1_OFFSET 6
+
+#define PMS7003_TIMEOUT msecs_to_jiffies(6000)
+#define PMS7003_CMD_LENGTH 7
+#define PMS7003_PM_MAX 1000
+#define PMS7003_PM_MIN 0
+
+enum {
+ PM1,
+ PM2P5,
+ PM10,
+};
+
+enum pms7003_cmd {
+ CMD_WAKEUP,
+ CMD_ENTER_PASSIVE_MODE,
+ CMD_READ_PASSIVE,
+ CMD_SLEEP,
+};
+
+/*
+ * commands have following format:
+ *
+ * +------+------+-----+------+-----+-----------+-----------+
+ * | 0x42 | 0x4d | cmd | 0x00 | arg | cksum msb | cksum lsb |
+ * +------+------+-----+------+-----+-----------+-----------+
+ */
+static const u8 pms7003_cmd_tbl[][PMS7003_CMD_LENGTH] = {
+ [CMD_WAKEUP] = { 0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74 },
+ [CMD_ENTER_PASSIVE_MODE] = { 0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70 },
+ [CMD_READ_PASSIVE] = { 0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71 },
+ [CMD_SLEEP] = { 0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73 },
+};
+
+struct pms7003_frame {
+ u8 data[PMS7003_MAX_DATA_LENGTH];
+ u16 expected_length;
+ u16 length;
+};
+
+struct pms7003_state {
+ struct serdev_device *serdev;
+ struct pms7003_frame frame;
+ struct completion frame_ready;
+ struct mutex lock; /* must be held whenever state gets touched */
+};
+
+static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
+{
+ int ret;
+
+ ret = serdev_device_write(state->serdev, pms7003_cmd_tbl[cmd],
+ PMS7003_CMD_LENGTH, PMS7003_TIMEOUT);
+ if (ret < PMS7003_CMD_LENGTH)
+ return ret < 0 ? ret : -EIO;
+
+ ret = wait_for_completion_interruptible_timeout(&state->frame_ready,
+ PMS7003_TIMEOUT);
+ if (!ret)
+ ret = -ETIMEDOUT;
+
+ return ret < 0 ? ret : 0;
+}
+
+static u16 pms7003_get_pm(const u8 *data)
+{
+ return clamp_val(get_unaligned_be16(data),
+ PMS7003_PM_MIN, PMS7003_PM_MAX);
+}
+
+static irqreturn_t pms7003_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct pms7003_state *state = iio_priv(indio_dev);
+ struct pms7003_frame *frame = &state->frame;
+ u16 data[3 + 1 + 4]; /* PM1, PM2P5, PM10, padding, timestamp */
+ int ret;
+
+ mutex_lock(&state->lock);
+ ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
+ if (ret) {
+ mutex_unlock(&state->lock);
+ goto err;
+ }
+
+ data[PM1] = pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
+ data[PM2P5] = pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
+ data[PM10] = pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
+ mutex_unlock(&state->lock);
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data,
+ iio_get_time_ns(indio_dev));
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int pms7003_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct pms7003_state *state = iio_priv(indio_dev);
+ struct pms7003_frame *frame = &state->frame;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_MASSCONCENTRATION:
+ mutex_lock(&state->lock);
+ ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
+ if (ret) {
+ mutex_unlock(&state->lock);
+ return ret;
+ }
+
+ *val = pms7003_get_pm(frame->data + chan->address);
+ mutex_unlock(&state->lock);
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info pms7003_info = {
+ .read_raw = pms7003_read_raw,
+};
+
+#define PMS7003_CHAN(_index, _mod, _addr) { \
+ .type = IIO_MASSCONCENTRATION, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _mod, \
+ .address = _addr, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 10, \
+ .storagebits = 16, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+static const struct iio_chan_spec pms7003_channels[] = {
+ PMS7003_CHAN(0, PM1, PMS7003_PM1_OFFSET),
+ PMS7003_CHAN(1, PM2P5, PMS7003_PM2P5_OFFSET),
+ PMS7003_CHAN(2, PM10, PMS7003_PM10_OFFSET),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static u16 pms7003_calc_checksum(struct pms7003_frame *frame)
+{
+ u16 checksum = (PMS7003_MAGIC >> 8) + (u8)(PMS7003_MAGIC & 0xff) +
+ (frame->length >> 8) + (u8)frame->length;
+ int i;
+
+ for (i = 0; i < frame->length - PMS7003_CHECKSUM_LENGTH; i++)
+ checksum += frame->data[i];
+
+ return checksum;
+}
+
+static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
+{
+ int offset = frame->length - PMS7003_CHECKSUM_LENGTH;
+ u16 checksum = get_unaligned_be16(frame->data + offset);
+
+ return checksum == pms7003_calc_checksum(frame);
+}
+
+static int pms7003_receive_buf(struct serdev_device *serdev,
+ const unsigned char *buf, size_t size)
+{
+ struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
+ struct pms7003_state *state = iio_priv(indio_dev);
+ struct pms7003_frame *frame = &state->frame;
+ int num;
+
+ if (!frame->expected_length) {
+ u16 magic;
+
+ /* wait for SOF and data length */
+ if (size < 4)
+ return 0;
+
+ magic = get_unaligned_be16(buf);
+ if (magic != PMS7003_MAGIC)
+ return 2;
+
+ num = get_unaligned_be16(buf + 2);
+ if (num <= PMS7003_MAX_DATA_LENGTH) {
+ frame->expected_length = num;
+ frame->length = 0;
+ }
+
+ return 4;
+ }
+
+ num = min(size, (size_t)(frame->expected_length - frame->length));
+ memcpy(frame->data + frame->length, buf, num);
+ frame->length += num;
+
+ if (frame->length == frame->expected_length) {
+ if (pms7003_frame_is_okay(frame))
+ complete(&state->frame_ready);
+
+ frame->expected_length = 0;
+ }
+
+ return num;
+}
+
+static const struct serdev_device_ops pms7003_serdev_ops = {
+ .receive_buf = pms7003_receive_buf,
+ .write_wakeup = serdev_device_write_wakeup,
+};
+
+static void pms7003_stop(void *data)
+{
+ struct pms7003_state *state = data;
+
+ pms7003_do_cmd(state, CMD_SLEEP);
+}
+
+static const unsigned long pms7003_scan_masks[] = { 0x07, 0x00 };
+
+static int pms7003_probe(struct serdev_device *serdev)
+{
+ struct pms7003_state *state;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&serdev->dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+ serdev_device_set_drvdata(serdev, indio_dev);
+ state->serdev = serdev;
+ indio_dev->dev.parent = &serdev->dev;
+ indio_dev->info = &pms7003_info;
+ indio_dev->name = PMS7003_DRIVER_NAME;
+ indio_dev->channels = pms7003_channels,
+ indio_dev->num_channels = ARRAY_SIZE(pms7003_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->available_scan_masks = pms7003_scan_masks;
+
+ mutex_init(&state->lock);
+ init_completion(&state->frame_ready);
+
+ serdev_device_set_client_ops(serdev, &pms7003_serdev_ops);
+ ret = devm_serdev_device_open(&serdev->dev, serdev);
+ if (ret)
+ return ret;
+
+ serdev_device_set_baudrate(serdev, 9600);
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+ if (ret)
+ return ret;
+
+ ret = pms7003_do_cmd(state, CMD_WAKEUP);
+ if (ret) {
+ dev_err(&serdev->dev, "failed to wakeup sensor\n");
+ return ret;
+ }
+
+ ret = pms7003_do_cmd(state, CMD_ENTER_PASSIVE_MODE);
+ if (ret) {
+ dev_err(&serdev->dev, "failed to enter passive mode\n");
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&serdev->dev, pms7003_stop, state);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(&serdev->dev, indio_dev, NULL,
+ pms7003_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&serdev->dev, indio_dev);
+}
+
+static const struct of_device_id pms7003_of_match[] = {
+ { .compatible = "plantower,pms7003" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pms7003_of_match);
+
+static struct serdev_device_driver pms7003_driver = {
+ .driver = {
+ .name = PMS7003_DRIVER_NAME,
+ .of_match_table = pms7003_of_match,
+ },
+ .probe = pms7003_probe,
+};
+module_serdev_device_driver(pms7003_driver);
+
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
+MODULE_DESCRIPTION("Plantower PMS7003 particulate matter sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c
new file mode 100644
index 000000000000..8cc8fe5e356d
--- /dev/null
+++ b/drivers/iio/chemical/sgp30.c
@@ -0,0 +1,591 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sgp30.c - Support for Sensirion SGP Gas Sensors
+ *
+ * Copyright (C) 2018 Andreas Brauchli <andreas.brauchli@sensirion.com>
+ *
+ * I2C slave address: 0x58
+ *
+ * Datasheets:
+ * https://www.sensirion.com/file/datasheet_sgp30
+ * https://www.sensirion.com/file/datasheet_sgpc3
+ *
+ * TODO:
+ * - baseline support
+ * - humidity compensation
+ * - power mode switching (SGPC3)
+ */
+
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define SGP_WORD_LEN 2
+#define SGP_CRC8_POLYNOMIAL 0x31
+#define SGP_CRC8_INIT 0xff
+#define SGP_CRC8_LEN 1
+#define SGP_CMD(cmd_word) cpu_to_be16(cmd_word)
+#define SGP_CMD_DURATION_US 12000
+#define SGP_MEASUREMENT_DURATION_US 50000
+#define SGP_CMD_LEN SGP_WORD_LEN
+#define SGP_CMD_MAX_BUF_SIZE (SGP_CMD_LEN + 2 * SGP_WORD_LEN)
+#define SGP_MEASUREMENT_LEN 2
+#define SGP30_MEASURE_INTERVAL_HZ 1
+#define SGPC3_MEASURE_INTERVAL_HZ 2
+#define SGP_VERS_PRODUCT(data) ((((data)->feature_set) & 0xf000) >> 12)
+#define SGP_VERS_RESERVED(data) ((((data)->feature_set) & 0x0800) >> 11)
+#define SGP_VERS_GEN(data) ((((data)->feature_set) & 0x0600) >> 9)
+#define SGP_VERS_ENG_BIT(data) ((((data)->feature_set) & 0x0100) >> 8)
+#define SGP_VERS_MAJOR(data) ((((data)->feature_set) & 0x00e0) >> 5)
+#define SGP_VERS_MINOR(data) (((data)->feature_set) & 0x001f)
+
+DECLARE_CRC8_TABLE(sgp_crc8_table);
+
+enum sgp_product_id {
+ SGP30 = 0,
+ SGPC3,
+};
+
+enum sgp30_channel_idx {
+ SGP30_IAQ_TVOC_IDX = 0,
+ SGP30_IAQ_CO2EQ_IDX,
+ SGP30_SIG_ETOH_IDX,
+ SGP30_SIG_H2_IDX,
+};
+
+enum sgpc3_channel_idx {
+ SGPC3_IAQ_TVOC_IDX = 10,
+ SGPC3_SIG_ETOH_IDX,
+};
+
+enum sgp_cmd {
+ SGP_CMD_IAQ_INIT = SGP_CMD(0x2003),
+ SGP_CMD_IAQ_MEASURE = SGP_CMD(0x2008),
+ SGP_CMD_GET_FEATURE_SET = SGP_CMD(0x202f),
+ SGP_CMD_GET_SERIAL_ID = SGP_CMD(0x3682),
+
+ SGP30_CMD_MEASURE_SIGNAL = SGP_CMD(0x2050),
+
+ SGPC3_CMD_MEASURE_RAW = SGP_CMD(0x2046),
+};
+
+struct sgp_version {
+ u8 major;
+ u8 minor;
+};
+
+struct sgp_crc_word {
+ __be16 value;
+ u8 crc8;
+} __attribute__((__packed__));
+
+union sgp_reading {
+ u8 start;
+ struct sgp_crc_word raw_words[4];
+};
+
+enum _iaq_buffer_state {
+ IAQ_BUFFER_EMPTY = 0,
+ IAQ_BUFFER_DEFAULT_VALS,
+ IAQ_BUFFER_VALID,
+};
+
+struct sgp_data {
+ struct i2c_client *client;
+ struct task_struct *iaq_thread;
+ struct mutex data_lock;
+ unsigned long iaq_init_start_jiffies;
+ unsigned long iaq_defval_skip_jiffies;
+ u16 product_id;
+ u16 feature_set;
+ unsigned long measure_interval_jiffies;
+ enum sgp_cmd iaq_init_cmd;
+ enum sgp_cmd measure_iaq_cmd;
+ enum sgp_cmd measure_gas_signals_cmd;
+ union sgp_reading buffer;
+ union sgp_reading iaq_buffer;
+ enum _iaq_buffer_state iaq_buffer_state;
+};
+
+struct sgp_device {
+ const struct iio_chan_spec *channels;
+ int num_channels;
+};
+
+static const struct sgp_version supported_versions_sgp30[] = {
+ {
+ .major = 1,
+ .minor = 0,
+ },
+};
+
+static const struct sgp_version supported_versions_sgpc3[] = {
+ {
+ .major = 0,
+ .minor = 4,
+ },
+};
+
+static const struct iio_chan_spec sgp30_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = SGP30_IAQ_TVOC_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = SGP30_IAQ_CO2EQ_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_ETHANOL,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .address = SGP30_SIG_ETOH_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_H2,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .address = SGP30_SIG_H2_IDX,
+ },
+};
+
+static const struct iio_chan_spec sgpc3_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .address = SGPC3_IAQ_TVOC_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_ETHANOL,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .address = SGPC3_SIG_ETOH_IDX,
+ },
+};
+
+static const struct sgp_device sgp_devices[] = {
+ [SGP30] = {
+ .channels = sgp30_channels,
+ .num_channels = ARRAY_SIZE(sgp30_channels),
+ },
+ [SGPC3] = {
+ .channels = sgpc3_channels,
+ .num_channels = ARRAY_SIZE(sgpc3_channels),
+ },
+};
+
+/**
+ * sgp_verify_buffer() - verify the checksums of the data buffer words
+ *
+ * @data: SGP data
+ * @buf: Raw data buffer
+ * @word_count: Num data words stored in the buffer, excluding CRC bytes
+ *
+ * Return: 0 on success, negative error otherwise.
+ */
+static int sgp_verify_buffer(const struct sgp_data *data,
+ union sgp_reading *buf, size_t word_count)
+{
+ size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN);
+ int i;
+ u8 crc;
+ u8 *data_buf = &buf->start;
+
+ for (i = 0; i < size; i += SGP_WORD_LEN + SGP_CRC8_LEN) {
+ crc = crc8(sgp_crc8_table, &data_buf[i], SGP_WORD_LEN,
+ SGP_CRC8_INIT);
+ if (crc != data_buf[i + SGP_WORD_LEN]) {
+ dev_err(&data->client->dev, "CRC error\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * sgp_read_cmd() - reads data from sensor after issuing a command
+ * The caller must hold data->data_lock for the duration of the call.
+ * @data: SGP data
+ * @cmd: SGP Command to issue
+ * @buf: Raw data buffer to use
+ * @word_count: Num words to read, excluding CRC bytes
+ *
+ * Return: 0 on success, negative error otherwise.
+ */
+static int sgp_read_cmd(struct sgp_data *data, enum sgp_cmd cmd,
+ union sgp_reading *buf, size_t word_count,
+ unsigned long duration_us)
+{
+ int ret;
+ struct i2c_client *client = data->client;
+ size_t size = word_count * (SGP_WORD_LEN + SGP_CRC8_LEN);
+ u8 *data_buf;
+
+ ret = i2c_master_send(client, (const char *)&cmd, SGP_CMD_LEN);
+ if (ret != SGP_CMD_LEN)
+ return -EIO;
+ usleep_range(duration_us, duration_us + 1000);
+
+ if (word_count == 0)
+ return 0;
+
+ data_buf = &buf->start;
+ ret = i2c_master_recv(client, data_buf, size);
+ if (ret < 0)
+ return ret;
+ if (ret != size)
+ return -EIO;
+
+ return sgp_verify_buffer(data, buf, word_count);
+}
+
+/**
+ * sgp_measure_iaq() - measure and retrieve IAQ values from sensor
+ * The caller must hold data->data_lock for the duration of the call.
+ * @data: SGP data
+ *
+ * Return: 0 on success, -EBUSY on default values, negative error
+ * otherwise.
+ */
+
+static int sgp_measure_iaq(struct sgp_data *data)
+{
+ int ret;
+ /* data contains default values */
+ bool default_vals = !time_after(jiffies, data->iaq_init_start_jiffies +
+ data->iaq_defval_skip_jiffies);
+
+ ret = sgp_read_cmd(data, data->measure_iaq_cmd, &data->iaq_buffer,
+ SGP_MEASUREMENT_LEN, SGP_MEASUREMENT_DURATION_US);
+ if (ret < 0)
+ return ret;
+
+ data->iaq_buffer_state = IAQ_BUFFER_DEFAULT_VALS;
+
+ if (default_vals)
+ return -EBUSY;
+
+ data->iaq_buffer_state = IAQ_BUFFER_VALID;
+
+ return 0;
+}
+
+static void sgp_iaq_thread_sleep_until(const struct sgp_data *data,
+ unsigned long sleep_jiffies)
+{
+ const long IAQ_POLL = 50000;
+
+ while (!time_after(jiffies, sleep_jiffies)) {
+ usleep_range(IAQ_POLL, IAQ_POLL + 10000);
+ if (kthread_should_stop() || data->iaq_init_start_jiffies == 0)
+ return;
+ }
+}
+
+static int sgp_iaq_threadfn(void *p)
+{
+ struct sgp_data *data = (struct sgp_data *)p;
+ unsigned long next_update_jiffies;
+ int ret;
+
+ while (!kthread_should_stop()) {
+ mutex_lock(&data->data_lock);
+ if (data->iaq_init_start_jiffies == 0) {
+ ret = sgp_read_cmd(data, data->iaq_init_cmd, NULL, 0,
+ SGP_CMD_DURATION_US);
+ if (ret < 0)
+ goto unlock_sleep_continue;
+ data->iaq_init_start_jiffies = jiffies;
+ }
+
+ ret = sgp_measure_iaq(data);
+ if (ret && ret != -EBUSY) {
+ dev_warn(&data->client->dev,
+ "IAQ measurement error [%d]\n", ret);
+ }
+unlock_sleep_continue:
+ next_update_jiffies = jiffies + data->measure_interval_jiffies;
+ mutex_unlock(&data->data_lock);
+ sgp_iaq_thread_sleep_until(data, next_update_jiffies);
+ }
+
+ return 0;
+}
+
+static int sgp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct sgp_data *data = iio_priv(indio_dev);
+ struct sgp_crc_word *words;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ mutex_lock(&data->data_lock);
+ if (data->iaq_buffer_state != IAQ_BUFFER_VALID) {
+ mutex_unlock(&data->data_lock);
+ return -EBUSY;
+ }
+ words = data->iaq_buffer.raw_words;
+ switch (chan->address) {
+ case SGP30_IAQ_TVOC_IDX:
+ case SGPC3_IAQ_TVOC_IDX:
+ *val = 0;
+ *val2 = be16_to_cpu(words[1].value);
+ ret = IIO_VAL_INT_PLUS_NANO;
+ break;
+ case SGP30_IAQ_CO2EQ_IDX:
+ *val = 0;
+ *val2 = be16_to_cpu(words[0].value);
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&data->data_lock);
+ break;
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->data_lock);
+ if (chan->address == SGPC3_SIG_ETOH_IDX) {
+ if (data->iaq_buffer_state == IAQ_BUFFER_EMPTY)
+ ret = -EBUSY;
+ else
+ ret = 0;
+ words = data->iaq_buffer.raw_words;
+ } else {
+ ret = sgp_read_cmd(data, data->measure_gas_signals_cmd,
+ &data->buffer, SGP_MEASUREMENT_LEN,
+ SGP_MEASUREMENT_DURATION_US);
+ words = data->buffer.raw_words;
+ }
+ if (ret) {
+ mutex_unlock(&data->data_lock);
+ return ret;
+ }
+
+ switch (chan->address) {
+ case SGP30_SIG_ETOH_IDX:
+ *val = be16_to_cpu(words[1].value);
+ ret = IIO_VAL_INT;
+ break;
+ case SGPC3_SIG_ETOH_IDX:
+ case SGP30_SIG_H2_IDX:
+ *val = be16_to_cpu(words[0].value);
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&data->data_lock);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int sgp_check_compat(struct sgp_data *data,
+ unsigned int product_id)
+{
+ const struct sgp_version *supported_versions;
+ u16 ix, num_fs;
+ u16 product, generation, major, minor;
+
+ /* driver does not match product */
+ generation = SGP_VERS_GEN(data);
+ if (generation != 0) {
+ dev_err(&data->client->dev,
+ "incompatible product generation %d != 0", generation);
+ return -ENODEV;
+ }
+
+ product = SGP_VERS_PRODUCT(data);
+ if (product != product_id) {
+ dev_err(&data->client->dev,
+ "sensor reports a different product: 0x%04hx\n",
+ product);
+ return -ENODEV;
+ }
+
+ if (SGP_VERS_RESERVED(data))
+ dev_warn(&data->client->dev, "reserved bit is set\n");
+
+ /* engineering samples are not supported: no interface guarantees */
+ if (SGP_VERS_ENG_BIT(data))
+ return -ENODEV;
+
+ switch (product) {
+ case SGP30:
+ supported_versions = supported_versions_sgp30;
+ num_fs = ARRAY_SIZE(supported_versions_sgp30);
+ break;
+ case SGPC3:
+ supported_versions = supported_versions_sgpc3;
+ num_fs = ARRAY_SIZE(supported_versions_sgpc3);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ major = SGP_VERS_MAJOR(data);
+ minor = SGP_VERS_MINOR(data);
+ for (ix = 0; ix < num_fs; ix++) {
+ if (major == supported_versions[ix].major &&
+ minor >= supported_versions[ix].minor)
+ return 0;
+ }
+ dev_err(&data->client->dev, "unsupported sgp version: %d.%d\n",
+ major, minor);
+
+ return -ENODEV;
+}
+
+static void sgp_init(struct sgp_data *data)
+{
+ data->iaq_init_cmd = SGP_CMD_IAQ_INIT;
+ data->iaq_init_start_jiffies = 0;
+ data->iaq_buffer_state = IAQ_BUFFER_EMPTY;
+ switch (SGP_VERS_PRODUCT(data)) {
+ case SGP30:
+ data->measure_interval_jiffies = SGP30_MEASURE_INTERVAL_HZ * HZ;
+ data->measure_iaq_cmd = SGP_CMD_IAQ_MEASURE;
+ data->measure_gas_signals_cmd = SGP30_CMD_MEASURE_SIGNAL;
+ data->product_id = SGP30;
+ data->iaq_defval_skip_jiffies = 15 * HZ;
+ break;
+ case SGPC3:
+ data->measure_interval_jiffies = SGPC3_MEASURE_INTERVAL_HZ * HZ;
+ data->measure_iaq_cmd = SGPC3_CMD_MEASURE_RAW;
+ data->measure_gas_signals_cmd = SGPC3_CMD_MEASURE_RAW;
+ data->product_id = SGPC3;
+ data->iaq_defval_skip_jiffies =
+ 43 * data->measure_interval_jiffies;
+ break;
+ };
+}
+
+static const struct iio_info sgp_info = {
+ .read_raw = sgp_read_raw,
+};
+
+static const struct of_device_id sgp_dt_ids[] = {
+ { .compatible = "sensirion,sgp30", .data = (void *)SGP30 },
+ { .compatible = "sensirion,sgpc3", .data = (void *)SGPC3 },
+ { }
+};
+
+static int sgp_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct sgp_data *data;
+ const struct of_device_id *of_id;
+ unsigned long product_id;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ of_id = of_match_device(sgp_dt_ids, &client->dev);
+ if (of_id)
+ product_id = (unsigned long)of_id->data;
+ else
+ product_id = id->driver_data;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ crc8_populate_msb(sgp_crc8_table, SGP_CRC8_POLYNOMIAL);
+ mutex_init(&data->data_lock);
+
+ /* get feature set version and write it to client data */
+ ret = sgp_read_cmd(data, SGP_CMD_GET_FEATURE_SET, &data->buffer, 1,
+ SGP_CMD_DURATION_US);
+ if (ret < 0)
+ return ret;
+
+ data->feature_set = be16_to_cpu(data->buffer.raw_words[0].value);
+
+ ret = sgp_check_compat(data, product_id);
+ if (ret)
+ return ret;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &sgp_info;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = sgp_devices[product_id].channels;
+ indio_dev->num_channels = sgp_devices[product_id].num_channels;
+
+ sgp_init(data);
+
+ ret = devm_iio_device_register(&client->dev, indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to register iio device\n");
+ return ret;
+ }
+
+ data->iaq_thread = kthread_run(sgp_iaq_threadfn, data,
+ "%s-iaq", data->client->name);
+
+ return 0;
+}
+
+static int sgp_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct sgp_data *data = iio_priv(indio_dev);
+
+ if (data->iaq_thread)
+ kthread_stop(data->iaq_thread);
+
+ return 0;
+}
+
+static const struct i2c_device_id sgp_id[] = {
+ { "sgp30", SGP30 },
+ { "sgpc3", SGPC3 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, sgp_id);
+MODULE_DEVICE_TABLE(of, sgp_dt_ids);
+
+static struct i2c_driver sgp_driver = {
+ .driver = {
+ .name = "sgp30",
+ .of_match_table = of_match_ptr(sgp_dt_ids),
+ },
+ .probe = sgp_probe,
+ .remove = sgp_remove,
+ .id_table = sgp_id,
+};
+module_i2c_driver(sgp_driver);
+
+MODULE_AUTHOR("Andreas Brauchli <andreas.brauchli@sensirion.com>");
+MODULE_AUTHOR("Pascal Sachs <pascal.sachs@sensirion.com>");
+MODULE_DESCRIPTION("Sensirion SGP gas sensors");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c
new file mode 100644
index 000000000000..edbb956e81e8
--- /dev/null
+++ b/drivers/iio/chemical/sps30.c
@@ -0,0 +1,548 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sensirion SPS30 particulate matter sensor driver
+ *
+ * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
+ *
+ * I2C slave address: 0x69
+ */
+
+#include <asm/unaligned.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#define SPS30_CRC8_POLYNOMIAL 0x31
+/* max number of bytes needed to store PM measurements or serial string */
+#define SPS30_MAX_READ_SIZE 48
+/* sensor measures reliably up to 3000 ug / m3 */
+#define SPS30_MAX_PM 3000
+/* minimum and maximum self cleaning periods in seconds */
+#define SPS30_AUTO_CLEANING_PERIOD_MIN 0
+#define SPS30_AUTO_CLEANING_PERIOD_MAX 604800
+
+/* SPS30 commands */
+#define SPS30_START_MEAS 0x0010
+#define SPS30_STOP_MEAS 0x0104
+#define SPS30_RESET 0xd304
+#define SPS30_READ_DATA_READY_FLAG 0x0202
+#define SPS30_READ_DATA 0x0300
+#define SPS30_READ_SERIAL 0xd033
+#define SPS30_START_FAN_CLEANING 0x5607
+#define SPS30_AUTO_CLEANING_PERIOD 0x8004
+/* not a sensor command per se, used only to distinguish write from read */
+#define SPS30_READ_AUTO_CLEANING_PERIOD 0x8005
+
+enum {
+ PM1,
+ PM2P5,
+ PM4,
+ PM10,
+};
+
+enum {
+ RESET,
+ MEASURING,
+};
+
+struct sps30_state {
+ struct i2c_client *client;
+ /*
+ * Guards against concurrent access to sensor registers.
+ * Must be held whenever sequence of commands is to be executed.
+ */
+ struct mutex lock;
+ int state;
+};
+
+DECLARE_CRC8_TABLE(sps30_crc8_table);
+
+static int sps30_write_then_read(struct sps30_state *state, u8 *txbuf,
+ int txsize, u8 *rxbuf, int rxsize)
+{
+ int ret;
+
+ /*
+ * Sensor does not support repeated start so instead of
+ * sending two i2c messages in a row we just send one by one.
+ */
+ ret = i2c_master_send(state->client, txbuf, txsize);
+ if (ret != txsize)
+ return ret < 0 ? ret : -EIO;
+
+ if (!rxbuf)
+ return 0;
+
+ ret = i2c_master_recv(state->client, rxbuf, rxsize);
+ if (ret != rxsize)
+ return ret < 0 ? ret : -EIO;
+
+ return 0;
+}
+
+static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
+{
+ /*
+ * Internally sensor stores measurements in a following manner:
+ *
+ * PM1: upper two bytes, crc8, lower two bytes, crc8
+ * PM2P5: upper two bytes, crc8, lower two bytes, crc8
+ * PM4: upper two bytes, crc8, lower two bytes, crc8
+ * PM10: upper two bytes, crc8, lower two bytes, crc8
+ *
+ * What follows next are number concentration measurements and
+ * typical particle size measurement which we omit.
+ */
+ u8 buf[SPS30_MAX_READ_SIZE] = { cmd >> 8, cmd };
+ int i, ret = 0;
+
+ switch (cmd) {
+ case SPS30_START_MEAS:
+ buf[2] = 0x03;
+ buf[3] = 0x00;
+ buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE);
+ ret = sps30_write_then_read(state, buf, 5, NULL, 0);
+ break;
+ case SPS30_STOP_MEAS:
+ case SPS30_RESET:
+ case SPS30_START_FAN_CLEANING:
+ ret = sps30_write_then_read(state, buf, 2, NULL, 0);
+ break;
+ case SPS30_READ_AUTO_CLEANING_PERIOD:
+ buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
+ buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD;
+ /* fall through */
+ case SPS30_READ_DATA_READY_FLAG:
+ case SPS30_READ_DATA:
+ case SPS30_READ_SERIAL:
+ /* every two data bytes are checksummed */
+ size += size / 2;
+ ret = sps30_write_then_read(state, buf, 2, buf, size);
+ break;
+ case SPS30_AUTO_CLEANING_PERIOD:
+ buf[2] = data[0];
+ buf[3] = data[1];
+ buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE);
+ buf[5] = data[2];
+ buf[6] = data[3];
+ buf[7] = crc8(sps30_crc8_table, &buf[5], 2, CRC8_INIT_VALUE);
+ ret = sps30_write_then_read(state, buf, 8, NULL, 0);
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ /* validate received data and strip off crc bytes */
+ for (i = 0; i < size; i += 3) {
+ u8 crc = crc8(sps30_crc8_table, &buf[i], 2, CRC8_INIT_VALUE);
+
+ if (crc != buf[i + 2]) {
+ dev_err(&state->client->dev,
+ "data integrity check failed\n");
+ return -EIO;
+ }
+
+ *data++ = buf[i];
+ *data++ = buf[i + 1];
+ }
+
+ return 0;
+}
+
+static s32 sps30_float_to_int_clamped(const u8 *fp)
+{
+ int val = get_unaligned_be32(fp);
+ int mantissa = val & GENMASK(22, 0);
+ /* this is fine since passed float is always non-negative */
+ int exp = val >> 23;
+ int fraction, shift;
+
+ /* special case 0 */
+ if (!exp && !mantissa)
+ return 0;
+
+ exp -= 127;
+ if (exp < 0) {
+ /* return values ranging from 1 to 99 */
+ return ((((1 << 23) + mantissa) * 100) >> 23) >> (-exp);
+ }
+
+ /* return values ranging from 100 to 300000 */
+ shift = 23 - exp;
+ val = (1 << exp) + (mantissa >> shift);
+ if (val >= SPS30_MAX_PM)
+ return SPS30_MAX_PM * 100;
+
+ fraction = mantissa & GENMASK(shift - 1, 0);
+
+ return val * 100 + ((fraction * 100) >> shift);
+}
+
+static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
+{
+ int i, ret, tries = 5;
+ u8 tmp[16];
+
+ if (state->state == RESET) {
+ ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0);
+ if (ret)
+ return ret;
+
+ state->state = MEASURING;
+ }
+
+ while (tries--) {
+ ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, tmp, 2);
+ if (ret)
+ return -EIO;
+
+ /* new measurements ready to be read */
+ if (tmp[1] == 1)
+ break;
+
+ msleep_interruptible(300);
+ }
+
+ if (tries == -1)
+ return -ETIMEDOUT;
+
+ ret = sps30_do_cmd(state, SPS30_READ_DATA, tmp, sizeof(int) * size);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < size; i++)
+ data[i] = sps30_float_to_int_clamped(&tmp[4 * i]);
+
+ return 0;
+}
+
+static irqreturn_t sps30_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct sps30_state *state = iio_priv(indio_dev);
+ int ret;
+ s32 data[4 + 2]; /* PM1, PM2P5, PM4, PM10, timestamp */
+
+ mutex_lock(&state->lock);
+ ret = sps30_do_meas(state, data, 4);
+ mutex_unlock(&state->lock);
+ if (ret)
+ goto err;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data,
+ iio_get_time_ns(indio_dev));
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int sps30_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct sps30_state *state = iio_priv(indio_dev);
+ int data[4], ret = -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_MASSCONCENTRATION:
+ mutex_lock(&state->lock);
+ /* read up to the number of bytes actually needed */
+ switch (chan->channel2) {
+ case IIO_MOD_PM1:
+ ret = sps30_do_meas(state, data, 1);
+ break;
+ case IIO_MOD_PM2P5:
+ ret = sps30_do_meas(state, data, 2);
+ break;
+ case IIO_MOD_PM4:
+ ret = sps30_do_meas(state, data, 3);
+ break;
+ case IIO_MOD_PM10:
+ ret = sps30_do_meas(state, data, 4);
+ break;
+ }
+ mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
+
+ *val = data[chan->address] / 100;
+ *val2 = (data[chan->address] % 100) * 10000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_MASSCONCENTRATION:
+ switch (chan->channel2) {
+ case IIO_MOD_PM1:
+ case IIO_MOD_PM2P5:
+ case IIO_MOD_PM4:
+ case IIO_MOD_PM10:
+ *val = 0;
+ *val2 = 10000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int sps30_do_cmd_reset(struct sps30_state *state)
+{
+ int ret;
+
+ ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0);
+ msleep(300);
+ /*
+ * Power-on-reset causes sensor to produce some glitch on i2c bus and
+ * some controllers end up in error state. Recover simply by placing
+ * some data on the bus, for example STOP_MEAS command, which
+ * is NOP in this case.
+ */
+ sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
+ state->state = RESET;
+
+ return ret;
+}
+
+static ssize_t start_cleaning_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 sps30_state *state = iio_priv(indio_dev);
+ int val, ret;
+
+ if (kstrtoint(buf, 0, &val) || val != 1)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ ret = sps30_do_cmd(state, SPS30_START_FAN_CLEANING, NULL, 0);
+ mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+static ssize_t cleaning_period_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct sps30_state *state = iio_priv(indio_dev);
+ u8 tmp[4];
+ int ret;
+
+ mutex_lock(&state->lock);
+ ret = sps30_do_cmd(state, SPS30_READ_AUTO_CLEANING_PERIOD, tmp, 4);
+ mutex_unlock(&state->lock);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", get_unaligned_be32(tmp));
+}
+
+static ssize_t cleaning_period_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 sps30_state *state = iio_priv(indio_dev);
+ int val, ret;
+ u8 tmp[4];
+
+ if (kstrtoint(buf, 0, &val))
+ return -EINVAL;
+
+ if ((val < SPS30_AUTO_CLEANING_PERIOD_MIN) ||
+ (val > SPS30_AUTO_CLEANING_PERIOD_MAX))
+ return -EINVAL;
+
+ put_unaligned_be32(val, tmp);
+
+ mutex_lock(&state->lock);
+ ret = sps30_do_cmd(state, SPS30_AUTO_CLEANING_PERIOD, tmp, 0);
+ if (ret) {
+ mutex_unlock(&state->lock);
+ return ret;
+ }
+
+ msleep(20);
+
+ /*
+ * sensor requires reset in order to return up to date self cleaning
+ * period
+ */
+ ret = sps30_do_cmd_reset(state);
+ if (ret)
+ dev_warn(dev,
+ "period changed but reads will return the old value\n");
+
+ mutex_unlock(&state->lock);
+
+ return len;
+}
+
+static ssize_t cleaning_period_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "[%d %d %d]\n",
+ SPS30_AUTO_CLEANING_PERIOD_MIN, 1,
+ SPS30_AUTO_CLEANING_PERIOD_MAX);
+}
+
+static IIO_DEVICE_ATTR_WO(start_cleaning, 0);
+static IIO_DEVICE_ATTR_RW(cleaning_period, 0);
+static IIO_DEVICE_ATTR_RO(cleaning_period_available, 0);
+
+static struct attribute *sps30_attrs[] = {
+ &iio_dev_attr_start_cleaning.dev_attr.attr,
+ &iio_dev_attr_cleaning_period.dev_attr.attr,
+ &iio_dev_attr_cleaning_period_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group sps30_attr_group = {
+ .attrs = sps30_attrs,
+};
+
+static const struct iio_info sps30_info = {
+ .attrs = &sps30_attr_group,
+ .read_raw = sps30_read_raw,
+};
+
+#define SPS30_CHAN(_index, _mod) { \
+ .type = IIO_MASSCONCENTRATION, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _mod, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .address = _mod, \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 19, \
+ .storagebits = 32, \
+ .endianness = IIO_CPU, \
+ }, \
+}
+
+static const struct iio_chan_spec sps30_channels[] = {
+ SPS30_CHAN(0, PM1),
+ SPS30_CHAN(1, PM2P5),
+ SPS30_CHAN(2, PM4),
+ SPS30_CHAN(3, PM10),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static void sps30_stop_meas(void *data)
+{
+ struct sps30_state *state = data;
+
+ sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
+}
+
+static const unsigned long sps30_scan_masks[] = { 0x0f, 0x00 };
+
+static int sps30_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct sps30_state *state;
+ u8 buf[32];
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ state->client = client;
+ state->state = RESET;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &sps30_info;
+ indio_dev->name = client->name;
+ indio_dev->channels = sps30_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sps30_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->available_scan_masks = sps30_scan_masks;
+
+ mutex_init(&state->lock);
+ crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL);
+
+ ret = sps30_do_cmd_reset(state);
+ if (ret) {
+ dev_err(&client->dev, "failed to reset device\n");
+ return ret;
+ }
+
+ ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf));
+ if (ret) {
+ dev_err(&client->dev, "failed to read serial number\n");
+ return ret;
+ }
+ /* returned serial number is already NUL terminated */
+ dev_info(&client->dev, "serial number: %s\n", buf);
+
+ ret = devm_add_action_or_reset(&client->dev, sps30_stop_meas, state);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ sps30_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id sps30_id[] = {
+ { "sps30" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sps30_id);
+
+static const struct of_device_id sps30_of_match[] = {
+ { .compatible = "sensirion,sps30" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sps30_of_match);
+
+static struct i2c_driver sps30_driver = {
+ .driver = {
+ .name = "sps30",
+ .of_match_table = sps30_of_match,
+ },
+ .id_table = sps30_id,
+ .probe_new = sps30_probe,
+};
+module_i2c_driver(sps30_driver);
+
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
+MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 851b61eaf3da..fbef9107acad 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -148,9 +148,9 @@ config AD5686_SPI
depends on SPI
select AD5686
help
- Say yes here to build support for Analog Devices AD5672R, AD5676,
- AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R.
- Voltage Output Digital to Analog Converter.
+ Say yes here to build support for Analog Devices AD5672R, AD5674R,
+ AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686,
+ AD5686R Voltage Output Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5686.
@@ -375,6 +375,16 @@ config TI_DAC7311
If compiled as a module, it will be called ti-dac7311.
+config TI_DAC7612
+ tristate "Texas Instruments 12-bit 2-channel DAC driver"
+ depends on SPI_MASTER && GPIOLIB
+ help
+ Driver for the Texas Instruments DAC7612, DAC7612U, DAC7612UB
+ The driver hand drive the load pin automatically, otherwise
+ it needs to be toggled manually.
+
+ If compiled as a module, it will be called ti-dac7612.
+
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index f0a37c93de8e..1369fa1d2f0e 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -41,4 +41,5 @@ obj-$(CONFIG_STM32_DAC) += stm32-dac.o
obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
+obj-$(CONFIG_TI_DAC7612) += ti-dac7612.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
index 665fa6bd9ced..0188ded5137c 100644
--- a/drivers/iio/dac/ad5686-spi.c
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -1,7 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0
/*
- * AD5672R, AD5676, AD5676R, AD5681R, AD5682R, AD5683, AD5683R,
- * AD5684, AD5684R, AD5685R, AD5686, AD5686R
+ * AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
+ * AD5681R, AD5682R, AD5683, AD5683R, AD5684,
+ * AD5684R, AD5685R, AD5686, AD5686R
* Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
@@ -102,8 +103,10 @@ static int ad5686_spi_remove(struct spi_device *spi)
static const struct spi_device_id ad5686_spi_id[] = {
{"ad5310r", ID_AD5310R},
{"ad5672r", ID_AD5672R},
+ {"ad5674r", ID_AD5674R},
{"ad5676", ID_AD5676},
{"ad5676r", ID_AD5676R},
+ {"ad5679r", ID_AD5679R},
{"ad5681r", ID_AD5681R},
{"ad5682r", ID_AD5682R},
{"ad5683", ID_AD5683},
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index a332b93ca2c4..e06b29c565b9 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0
/*
* AD5686R, AD5685R, AD5684R Digital to analog converters driver
*
@@ -71,7 +71,7 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
int ret;
struct ad5686_state *st = iio_priv(indio_dev);
unsigned int val, ref_bit_msk;
- u8 shift;
+ u8 shift, address = 0;
ret = strtobool(buf, &readin);
if (ret)
@@ -94,6 +94,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
case AD5686_REGMAP:
shift = 0;
ref_bit_msk = 0;
+ /* AD5674R/AD5679R have 16 channels and 2 powerdown registers */
+ if (chan->channel > 0x7)
+ address = 0x8;
break;
case AD5693_REGMAP:
shift = 13;
@@ -107,7 +110,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
if (!st->use_internal_vref)
val |= ref_bit_msk;
- ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0, val);
+ ret = st->write(st, AD5686_CMD_POWERDOWN_DAC,
+ address, val >> (address * 2));
return ret ? ret : len;
}
@@ -226,10 +230,32 @@ static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(7, 7, bits, _shift), \
}
+#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \
+static struct iio_chan_spec name[] = { \
+ AD5868_CHANNEL(0, 0, bits, _shift), \
+ AD5868_CHANNEL(1, 1, bits, _shift), \
+ AD5868_CHANNEL(2, 2, bits, _shift), \
+ AD5868_CHANNEL(3, 3, bits, _shift), \
+ AD5868_CHANNEL(4, 4, bits, _shift), \
+ AD5868_CHANNEL(5, 5, bits, _shift), \
+ AD5868_CHANNEL(6, 6, bits, _shift), \
+ AD5868_CHANNEL(7, 7, bits, _shift), \
+ AD5868_CHANNEL(8, 8, bits, _shift), \
+ AD5868_CHANNEL(9, 9, bits, _shift), \
+ AD5868_CHANNEL(10, 10, bits, _shift), \
+ AD5868_CHANNEL(11, 11, bits, _shift), \
+ AD5868_CHANNEL(12, 12, bits, _shift), \
+ AD5868_CHANNEL(13, 13, bits, _shift), \
+ AD5868_CHANNEL(14, 14, bits, _shift), \
+ AD5868_CHANNEL(15, 15, bits, _shift), \
+}
+
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
+DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
+DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0);
DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
@@ -262,6 +288,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
+ [ID_AD5674R] = {
+ .channels = ad5674r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
+ },
[ID_AD5675R] = {
.channels = ad5676_channels,
.int_vref_mv = 2500,
@@ -279,6 +311,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
+ [ID_AD5679R] = {
+ .channels = ad5679r_channels,
+ .int_vref_mv = 2500,
+ .num_channels = 16,
+ .regmap_type = AD5686_REGMAP,
+ },
[ID_AD5681R] = {
.channels = ad5691r_channels,
.int_vref_mv = 2500,
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
index 19f6917d4738..70a779939ddb 100644
--- a/drivers/iio/dac/ad5686.h
+++ b/drivers/iio/dac/ad5686.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file is part of AD5686 DAC driver
*
@@ -54,9 +54,11 @@ enum ad5686_supported_device_ids {
ID_AD5311R,
ID_AD5671R,
ID_AD5672R,
+ ID_AD5674R,
ID_AD5675R,
ID_AD5676,
ID_AD5676R,
+ ID_AD5679R,
ID_AD5681R,
ID_AD5682R,
ID_AD5683,
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index 7350d9806a11..ccf794caef43 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0
/*
* AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R,
* AD5694, AD5694R, AD5695R, AD5696, AD5696R
diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c
index ef41f12bf262..2bdf1b0aee06 100644
--- a/drivers/iio/dac/ad5758.c
+++ b/drivers/iio/dac/ad5758.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0
/*
* AD5758 Digital to analog converters driver
*
diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c
new file mode 100644
index 000000000000..c46805144dd4
--- /dev/null
+++ b/drivers/iio/dac/ti-dac7612.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DAC7612 Dual, 12-Bit Serial input Digital-to-Analog Converter
+ *
+ * Copyright 2019 Qtechnology A/S
+ * 2019 Ricardo Ribalda <ricardo@ribalda.com>
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+
+#define DAC7612_RESOLUTION 12
+#define DAC7612_ADDRESS 4
+#define DAC7612_START 5
+
+struct dac7612 {
+ struct spi_device *spi;
+ struct gpio_desc *loaddacs;
+ uint16_t cache[2];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ uint8_t data[2] ____cacheline_aligned;
+};
+
+static int dac7612_cmd_single(struct dac7612 *priv, int channel, u16 val)
+{
+ int ret;
+
+ priv->data[0] = BIT(DAC7612_START) | (channel << DAC7612_ADDRESS);
+ priv->data[0] |= val >> 8;
+ priv->data[1] = val & 0xff;
+
+ priv->cache[channel] = val;
+
+ ret = spi_write(priv->spi, priv->data, sizeof(priv->data));
+ if (ret)
+ return ret;
+
+ gpiod_set_value(priv->loaddacs, 1);
+ gpiod_set_value(priv->loaddacs, 0);
+
+ return 0;
+}
+
+#define dac7612_CHANNEL(chan, name) { \
+ .type = IIO_VOLTAGE, \
+ .channel = (chan), \
+ .indexed = 1, \
+ .output = 1, \
+ .datasheet_name = name, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec dac7612_channels[] = {
+ dac7612_CHANNEL(0, "OUTA"),
+ dac7612_CHANNEL(1, "OUTB"),
+};
+
+static int dac7612_read_raw(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct dac7612 *priv;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ priv = iio_priv(iio_dev);
+ *val = priv->cache[chan->channel];
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dac7612_write_raw(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int val, int val2, long mask)
+{
+ struct dac7612 *priv = iio_priv(iio_dev);
+ int ret;
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ if ((val >= BIT(DAC7612_RESOLUTION)) || val < 0 || val2)
+ return -EINVAL;
+
+ if (val == priv->cache[chan->channel])
+ return 0;
+
+ mutex_lock(&iio_dev->mlock);
+ ret = dac7612_cmd_single(priv, chan->channel, val);
+ mutex_unlock(&iio_dev->mlock);
+
+ return ret;
+}
+
+static const struct iio_info dac7612_info = {
+ .read_raw = dac7612_read_raw,
+ .write_raw = dac7612_write_raw,
+};
+
+static int dac7612_probe(struct spi_device *spi)
+{
+ struct iio_dev *iio_dev;
+ struct dac7612 *priv;
+ int i;
+ int ret;
+
+ iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(iio_dev);
+ /*
+ * LOADDACS pin can be controlled by the driver or externally.
+ * When controlled by the driver, the DAC value is updated after
+ * every write.
+ * When the driver does not control the PIN, the user or an external
+ * event can change the value of all DACs by pulsing down the LOADDACs
+ * pin.
+ */
+ priv->loaddacs = devm_gpiod_get_optional(&spi->dev, "ti,loaddacs",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->loaddacs))
+ return PTR_ERR(priv->loaddacs);
+ priv->spi = spi;
+ spi_set_drvdata(spi, iio_dev);
+ iio_dev->dev.parent = &spi->dev;
+ iio_dev->info = &dac7612_info;
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->channels = dac7612_channels;
+ iio_dev->num_channels = ARRAY_SIZE(priv->cache);
+ iio_dev->name = spi_get_device_id(spi)->name;
+
+ for (i = 0; i < ARRAY_SIZE(priv->cache); i++) {
+ ret = dac7612_cmd_single(priv, i, 0);
+ if (ret)
+ return ret;
+ }
+
+ return devm_iio_device_register(&spi->dev, iio_dev);
+}
+
+static const struct spi_device_id dac7612_id[] = {
+ {"ti-dac7612"},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, dac7612_id);
+
+static const struct of_device_id dac7612_of_match[] = {
+ { .compatible = "ti,dac7612" },
+ { .compatible = "ti,dac7612u" },
+ { .compatible = "ti,dac7612ub" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, dac7612_of_match);
+
+static struct spi_driver dac7612_driver = {
+ .driver = {
+ .name = "ti-dac7612",
+ .of_match_table = dac7612_of_match,
+ },
+ .probe = dac7612_probe,
+ .id_table = dac7612_id,
+};
+module_spi_driver(dac7612_driver);
+
+MODULE_AUTHOR("Ricardo Ribalda <ricardo@ribalda.com>");
+MODULE_DESCRIPTION("Texas Instruments DAC7612 DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index f3f94fbdd20a..3f9be69499ec 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -943,11 +943,14 @@ static int ad9523_setup(struct iio_dev *indio_dev)
}
}
- for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN)
- ad9523_write(indio_dev,
+ for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN) {
+ ret = ad9523_write(indio_dev,
AD9523_CHANNEL_CLOCK_DIST(i),
AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
AD9523_CLK_DIST_PWR_DOWN_EN);
+ if (ret < 0)
+ return ret;
+ }
ret = ad9523_write(indio_dev, AD9523_POWER_DOWN_CTRL, 0);
if (ret < 0)
diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h
index 2351049d930b..621f5309d735 100644
--- a/drivers/iio/imu/bmi160/bmi160.h
+++ b/drivers/iio/imu/bmi160/bmi160.h
@@ -2,9 +2,20 @@
#ifndef BMI160_H_
#define BMI160_H_
+#include <linux/iio/iio.h>
+
+struct bmi160_data {
+ struct regmap *regmap;
+ struct iio_trigger *trig;
+};
+
extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
+int bmi160_enable_irq(struct regmap *regmap, bool enable);
+
+int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type);
+
#endif /* BMI160_H_ */
diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index b10330b0f93f..6af65d6f1d28 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -1,26 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU (accel, gyro plus external magnetometer)
*
* Copyright (c) 2016, Intel Corporation.
- *
- * This file is subject to the terms and conditions of version 2 of
- * the GNU General Public License. See the file COPYING in the main
- * directory of this archive for more details.
+ * Copyright (c) 2019, Martin Kelly.
*
* IIO core driver for BMI160, with support for I2C/SPI busses
*
- * TODO: magnetometer, interrupts, hardware FIFO
+ * TODO: magnetometer, hardware FIFO
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
#include "bmi160.h"
@@ -64,8 +65,32 @@
#define BMI160_CMD_GYRO_PM_FAST_STARTUP 0x17
#define BMI160_CMD_SOFTRESET 0xB6
+#define BMI160_REG_INT_EN 0x51
+#define BMI160_DRDY_INT_EN BIT(4)
+
+#define BMI160_REG_INT_OUT_CTRL 0x53
+#define BMI160_INT_OUT_CTRL_MASK 0x0f
+#define BMI160_INT1_OUT_CTRL_SHIFT 0
+#define BMI160_INT2_OUT_CTRL_SHIFT 4
+#define BMI160_EDGE_TRIGGERED BIT(0)
+#define BMI160_ACTIVE_HIGH BIT(1)
+#define BMI160_OPEN_DRAIN BIT(2)
+#define BMI160_OUTPUT_EN BIT(3)
+
+#define BMI160_REG_INT_LATCH 0x54
+#define BMI160_INT1_LATCH_MASK BIT(4)
+#define BMI160_INT2_LATCH_MASK BIT(5)
+
+/* INT1 and INT2 are in the opposite order as in INT_OUT_CTRL! */
+#define BMI160_REG_INT_MAP 0x56
+#define BMI160_INT1_MAP_DRDY_EN 0x80
+#define BMI160_INT2_MAP_DRDY_EN 0x08
+
#define BMI160_REG_DUMMY 0x7F
+#define BMI160_NORMAL_WRITE_USLEEP 2
+#define BMI160_SUSPENDED_WRITE_USLEEP 450
+
#define BMI160_ACCEL_PMU_MIN_USLEEP 3800
#define BMI160_GYRO_PMU_MIN_USLEEP 80000
#define BMI160_SOFTRESET_USLEEP 1000
@@ -108,8 +133,9 @@ enum bmi160_sensor_type {
BMI160_NUM_SENSORS /* must be last */
};
-struct bmi160_data {
- struct regmap *regmap;
+enum bmi160_int_pin {
+ BMI160_PIN_INT1,
+ BMI160_PIN_INT2
};
const struct regmap_config bmi160_regmap_config = {
@@ -273,7 +299,7 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t,
cmd = bmi160_regs[t].pmu_cmd_suspend;
ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd);
- if (ret < 0)
+ if (ret)
return ret;
usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000);
@@ -305,7 +331,7 @@ int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
int i, ret, val;
ret = regmap_read(data->regmap, bmi160_regs[t].range, &val);
- if (ret < 0)
+ if (ret)
return ret;
for (i = 0; i < bmi160_scale_table[t].num; i++)
@@ -328,7 +354,7 @@ static int bmi160_get_data(struct bmi160_data *data, int chan_type,
reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(sample);
ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(sample));
- if (ret < 0)
+ if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(sample), 15);
@@ -362,7 +388,7 @@ static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
int i, val, ret;
ret = regmap_read(data->regmap, bmi160_regs[t].config, &val);
- if (ret < 0)
+ if (ret)
return ret;
val &= bmi160_regs[t].config_odr_mask;
@@ -394,13 +420,12 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
indio_dev->masklength) {
ret = regmap_bulk_read(data->regmap, base + i * sizeof(sample),
&sample, sizeof(sample));
- if (ret < 0)
+ if (ret)
goto done;
buf[j++] = sample;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_timestamp(indio_dev, buf, pf->timestamp);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -416,18 +441,18 @@ static int bmi160_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = bmi160_get_data(data, chan->type, chan->channel2, val);
- if (ret < 0)
+ if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
ret = bmi160_get_scale(data,
bmi160_to_sensor(chan->type), val2);
- return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = bmi160_get_odr(data, bmi160_to_sensor(chan->type),
val, val2);
- return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -498,6 +523,186 @@ static const char *bmi160_match_acpi_device(struct device *dev)
return dev_name(dev);
}
+static int bmi160_write_conf_reg(struct regmap *regmap, unsigned int reg,
+ unsigned int mask, unsigned int bits,
+ unsigned int write_usleep)
+{
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(regmap, reg, &val);
+ if (ret)
+ return ret;
+
+ val = (val & ~mask) | bits;
+
+ ret = regmap_write(regmap, reg, val);
+ if (ret)
+ return ret;
+
+ /*
+ * We need to wait after writing before we can write again. See the
+ * datasheet, page 93.
+ */
+ usleep_range(write_usleep, write_usleep + 1000);
+
+ return 0;
+}
+
+static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin,
+ bool open_drain, u8 irq_mask,
+ unsigned long write_usleep)
+{
+ int ret;
+ struct device *dev = regmap_get_device(regmap);
+ u8 int_out_ctrl_shift;
+ u8 int_latch_mask;
+ u8 int_map_mask;
+ u8 int_out_ctrl_mask;
+ u8 int_out_ctrl_bits;
+ const char *pin_name;
+
+ switch (pin) {
+ case BMI160_PIN_INT1:
+ int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT;
+ int_latch_mask = BMI160_INT1_LATCH_MASK;
+ int_map_mask = BMI160_INT1_MAP_DRDY_EN;
+ break;
+ case BMI160_PIN_INT2:
+ int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT;
+ int_latch_mask = BMI160_INT2_LATCH_MASK;
+ int_map_mask = BMI160_INT2_MAP_DRDY_EN;
+ break;
+ }
+ int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift;
+
+ /*
+ * Enable the requested pin with the right settings:
+ * - Push-pull/open-drain
+ * - Active low/high
+ * - Edge/level triggered
+ */
+ int_out_ctrl_bits = BMI160_OUTPUT_EN;
+ if (open_drain)
+ /* Default is push-pull. */
+ int_out_ctrl_bits |= BMI160_OPEN_DRAIN;
+ int_out_ctrl_bits |= irq_mask;
+ int_out_ctrl_bits <<= int_out_ctrl_shift;
+
+ ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_OUT_CTRL,
+ int_out_ctrl_mask, int_out_ctrl_bits,
+ write_usleep);
+ if (ret)
+ return ret;
+
+ /* Set the pin to input mode with no latching. */
+ ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_LATCH,
+ int_latch_mask, int_latch_mask,
+ write_usleep);
+ if (ret)
+ return ret;
+
+ /* Map interrupts to the requested pin. */
+ ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP,
+ int_map_mask, int_map_mask,
+ write_usleep);
+ if (ret) {
+ switch (pin) {
+ case BMI160_PIN_INT1:
+ pin_name = "INT1";
+ break;
+ case BMI160_PIN_INT2:
+ pin_name = "INT2";
+ break;
+ }
+ dev_err(dev, "Failed to configure %s IRQ pin", pin_name);
+ }
+
+ return ret;
+}
+
+int bmi160_enable_irq(struct regmap *regmap, bool enable)
+{
+ unsigned int enable_bit = 0;
+
+ if (enable)
+ enable_bit = BMI160_DRDY_INT_EN;
+
+ return bmi160_write_conf_reg(regmap, BMI160_REG_INT_EN,
+ BMI160_DRDY_INT_EN, enable_bit,
+ BMI160_NORMAL_WRITE_USLEEP);
+}
+EXPORT_SYMBOL(bmi160_enable_irq);
+
+static int bmi160_get_irq(struct device_node *of_node, enum bmi160_int_pin *pin)
+{
+ int irq;
+
+ /* Use INT1 if possible, otherwise fall back to INT2. */
+ irq = of_irq_get_byname(of_node, "INT1");
+ if (irq > 0) {
+ *pin = BMI160_PIN_INT1;
+ return irq;
+ }
+
+ irq = of_irq_get_byname(of_node, "INT2");
+ if (irq > 0)
+ *pin = BMI160_PIN_INT2;
+
+ return irq;
+}
+
+static int bmi160_config_device_irq(struct iio_dev *indio_dev, int irq_type,
+ enum bmi160_int_pin pin)
+{
+ bool open_drain;
+ u8 irq_mask;
+ struct bmi160_data *data = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(data->regmap);
+
+ /* Level-triggered, active-low is the default if we set all zeroes. */
+ if (irq_type == IRQF_TRIGGER_RISING)
+ irq_mask = BMI160_ACTIVE_HIGH | BMI160_EDGE_TRIGGERED;
+ else if (irq_type == IRQF_TRIGGER_FALLING)
+ irq_mask = BMI160_EDGE_TRIGGERED;
+ else if (irq_type == IRQF_TRIGGER_HIGH)
+ irq_mask = BMI160_ACTIVE_HIGH;
+ else if (irq_type == IRQF_TRIGGER_LOW)
+ irq_mask = 0;
+ else {
+ dev_err(&indio_dev->dev,
+ "Invalid interrupt type 0x%x specified\n", irq_type);
+ return -EINVAL;
+ }
+
+ open_drain = of_property_read_bool(dev->of_node, "drive-open-drain");
+
+ return bmi160_config_pin(data->regmap, pin, open_drain, irq_mask,
+ BMI160_NORMAL_WRITE_USLEEP);
+}
+
+static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq,
+ enum bmi160_int_pin pin)
+{
+ struct irq_data *desc;
+ u32 irq_type;
+ int ret;
+
+ desc = irq_get_irq_data(irq);
+ if (!desc) {
+ dev_err(&indio_dev->dev, "Could not find IRQ %d\n", irq);
+ return -EINVAL;
+ }
+
+ irq_type = irqd_get_trigger_type(desc);
+
+ ret = bmi160_config_device_irq(indio_dev, irq_type, pin);
+ if (ret)
+ return ret;
+
+ return bmi160_probe_trigger(indio_dev, irq, irq_type);
+}
+
static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
{
int ret;
@@ -505,7 +710,7 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
struct device *dev = regmap_get_device(data->regmap);
ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET);
- if (ret < 0)
+ if (ret)
return ret;
usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1);
@@ -516,12 +721,12 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
*/
if (use_spi) {
ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
- if (ret < 0)
+ if (ret)
return ret;
}
ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val);
- if (ret < 0) {
+ if (ret) {
dev_err(dev, "Error reading chip id\n");
return ret;
}
@@ -532,16 +737,59 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
}
ret = bmi160_set_mode(data, BMI160_ACCEL, true);
- if (ret < 0)
+ if (ret)
return ret;
ret = bmi160_set_mode(data, BMI160_GYRO, true);
- if (ret < 0)
+ if (ret)
return ret;
return 0;
}
+static int bmi160_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool enable)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct bmi160_data *data = iio_priv(indio_dev);
+
+ return bmi160_enable_irq(data->regmap, enable);
+}
+
+static const struct iio_trigger_ops bmi160_trigger_ops = {
+ .set_trigger_state = &bmi160_data_rdy_trigger_set_state,
+};
+
+int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
+{
+ struct bmi160_data *data = iio_priv(indio_dev);
+ int ret;
+
+ data->trig = devm_iio_trigger_alloc(&indio_dev->dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+
+ if (data->trig == NULL)
+ return -ENOMEM;
+
+ ret = devm_request_irq(&indio_dev->dev, irq,
+ &iio_trigger_generic_data_rdy_poll,
+ irq_type, "bmi160", data->trig);
+ if (ret)
+ return ret;
+
+ data->trig->dev.parent = regmap_get_device(data->regmap);
+ data->trig->ops = &bmi160_trigger_ops;
+ iio_trigger_set_drvdata(data->trig, indio_dev);
+
+ ret = devm_iio_trigger_register(&indio_dev->dev, data->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(data->trig);
+
+ return 0;
+}
+
static void bmi160_chip_uninit(void *data)
{
struct bmi160_data *bmi_data = data;
@@ -555,6 +803,8 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
{
struct iio_dev *indio_dev;
struct bmi160_data *data;
+ int irq;
+ enum bmi160_int_pin int_pin;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -566,11 +816,11 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
data->regmap = regmap;
ret = bmi160_chip_init(data, use_spi);
- if (ret < 0)
+ if (ret)
return ret;
ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data);
- if (ret < 0)
+ if (ret)
return ret;
if (!name && ACPI_HANDLE(dev))
@@ -583,16 +833,23 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmi160_info;
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
bmi160_trigger_handler, NULL);
- if (ret < 0)
+ if (ret)
return ret;
- ret = devm_iio_device_register(dev, indio_dev);
- if (ret < 0)
- return ret;
+ irq = bmi160_get_irq(dev->of_node, &int_pin);
+ if (irq > 0) {
+ ret = bmi160_setup_irq(indio_dev, irq, int_pin);
+ if (ret)
+ dev_err(&indio_dev->dev, "Failed to setup IRQ %d\n",
+ irq);
+ } else {
+ dev_info(&indio_dev->dev, "Not setting up IRQ trigger\n");
+ }
- return 0;
+ return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(bmi160_core_probe);
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index 5b1f7e6af651..e36f5e82d400 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, I2C bits
*
* Copyright (c) 2016, Intel Corporation.
*
- * This file is subject to the terms and conditions of version 2 of
- * the GNU General Public License. See the file COPYING in the main
- * directory of this archive for more details.
- *
* 7-bit I2C slave address is:
* - 0x68 if SDO is pulled to GND
* - 0x69 if SDO is pulled to VDDIO
diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c
index e521ad14eeac..c19e3df35559 100644
--- a/drivers/iio/imu/bmi160/bmi160_spi.c
+++ b/drivers/iio/imu/bmi160/bmi160_spi.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, SPI bits
*
* Copyright (c) 2016, Intel Corporation.
*
- * This file is subject to the terms and conditions of version 2 of
- * the GNU General Public License. See the file COPYING in the main
- * directory of this archive for more details.
*/
#include <linux/acpi.h>
#include <linux/module.h>
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index 5483b2ea754d..d2fe9dbddda7 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -13,8 +13,8 @@ config INV_MPU6050_I2C
select INV_MPU6050_IIO
select REGMAP_I2C
help
- This driver supports the Invensense MPU6050/6500/9150 and ICM20608
- motion tracking devices over I2C.
+ This driver supports the Invensense MPU6050/6500/9150 and
+ ICM20608/20602 motion tracking devices over I2C.
This driver can be built as a module. The module will be called
inv-mpu6050-i2c.
@@ -24,7 +24,7 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
- This driver supports the Invensense MPU6050/6500/9150 and ICM20608
- motion tracking devices over SPI.
+ This driver supports the Invensense MPU6050/6500/9150 and
+ ICM20608/20602 motion tracking devices over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 1e428c196a82..650de0fefb7b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -38,6 +38,29 @@ static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
*/
static const int accel_scale[] = {598, 1196, 2392, 4785};
+static const struct inv_mpu6050_reg_map reg_set_icm20602 = {
+ .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
+ .lpf = INV_MPU6050_REG_CONFIG,
+ .accel_lpf = INV_MPU6500_REG_ACCEL_CONFIG_2,
+ .user_ctrl = INV_MPU6050_REG_USER_CTRL,
+ .fifo_en = INV_MPU6050_REG_FIFO_EN,
+ .gyro_config = INV_MPU6050_REG_GYRO_CONFIG,
+ .accl_config = INV_MPU6050_REG_ACCEL_CONFIG,
+ .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H,
+ .fifo_r_w = INV_MPU6050_REG_FIFO_R_W,
+ .raw_gyro = INV_MPU6050_REG_RAW_GYRO,
+ .raw_accl = INV_MPU6050_REG_RAW_ACCEL,
+ .temperature = INV_MPU6050_REG_TEMPERATURE,
+ .int_enable = INV_MPU6050_REG_INT_ENABLE,
+ .int_status = INV_MPU6050_REG_INT_STATUS,
+ .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
+ .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
+ .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
+ .accl_offset = INV_MPU6500_REG_ACCEL_OFFSET,
+ .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
+ .i2c_if = INV_ICM20602_REG_I2C_IF,
+};
+
static const struct inv_mpu6050_reg_map reg_set_6500 = {
.sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
.lpf = INV_MPU6050_REG_CONFIG,
@@ -58,6 +81,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = {
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
.accl_offset = INV_MPU6500_REG_ACCEL_OFFSET,
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
+ .i2c_if = 0,
};
static const struct inv_mpu6050_reg_map reg_set_6050 = {
@@ -78,6 +102,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
.accl_offset = INV_MPU6050_REG_ACCEL_OFFSET,
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
+ .i2c_if = 0,
};
static const struct inv_mpu6050_chip_config chip_config_6050 = {
@@ -140,6 +165,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
+ {
+ .whoami = INV_ICM20602_WHOAMI_VALUE,
+ .name = "ICM20602",
+ .reg = &reg_set_icm20602,
+ .config = &chip_config_6050,
+ },
};
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index dd758e3d403d..e46eb4ddea21 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -127,6 +127,7 @@ static int inv_mpu_probe(struct i2c_client *client,
st = iio_priv(dev_get_drvdata(&client->dev));
switch (st->chip_type) {
case INV_ICM20608:
+ case INV_ICM20602:
/* no i2c auxiliary bus on the chip */
break;
default:
@@ -179,6 +180,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},
+ {"icm20602", INV_ICM20602},
{}
};
@@ -213,6 +215,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,icm20608",
.data = (void *)INV_ICM20608
},
+ {
+ .compatible = "invensense,icm20602",
+ .data = (void *)INV_ICM20602
+ },
{ }
};
MODULE_DEVICE_TABLE(of, inv_of_match);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 6bcc11fc1b88..325afd9f5f61 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -44,6 +44,7 @@
* @int_pin_cfg; Controls interrupt pin configuration.
* @accl_offset: Controls the accelerometer calibration offset.
* @gyro_offset: Controls the gyroscope calibration offset.
+ * @i2c_if: Controls the i2c interface
*/
struct inv_mpu6050_reg_map {
u8 sample_rate_div;
@@ -65,6 +66,7 @@ struct inv_mpu6050_reg_map {
u8 int_pin_cfg;
u8 accl_offset;
u8 gyro_offset;
+ u8 i2c_if;
};
/*device enum */
@@ -77,6 +79,7 @@ enum inv_devices {
INV_MPU9250,
INV_MPU9255,
INV_ICM20608,
+ INV_ICM20602,
INV_NUM_PARTS
};
@@ -195,6 +198,10 @@ struct inv_mpu6050_state {
#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
+/* ICM20602 register */
+#define INV_ICM20602_REG_I2C_IF 0x70
+#define INV_ICM20602_BIT_I2C_IF_DIS 0x40
+
#define INV_MPU6050_REG_FIFO_COUNT_H 0x72
#define INV_MPU6050_REG_FIFO_R_W 0x74
@@ -261,6 +268,7 @@ struct inv_mpu6050_state {
#define INV_MPU9255_WHOAMI_VALUE 0x73
#define INV_MPU6515_WHOAMI_VALUE 0x74
#define INV_ICM20608_WHOAMI_VALUE 0xAF
+#define INV_ICM20602_WHOAMI_VALUE 0x12
/* scan element definition */
enum inv_mpu6050_scan {
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 227f50afff22..a112c3f45f74 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -31,9 +31,14 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
if (ret)
return ret;
- st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS;
- ret = regmap_write(st->map, st->reg->user_ctrl,
- st->chip_config.user_ctrl);
+ if (st->reg->i2c_if) {
+ ret = regmap_write(st->map, st->reg->i2c_if,
+ INV_ICM20602_BIT_I2C_IF_DIS);
+ } else {
+ st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS;
+ ret = regmap_write(st->map, st->reg->user_ctrl,
+ st->chip_config.user_ctrl);
+ }
if (ret) {
inv_mpu6050_set_power_itg(st, false);
return ret;
@@ -81,6 +86,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},
+ {"icm20602", INV_ICM20602},
{}
};
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
index 8e47dccdd40f..66fbcd94642d 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
@@ -105,12 +105,10 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
static int st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 addr,
u8 *data, int len)
{
- const struct st_lsm6dsx_shub_settings *hub_settings;
int err;
mutex_lock(&hw->page_lock);
- hub_settings = &hw->settings->shub_settings;
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
goto out;
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 4f5cd9f60870..4700fd5d8c90 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -87,6 +87,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_GRAVITY] = "gravity",
[IIO_POSITIONRELATIVE] = "positionrelative",
[IIO_PHASE] = "phase",
+ [IIO_MASSCONCENTRATION] = "massconcentration",
};
static const char * const iio_modifier_names[] = {
@@ -127,6 +128,10 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_Q] = "q",
[IIO_MOD_CO2] = "co2",
[IIO_MOD_VOC] = "voc",
+ [IIO_MOD_PM1] = "pm1",
+ [IIO_MOD_PM2P5] = "pm2p5",
+ [IIO_MOD_PM4] = "pm4",
+ [IIO_MOD_PM10] = "pm10",
};
/* relies on pairs of these shared then separate */
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 36f458433480..5190eacfeb0a 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -299,6 +299,16 @@ config MAX44000
To compile this driver as a module, choose M here:
the module will be called max44000.
+config MAX44009
+ tristate "MAX44009 Ambient Light Sensor"
+ depends on I2C
+ help
+ Say Y here if you want to build support for Maxim Integrated's
+ MAX44009 ambient light sensor device.
+
+ To compile this driver as a module, choose M here:
+ the module will be called max44009.
+
config OPT3001
tristate "Texas Instruments OPT3001 Light Sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 286bf3975372..e40794fbb435 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_LV0104CS) += lv0104cs.o
obj-$(CONFIG_MAX44000) += max44000.o
+obj-$(CONFIG_MAX44009) += max44009.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c
index b45400f8fef4..846df4dce48c 100644
--- a/drivers/iio/light/isl29018.c
+++ b/drivers/iio/light/isl29018.c
@@ -23,6 +23,7 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -95,6 +96,7 @@ struct isl29018_chip {
struct isl29018_scale scale;
int prox_scheme;
bool suspended;
+ struct regulator *vcc_reg;
};
static int isl29018_set_integration_time(struct isl29018_chip *chip,
@@ -708,6 +710,16 @@ static const char *isl29018_match_acpi_device(struct device *dev, int *data)
return dev_name(dev);
}
+static void isl29018_disable_regulator_action(void *_data)
+{
+ struct isl29018_chip *chip = _data;
+ int err;
+
+ err = regulator_disable(chip->vcc_reg);
+ if (err)
+ pr_err("failed to disable isl29018's VCC regulator!\n");
+}
+
static int isl29018_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -742,6 +754,27 @@ static int isl29018_probe(struct i2c_client *client,
chip->scale = isl29018_scales[chip->int_time][0];
chip->suspended = false;
+ chip->vcc_reg = devm_regulator_get(&client->dev, "vcc");
+ if (IS_ERR(chip->vcc_reg)) {
+ err = PTR_ERR(chip->vcc_reg);
+ if (err != -EPROBE_DEFER)
+ dev_err(&client->dev, "failed to get VCC regulator!\n");
+ return err;
+ }
+
+ err = regulator_enable(chip->vcc_reg);
+ if (err) {
+ dev_err(&client->dev, "failed to enable VCC regulator!\n");
+ return err;
+ }
+
+ err = devm_add_action_or_reset(&client->dev, isl29018_disable_regulator_action,
+ chip);
+ if (err) {
+ dev_err(&client->dev, "failed to setup regulator cleanup action!\n");
+ return err;
+ }
+
chip->regmap = devm_regmap_init_i2c(client,
isl29018_chip_info_tbl[dev_id].regmap_cfg);
if (IS_ERR(chip->regmap)) {
@@ -768,6 +801,7 @@ static int isl29018_probe(struct i2c_client *client,
static int isl29018_suspend(struct device *dev)
{
struct isl29018_chip *chip = iio_priv(dev_get_drvdata(dev));
+ int ret;
mutex_lock(&chip->lock);
@@ -777,10 +811,13 @@ static int isl29018_suspend(struct device *dev)
* So we do not have much to do here.
*/
chip->suspended = true;
+ ret = regulator_disable(chip->vcc_reg);
+ if (ret)
+ dev_err(dev, "failed to disable VCC regulator\n");
mutex_unlock(&chip->lock);
- return 0;
+ return ret;
}
static int isl29018_resume(struct device *dev)
@@ -790,6 +827,13 @@ static int isl29018_resume(struct device *dev)
mutex_lock(&chip->lock);
+ err = regulator_enable(chip->vcc_reg);
+ if (err) {
+ dev_err(dev, "failed to enable VCC regulator\n");
+ mutex_unlock(&chip->lock);
+ return err;
+ }
+
err = isl29018_chip_init(chip);
if (!err)
chip->suspended = false;
diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c
new file mode 100644
index 000000000000..00ba15499638
--- /dev/null
+++ b/drivers/iio/light/max44009.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * max44009.c - Support for MAX44009 Ambient Light Sensor
+ *
+ * Copyright (c) 2019 Robert Eshleman <bobbyeshleman@gmail.com>
+ *
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX44009.pdf
+ *
+ * TODO: Support continuous mode and configuring from manual mode to
+ * automatic mode.
+ *
+ * Default I2C address: 0x4a
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/util_macros.h>
+
+#define MAX44009_DRV_NAME "max44009"
+
+/* Registers in datasheet order */
+#define MAX44009_REG_INT_STATUS 0x0
+#define MAX44009_REG_INT_EN 0x1
+#define MAX44009_REG_CFG 0x2
+#define MAX44009_REG_LUX_HI 0x3
+#define MAX44009_REG_LUX_LO 0x4
+#define MAX44009_REG_UPPER_THR 0x5
+#define MAX44009_REG_LOWER_THR 0x6
+#define MAX44009_REG_THR_TIMER 0x7
+
+#define MAX44009_CFG_TIM_MASK GENMASK(2, 0)
+#define MAX44009_CFG_MAN_MODE_MASK BIT(6)
+
+/* The maximum rising threshold for the max44009 */
+#define MAX44009_MAXIMUM_THRESHOLD 7520256
+
+#define MAX44009_THRESH_EXP_MASK (0xf << 4)
+#define MAX44009_THRESH_EXP_RSHIFT 4
+#define MAX44009_THRESH_MANT_LSHIFT 4
+#define MAX44009_THRESH_MANT_MASK 0xf
+
+#define MAX44009_UPPER_THR_MINIMUM 15
+
+/* The max44009 always scales raw readings by 0.045 and is non-configurable */
+#define MAX44009_SCALE_NUMERATOR 45
+#define MAX44009_SCALE_DENOMINATOR 1000
+
+/* The fixed-point fractional multiplier for de-scaling threshold values */
+#define MAX44009_FRACT_MULT 1000000
+
+static const u32 max44009_int_time_ns_array[] = {
+ 800000000,
+ 400000000,
+ 200000000,
+ 100000000,
+ 50000000, /* Manual mode only */
+ 25000000, /* Manual mode only */
+ 12500000, /* Manual mode only */
+ 6250000, /* Manual mode only */
+};
+
+static const char max44009_int_time_str[] =
+ "0.8 "
+ "0.4 "
+ "0.2 "
+ "0.1 "
+ "0.05 "
+ "0.025 "
+ "0.0125 "
+ "0.00625";
+
+struct max44009_data {
+ struct i2c_client *client;
+ struct mutex lock;
+};
+
+static const struct iio_event_spec max44009_event_spec[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static const struct iio_chan_spec max44009_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ .event_spec = max44009_event_spec,
+ .num_event_specs = ARRAY_SIZE(max44009_event_spec),
+ },
+};
+
+static int max44009_read_int_time(struct max44009_data *data)
+{
+
+ int ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_CFG);
+
+ if (ret < 0)
+ return ret;
+
+ return max44009_int_time_ns_array[ret & MAX44009_CFG_TIM_MASK];
+}
+
+static int max44009_write_int_time(struct max44009_data *data,
+ int val, int val2)
+{
+ struct i2c_client *client = data->client;
+ int ret, int_time, config;
+ s64 ns;
+
+ ns = val * NSEC_PER_SEC + val2;
+ int_time = find_closest_descending(
+ ns,
+ max44009_int_time_ns_array,
+ ARRAY_SIZE(max44009_int_time_ns_array));
+
+ ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG);
+ if (ret < 0)
+ return ret;
+
+ config = ret;
+ config &= int_time;
+
+ /*
+ * To set the integration time, the device must also be in manual
+ * mode.
+ */
+ config |= MAX44009_CFG_MAN_MODE_MASK;
+
+ return i2c_smbus_write_byte_data(client, MAX44009_REG_CFG, config);
+}
+
+static int max44009_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct max44009_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT) {
+ mutex_lock(&data->lock);
+ ret = max44009_write_int_time(data, val, val2);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+ return -EINVAL;
+}
+
+static int max44009_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int max44009_lux_raw(u8 hi, u8 lo)
+{
+ int mantissa;
+ int exponent;
+
+ /*
+ * The mantissa consists of the low nibble of the Lux High Byte
+ * and the low nibble of the Lux Low Byte.
+ */
+ mantissa = ((hi & 0xf) << 4) | (lo & 0xf);
+
+ /* The exponent byte is just the upper nibble of the Lux High Byte */
+ exponent = (hi >> 4) & 0xf;
+
+ /*
+ * The exponent value is base 2 to the power of the raw exponent byte.
+ */
+ exponent = 1 << exponent;
+
+ return exponent * mantissa;
+}
+
+#define MAX44009_READ_LUX_XFER_LEN (4)
+
+static int max44009_read_lux_raw(struct max44009_data *data)
+{
+ int ret;
+ u8 hireg = MAX44009_REG_LUX_HI;
+ u8 loreg = MAX44009_REG_LUX_LO;
+ u8 lo = 0;
+ u8 hi = 0;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = data->client->addr,
+ .flags = 0,
+ .len = sizeof(hireg),
+ .buf = &hireg,
+ },
+ {
+ .addr = data->client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(hi),
+ .buf = &hi,
+ },
+ {
+ .addr = data->client->addr,
+ .flags = 0,
+ .len = sizeof(loreg),
+ .buf = &loreg,
+ },
+ {
+ .addr = data->client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(lo),
+ .buf = &lo,
+ }
+ };
+
+ /*
+ * Use i2c_transfer instead of smbus read because i2c_transfer
+ * does NOT use a stop bit between address write and data read.
+ * Using a stop bit causes disjoint upper/lower byte reads and
+ * reduces accuracy.
+ */
+ ret = i2c_transfer(data->client->adapter,
+ msgs, MAX44009_READ_LUX_XFER_LEN);
+
+ if (ret != MAX44009_READ_LUX_XFER_LEN)
+ return -EIO;
+
+ return max44009_lux_raw(hi, lo);
+}
+
+static int max44009_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct max44009_data *data = iio_priv(indio_dev);
+ int lux_raw;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = max44009_read_lux_raw(data);
+ if (ret < 0)
+ return ret;
+ lux_raw = ret;
+
+ *val = lux_raw * MAX44009_SCALE_NUMERATOR;
+ *val2 = MAX44009_SCALE_DENOMINATOR;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_INT_TIME:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = max44009_read_int_time(data);
+ if (ret < 0)
+ return ret;
+
+ *val2 = ret;
+ *val = 0;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static IIO_CONST_ATTR(illuminance_integration_time_available,
+ max44009_int_time_str);
+
+static struct attribute *max44009_attributes[] = {
+ &iio_const_attr_illuminance_integration_time_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group max44009_attribute_group = {
+ .attrs = max44009_attributes,
+};
+
+static int max44009_threshold_byte_from_fraction(int integral, int fractional)
+{
+ int mantissa, exp;
+
+ if ((integral <= 0 && fractional <= 0) ||
+ integral > MAX44009_MAXIMUM_THRESHOLD ||
+ (integral == MAX44009_MAXIMUM_THRESHOLD && fractional != 0))
+ return -EINVAL;
+
+ /* Reverse scaling of fixed-point integral */
+ mantissa = integral * MAX44009_SCALE_DENOMINATOR;
+ mantissa /= MAX44009_SCALE_NUMERATOR;
+
+ /* Reverse scaling of fixed-point fractional */
+ mantissa += fractional / MAX44009_FRACT_MULT *
+ (MAX44009_SCALE_DENOMINATOR / MAX44009_SCALE_NUMERATOR);
+
+ for (exp = 0; mantissa > 0xff; exp++)
+ mantissa >>= 1;
+
+ mantissa >>= 4;
+ mantissa &= 0xf;
+ exp <<= 4;
+
+ return exp | mantissa;
+}
+
+static int max44009_get_thr_reg(enum iio_event_direction dir)
+{
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return MAX44009_REG_UPPER_THR;
+ case IIO_EV_DIR_FALLING:
+ return MAX44009_REG_LOWER_THR;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int max44009_write_event_value(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)
+{
+ struct max44009_data *data = iio_priv(indio_dev);
+ int reg, threshold;
+
+ if (info != IIO_EV_INFO_VALUE || chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ threshold = max44009_threshold_byte_from_fraction(val, val2);
+ if (threshold < 0)
+ return threshold;
+
+ reg = max44009_get_thr_reg(dir);
+ if (reg < 0)
+ return reg;
+
+ return i2c_smbus_write_byte_data(data->client, reg, threshold);
+}
+
+static int max44009_read_threshold(struct iio_dev *indio_dev,
+ enum iio_event_direction dir)
+{
+ struct max44009_data *data = iio_priv(indio_dev);
+ int byte, reg;
+ int mantissa, exponent;
+
+ reg = max44009_get_thr_reg(dir);
+ if (reg < 0)
+ return reg;
+
+ byte = i2c_smbus_read_byte_data(data->client, reg);
+ if (byte < 0)
+ return byte;
+
+ mantissa = byte & MAX44009_THRESH_MANT_MASK;
+ mantissa <<= MAX44009_THRESH_MANT_LSHIFT;
+
+ /*
+ * To get the upper threshold, always adds the minimum upper threshold
+ * value to the shifted byte value (see datasheet).
+ */
+ if (dir == IIO_EV_DIR_RISING)
+ mantissa += MAX44009_UPPER_THR_MINIMUM;
+
+ /*
+ * Exponent is base 2 to the power of the threshold exponent byte
+ * value
+ */
+ exponent = byte & MAX44009_THRESH_EXP_MASK;
+ exponent >>= MAX44009_THRESH_EXP_RSHIFT;
+
+ return (1 << exponent) * mantissa;
+}
+
+static int max44009_read_event_value(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 ret;
+ int threshold;
+
+ if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ ret = max44009_read_threshold(indio_dev, dir);
+ if (ret < 0)
+ return ret;
+ threshold = ret;
+
+ *val = threshold * MAX44009_SCALE_NUMERATOR;
+ *val2 = MAX44009_SCALE_DENOMINATOR;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int max44009_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)
+{
+ struct max44009_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ MAX44009_REG_INT_EN, state);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Set device to trigger interrupt immediately upon exceeding
+ * the threshold limit.
+ */
+ return i2c_smbus_write_byte_data(data->client,
+ MAX44009_REG_THR_TIMER, 0);
+}
+
+static int max44009_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 max44009_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ return i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_EN);
+}
+
+static const struct iio_info max44009_info = {
+ .read_raw = max44009_read_raw,
+ .write_raw = max44009_write_raw,
+ .write_raw_get_fmt = max44009_write_raw_get_fmt,
+ .read_event_value = max44009_read_event_value,
+ .read_event_config = max44009_read_event_config,
+ .write_event_value = max44009_write_event_value,
+ .write_event_config = max44009_write_event_config,
+ .attrs = &max44009_attribute_group,
+};
+
+static irqreturn_t max44009_threaded_irq_handler(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct max44009_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_STATUS);
+ if (ret) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns(indio_dev));
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int max44009_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max44009_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &max44009_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = MAX44009_DRV_NAME;
+ indio_dev->channels = max44009_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max44009_channels);
+ mutex_init(&data->lock);
+
+ /* Clear any stale interrupt bit */
+ ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG);
+ if (ret < 0)
+ return ret;
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL,
+ max44009_threaded_irq_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT | IRQF_SHARED,
+ "max44009_event",
+ indio_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id max44009_id[] = {
+ { "max44009", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max44009_id);
+
+static struct i2c_driver max44009_driver = {
+ .driver = {
+ .name = MAX44009_DRV_NAME,
+ },
+ .probe = max44009_probe,
+ .id_table = max44009_id,
+};
+module_i2c_driver(max44009_driver);
+
+static const struct of_device_id max44009_of_match[] = {
+ { .compatible = "maxim,max44009" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max44009_of_match);
+
+MODULE_AUTHOR("Robert Eshleman <bobbyeshleman@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MAX44009 ambient light sensor driver");
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index f063355480ba..dd990cdb04a8 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -20,6 +20,7 @@
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
#define MAG3110_STATUS 0x00
#define MAG3110_OUT_X 0x01 /* MSB first */
@@ -56,6 +57,8 @@ struct mag3110_data {
struct mutex lock;
u8 ctrl_reg1;
int sleep_val;
+ struct regulator *vdd_reg;
+ struct regulator *vddio_reg;
};
static int mag3110_request(struct mag3110_data *data)
@@ -469,17 +472,50 @@ static int mag3110_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret;
- ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I);
- if (ret < 0)
- return ret;
- if (ret != MAG3110_DEVICE_ID)
- return -ENODEV;
-
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
+
+ data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(data->vdd_reg)) {
+ if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_err(&client->dev, "failed to get VDD regulator!\n");
+ return PTR_ERR(data->vdd_reg);
+ }
+
+ data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
+ if (IS_ERR(data->vddio_reg)) {
+ if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_err(&client->dev, "failed to get VDDIO regulator!\n");
+ return PTR_ERR(data->vddio_reg);
+ }
+
+ ret = regulator_enable(data->vdd_reg);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable VDD regulator!\n");
+ return ret;
+ }
+
+ ret = regulator_enable(data->vddio_reg);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable VDDIO regulator!\n");
+ goto disable_regulator_vdd;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, MAG3110_WHO_AM_I);
+ if (ret < 0)
+ goto disable_regulators;
+ if (ret != MAG3110_DEVICE_ID) {
+ ret = -ENODEV;
+ goto disable_regulators;
+ }
+
data->client = client;
mutex_init(&data->lock);
@@ -499,7 +535,7 @@ static int mag3110_probe(struct i2c_client *client,
ret = mag3110_change_config(data, MAG3110_CTRL_REG1, data->ctrl_reg1);
if (ret < 0)
- return ret;
+ goto disable_regulators;
ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2,
MAG3110_CTRL_AUTO_MRST_EN);
@@ -520,16 +556,24 @@ buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
standby_on_error:
mag3110_standby(iio_priv(indio_dev));
+disable_regulators:
+ regulator_disable(data->vddio_reg);
+disable_regulator_vdd:
+ regulator_disable(data->vdd_reg);
+
return ret;
}
static int mag3110_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mag3110_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
mag3110_standby(iio_priv(indio_dev));
+ regulator_disable(data->vddio_reg);
+ regulator_disable(data->vdd_reg);
return 0;
}
@@ -537,14 +581,48 @@ static int mag3110_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int mag3110_suspend(struct device *dev)
{
- return mag3110_standby(iio_priv(i2c_get_clientdata(
+ struct mag3110_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+ int ret;
+
+ ret = mag3110_standby(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
+ if (ret)
+ return ret;
+
+ ret = regulator_disable(data->vddio_reg);
+ if (ret) {
+ dev_err(dev, "failed to disable VDDIO regulator\n");
+ return ret;
+ }
+
+ ret = regulator_disable(data->vdd_reg);
+ if (ret) {
+ dev_err(dev, "failed to disable VDD regulator\n");
+ return ret;
+ }
+
+ return 0;
}
static int mag3110_resume(struct device *dev)
{
struct mag3110_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
+ int ret;
+
+ ret = regulator_enable(data->vdd_reg);
+ if (ret) {
+ dev_err(dev, "failed to enable VDD regulator\n");
+ return ret;
+ }
+
+ ret = regulator_enable(data->vddio_reg);
+ if (ret) {
+ dev_err(dev, "failed to enable VDDIO regulator\n");
+ regulator_disable(data->vdd_reg);
+ return ret;
+ }
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1);
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index eaa7cfcb4c2a..efeb89f3df71 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -165,7 +165,7 @@ config IIO_ST_PRESS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics pressure
- sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB.
+ sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB, LPS22HH.
This driver can also be built as a module. If so, these modules
will be created:
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index e67eb0d971bf..57946605f3ba 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -21,6 +21,7 @@ enum st_press_type {
LPS22HB,
LPS33HW,
LPS35HW,
+ LPS22HH,
ST_PRESS_MAX,
};
@@ -30,6 +31,7 @@ enum st_press_type {
#define LPS22HB_PRESS_DEV_NAME "lps22hb"
#define LPS33HW_PRESS_DEV_NAME "lps33hw"
#define LPS35HW_PRESS_DEV_NAME "lps35hw"
+#define LPS22HH_PRESS_DEV_NAME "lps22hh"
/**
* struct st_sensors_platform_data - default press platform data
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 4ddb6cf7d401..38dcdb7c000e 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -492,6 +492,75 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.multi_read_bit = false,
.bootime = 2,
},
+ {
+ /*
+ * CUSTOM VALUES FOR LPS22HH SENSOR
+ * See LPS22HH datasheet:
+ * http://www2.st.com/resource/en/datasheet/lps22hh.pdf
+ */
+ .wai = 0xb3,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
+ .sensors_supported = {
+ [0] = LPS22HH_PRESS_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_press_lps22hb_channels,
+ .num_ch = ARRAY_SIZE(st_press_lps22hb_channels),
+ .odr = {
+ .addr = 0x10,
+ .mask = 0x70,
+ .odr_avl = {
+ { .hz = 1, .value = 0x01 },
+ { .hz = 10, .value = 0x02 },
+ { .hz = 25, .value = 0x03 },
+ { .hz = 50, .value = 0x04 },
+ { .hz = 75, .value = 0x05 },
+ { .hz = 100, .value = 0x06 },
+ { .hz = 200, .value = 0x07 },
+ },
+ },
+ .pw = {
+ .addr = 0x10,
+ .mask = 0x70,
+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
+ },
+ .fs = {
+ .fs_avl = {
+ /*
+ * Pressure and temperature sensitivity values
+ * as defined in table 3 of LPS22HH datasheet.
+ */
+ [0] = {
+ .num = ST_PRESS_FS_AVL_1260MB,
+ .gain = ST_PRESS_KPASCAL_NANO_SCALE,
+ .gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS,
+ },
+ },
+ },
+ .bdu = {
+ .addr = 0x10,
+ .mask = BIT(1),
+ },
+ .drdy_irq = {
+ .int1 = {
+ .addr = 0x12,
+ .mask = BIT(2),
+ .addr_od = 0x11,
+ .mask_od = BIT(5),
+ },
+ .addr_ihl = 0x11,
+ .mask_ihl = BIT(6),
+ .stat_drdy = {
+ .addr = ST_SENSORS_DEFAULT_STAT_ADDR,
+ .mask = 0x03,
+ },
+ },
+ .sim = {
+ .addr = 0x10,
+ .value = BIT(0),
+ },
+ .multi_read_bit = false,
+ .bootime = 2,
+ },
};
static int st_press_write_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 2026a1012012..a60849dd4ea7 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -45,6 +45,10 @@ static const struct of_device_id st_press_of_match[] = {
.compatible = "st,lps35hw",
.data = LPS35HW_PRESS_DEV_NAME,
},
+ {
+ .compatible = "st,lps22hh",
+ .data = LPS22HH_PRESS_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_press_of_match);
@@ -69,6 +73,7 @@ static const struct i2c_device_id st_press_id_table[] = {
{ LPS22HB_PRESS_DEV_NAME, LPS22HB },
{ LPS33HW_PRESS_DEV_NAME, LPS33HW },
{ LPS35HW_PRESS_DEV_NAME, LPS35HW },
+ { LPS22HH_PRESS_DEV_NAME, LPS22HH },
{},
};
MODULE_DEVICE_TABLE(i2c, st_press_id_table);
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 9a3441b128e7..79a12ed46e54 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -49,6 +49,10 @@ static const struct of_device_id st_press_of_match[] = {
.compatible = "st,lps35hw",
.data = LPS35HW_PRESS_DEV_NAME,
},
+ {
+ .compatible = "st,lps22hh",
+ .data = LPS22HH_PRESS_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_press_of_match);
@@ -93,6 +97,7 @@ static const struct spi_device_id st_press_id_table[] = {
{ LPS22HB_PRESS_DEV_NAME },
{ LPS33HW_PRESS_DEV_NAME },
{ LPS35HW_PRESS_DEV_NAME },
+ { LPS22HH_PRESS_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_press_id_table);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e4f608815c05..c0901b96cfe4 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -56,8 +56,6 @@ source "drivers/staging/iio/Kconfig"
source "drivers/staging/sm750fb/Kconfig"
-source "drivers/staging/xgifb/Kconfig"
-
source "drivers/staging/emxx_udc/Kconfig"
source "drivers/staging/speakup/Kconfig"
@@ -104,12 +102,16 @@ source "drivers/staging/pi433/Kconfig"
source "drivers/staging/mt7621-pci/Kconfig"
+source "drivers/staging/mt7621-pci-phy/Kconfig"
+
source "drivers/staging/mt7621-pinctrl/Kconfig"
source "drivers/staging/mt7621-spi/Kconfig"
source "drivers/staging/mt7621-dma/Kconfig"
+source "drivers/staging/ralink-gdma/Kconfig"
+
source "drivers/staging/mt7621-mmc/Kconfig"
source "drivers/staging/mt7621-eth/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 5868631e8f1b..57c6bce13ff4 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_SM750) += sm750fb/
-obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_MFD_NVEC) += nvec/
@@ -41,12 +40,14 @@ obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
obj-$(CONFIG_PI433) += pi433/
-obj-$(CONFIG_SOC_MT7621) += mt7621-pci/
-obj-$(CONFIG_SOC_MT7621) += mt7621-pinctrl/
-obj-$(CONFIG_SOC_MT7621) += mt7621-spi/
+obj-$(CONFIG_PCI_MT7621) += mt7621-pci/
+obj-$(CONFIG_PCI_MT7621_PHY) += mt7621-pci-phy/
+obj-$(CONFIG_PINCTRL_RT2880) += mt7621-pinctrl/
+obj-$(CONFIG_SPI_MT7621) += mt7621-spi/
obj-$(CONFIG_SOC_MT7621) += mt7621-dma/
-obj-$(CONFIG_SOC_MT7621) += mt7621-mmc/
-obj-$(CONFIG_SOC_MT7621) += mt7621-eth/
+obj-$(CONFIG_DMA_RALINK) += ralink-gdma/
+obj-$(CONFIG_MTK_MMC) += mt7621-mmc/
+obj-$(CONFIG_NET_MEDIATEK_SOC_STAGING) += mt7621-eth/
obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 90a8a9f1ac7d..74d497d39c5a 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -75,6 +75,9 @@ struct ashmem_range {
/* LRU list of unpinned pages, protected by ashmem_mutex */
static LIST_HEAD(ashmem_lru_list);
+static atomic_t ashmem_shrink_inflight = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(ashmem_shrink_wait);
+
/*
* long lru_count - The count of pages on our LRU list.
*
@@ -126,7 +129,8 @@ static inline bool page_range_in_range(struct ashmem_range *range,
page_range_subsumes_range(range, start, end);
}
-static inline bool range_before_page(struct ashmem_range *range, size_t page)
+static inline bool range_before_page(struct ashmem_range *range,
+ size_t page)
{
return range->pgend < page;
}
@@ -168,19 +172,15 @@ static inline void lru_del(struct ashmem_range *range)
* @end: The ending page (inclusive)
*
* This function is protected by ashmem_mutex.
- *
- * Return: 0 if successful, or -ENOMEM if there is an error
*/
-static int range_alloc(struct ashmem_area *asma,
- struct ashmem_range *prev_range, unsigned int purged,
- size_t start, size_t end)
+static void range_alloc(struct ashmem_area *asma,
+ struct ashmem_range *prev_range, unsigned int purged,
+ size_t start, size_t end,
+ struct ashmem_range **new_range)
{
- struct ashmem_range *range;
-
- range = kmem_cache_zalloc(ashmem_range_cachep, GFP_KERNEL);
- if (!range)
- return -ENOMEM;
+ struct ashmem_range *range = *new_range;
+ *new_range = NULL;
range->asma = asma;
range->pgstart = start;
range->pgend = end;
@@ -190,8 +190,6 @@ static int range_alloc(struct ashmem_area *asma,
if (range_on_lru(range))
lru_add(range);
-
- return 0;
}
/**
@@ -438,7 +436,6 @@ out:
static unsigned long
ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
{
- struct ashmem_range *range, *next;
unsigned long freed = 0;
/* We might recurse into filesystem code, so bail out if necessary */
@@ -448,21 +445,33 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
if (!mutex_trylock(&ashmem_mutex))
return -1;
- list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
+ while (!list_empty(&ashmem_lru_list)) {
+ struct ashmem_range *range =
+ list_first_entry(&ashmem_lru_list, typeof(*range), lru);
loff_t start = range->pgstart * PAGE_SIZE;
loff_t end = (range->pgend + 1) * PAGE_SIZE;
+ struct file *f = range->asma->file;
- range->asma->file->f_op->fallocate(range->asma->file,
- FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
- start, end - start);
+ get_file(f);
+ atomic_inc(&ashmem_shrink_inflight);
range->purged = ASHMEM_WAS_PURGED;
lru_del(range);
freed += range_size(range);
+ mutex_unlock(&ashmem_mutex);
+ f->f_op->fallocate(f,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ start, end - start);
+ fput(f);
+ if (atomic_dec_and_test(&ashmem_shrink_inflight))
+ wake_up_all(&ashmem_shrink_wait);
+ if (!mutex_trylock(&ashmem_mutex))
+ goto out;
if (--sc->nr_to_scan <= 0)
break;
}
mutex_unlock(&ashmem_mutex);
+out:
return freed;
}
@@ -582,7 +591,8 @@ static int get_name(struct ashmem_area *asma, void __user *name)
*
* Caller must hold ashmem_mutex.
*/
-static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend)
+static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend,
+ struct ashmem_range **new_range)
{
struct ashmem_range *range, *next;
int ret = ASHMEM_NOT_PURGED;
@@ -635,7 +645,7 @@ static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend)
* second half and adjust the first chunk's endpoint.
*/
range_alloc(asma, range, range->purged,
- pgend + 1, range->pgend);
+ pgend + 1, range->pgend, new_range);
range_shrink(range, range->pgstart, pgstart - 1);
break;
}
@@ -649,7 +659,8 @@ static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend)
*
* Caller must hold ashmem_mutex.
*/
-static int ashmem_unpin(struct ashmem_area *asma, size_t pgstart, size_t pgend)
+static int ashmem_unpin(struct ashmem_area *asma, size_t pgstart, size_t pgend,
+ struct ashmem_range **new_range)
{
struct ashmem_range *range, *next;
unsigned int purged = ASHMEM_NOT_PURGED;
@@ -675,7 +686,8 @@ restart:
}
}
- return range_alloc(asma, range, purged, pgstart, pgend);
+ range_alloc(asma, range, purged, pgstart, pgend, new_range);
+ return 0;
}
/*
@@ -708,11 +720,19 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
struct ashmem_pin pin;
size_t pgstart, pgend;
int ret = -EINVAL;
+ struct ashmem_range *range = NULL;
if (copy_from_user(&pin, p, sizeof(pin)))
return -EFAULT;
+ if (cmd == ASHMEM_PIN || cmd == ASHMEM_UNPIN) {
+ range = kmem_cache_zalloc(ashmem_range_cachep, GFP_KERNEL);
+ if (!range)
+ return -ENOMEM;
+ }
+
mutex_lock(&ashmem_mutex);
+ wait_event(ashmem_shrink_wait, !atomic_read(&ashmem_shrink_inflight));
if (!asma->file)
goto out_unlock;
@@ -735,10 +755,10 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
switch (cmd) {
case ASHMEM_PIN:
- ret = ashmem_pin(asma, pgstart, pgend);
+ ret = ashmem_pin(asma, pgstart, pgend, &range);
break;
case ASHMEM_UNPIN:
- ret = ashmem_unpin(asma, pgstart, pgend);
+ ret = ashmem_unpin(asma, pgstart, pgend, &range);
break;
case ASHMEM_GET_PIN_STATUS:
ret = ashmem_get_pin_status(asma, pgstart, pgend);
@@ -747,6 +767,8 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
out_unlock:
mutex_unlock(&ashmem_mutex);
+ if (range)
+ kmem_cache_free(ashmem_range_cachep, range);
return ret;
}
diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile
index bb30bf8774a0..17f3a7569e3d 100644
--- a/drivers/staging/android/ion/Makefile
+++ b/drivers/staging/android/ion/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o
+obj-$(CONFIG_ION) += ion.o ion_heap.o
obj-$(CONFIG_ION_SYSTEM_HEAP) += ion_system_heap.o ion_page_pool.o
obj-$(CONFIG_ION_CARVEOUT_HEAP) += ion_carveout_heap.o
obj-$(CONFIG_ION_CHUNK_HEAP) += ion_chunk_heap.o
diff --git a/drivers/staging/android/ion/ion-ioctl.c b/drivers/staging/android/ion/ion-ioctl.c
deleted file mode 100644
index a8d3cc412fb9..000000000000
--- a/drivers/staging/android/ion/ion-ioctl.c
+++ /dev/null
@@ -1,98 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2011 Google, Inc.
- */
-
-#include <linux/kernel.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-
-#include "ion.h"
-
-union ion_ioctl_arg {
- struct ion_allocation_data allocation;
- struct ion_heap_query query;
-};
-
-static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg)
-{
- switch (cmd) {
- case ION_IOC_HEAP_QUERY:
- if (arg->query.reserved0 ||
- arg->query.reserved1 ||
- arg->query.reserved2)
- return -EINVAL;
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-/* fix up the cases where the ioctl direction bits are incorrect */
-static unsigned int ion_ioctl_dir(unsigned int cmd)
-{
- switch (cmd) {
- default:
- return _IOC_DIR(cmd);
- }
-}
-
-long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
- unsigned int dir;
- union ion_ioctl_arg data;
-
- dir = ion_ioctl_dir(cmd);
-
- if (_IOC_SIZE(cmd) > sizeof(data))
- return -EINVAL;
-
- /*
- * The copy_from_user is unconditional here for both read and write
- * to do the validate. If there is no write for the ioctl, the
- * buffer is cleared
- */
- if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
- return -EFAULT;
-
- ret = validate_ioctl_arg(cmd, &data);
- if (ret) {
- pr_warn_once("%s: ioctl validate failed\n", __func__);
- return ret;
- }
-
- if (!(dir & _IOC_WRITE))
- memset(&data, 0, sizeof(data));
-
- switch (cmd) {
- case ION_IOC_ALLOC:
- {
- int fd;
-
- fd = ion_alloc(data.allocation.len,
- data.allocation.heap_id_mask,
- data.allocation.flags);
- if (fd < 0)
- return fd;
-
- data.allocation.fd = fd;
-
- break;
- }
- case ION_IOC_HEAP_QUERY:
- ret = ion_query_heaps(&data.query);
- break;
- default:
- return -ENOTTY;
- }
-
- if (dir & _IOC_READ) {
- if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd)))
- return -EFAULT;
- }
- return ret;
-}
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 6f5afab7c1a1..92c2914239e3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1,11 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion.c
+ * ION Memory Allocator
*
* Copyright (C) 2011 Google, Inc.
*/
-#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
@@ -14,10 +13,8 @@
#include <linux/file.h>
#include <linux/freezer.h>
#include <linux/fs.h>
-#include <linux/idr.h>
#include <linux/kthread.h>
#include <linux/list.h>
-#include <linux/memblock.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
@@ -390,7 +387,7 @@ static const struct dma_buf_ops dma_buf_ops = {
.unmap = ion_dma_buf_kunmap,
};
-int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
+static int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
{
struct ion_device *dev = internal_dev;
struct ion_buffer *buffer = NULL;
@@ -447,7 +444,7 @@ int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
return fd;
}
-int ion_query_heaps(struct ion_heap_query *query)
+static int ion_query_heaps(struct ion_heap_query *query)
{
struct ion_device *dev = internal_dev;
struct ion_heap_data __user *buffer = u64_to_user_ptr(query->heaps);
@@ -492,6 +489,81 @@ out:
return ret;
}
+union ion_ioctl_arg {
+ struct ion_allocation_data allocation;
+ struct ion_heap_query query;
+};
+
+static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg)
+{
+ switch (cmd) {
+ case ION_IOC_HEAP_QUERY:
+ if (arg->query.reserved0 ||
+ arg->query.reserved1 ||
+ arg->query.reserved2)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ union ion_ioctl_arg data;
+
+ if (_IOC_SIZE(cmd) > sizeof(data))
+ return -EINVAL;
+
+ /*
+ * The copy_from_user is unconditional here for both read and write
+ * to do the validate. If there is no write for the ioctl, the
+ * buffer is cleared
+ */
+ if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+
+ ret = validate_ioctl_arg(cmd, &data);
+ if (ret) {
+ pr_warn_once("%s: ioctl validate failed\n", __func__);
+ return ret;
+ }
+
+ if (!(_IOC_DIR(cmd) & _IOC_WRITE))
+ memset(&data, 0, sizeof(data));
+
+ switch (cmd) {
+ case ION_IOC_ALLOC:
+ {
+ int fd;
+
+ fd = ion_alloc(data.allocation.len,
+ data.allocation.heap_id_mask,
+ data.allocation.flags);
+ if (fd < 0)
+ return fd;
+
+ data.allocation.fd = fd;
+
+ break;
+ }
+ case ION_IOC_HEAP_QUERY:
+ ret = ion_query_heaps(&data.query);
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
static const struct file_operations ion_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = ion_ioctl,
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index 47b594cf1ac9..e291299fd35f 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * drivers/staging/android/ion/ion.h
+ * ION Memory Allocator kernel interface header
*
* Copyright (C) 2011 Google, Inc.
*/
@@ -22,32 +22,9 @@
#include "../uapi/ion.h"
/**
- * struct ion_platform_heap - defines a heap in the given platform
- * @type: type of the heap from ion_heap_type enum
- * @id: unique identifier for heap. When allocating higher numb ers
- * will be allocated from first. At allocation these are passed
- * as a bit mask and therefore can not exceed ION_NUM_HEAP_IDS.
- * @name: used for debug purposes
- * @base: base address of heap in physical memory if applicable
- * @size: size of the heap in bytes if applicable
- * @priv: private info passed from the board file
- *
- * Provided by the board file.
- */
-struct ion_platform_heap {
- enum ion_heap_type type;
- unsigned int id;
- const char *name;
- phys_addr_t base;
- size_t size;
- phys_addr_t align;
- void *priv;
-};
-
-/**
* struct ion_buffer - metadata for a particular buffer
- * @ref: reference count
* @node: node in the ion_device buffers tree
+ * @list: element in list of deferred freeable buffers
* @dev: back pointer to the ion_device
* @heap: back pointer to the heap the buffer came from
* @flags: buffer specific flags
@@ -58,7 +35,8 @@ struct ion_platform_heap {
* @lock: protects the buffers cnt fields
* @kmap_cnt: number of times the buffer is mapped to the kernel
* @vaddr: the kernel mapping if kmap_cnt is not zero
- * @sg_table: the sg table for the buffer if dmap_cnt is not zero
+ * @sg_table: the sg table for the buffer
+ * @attachments: list of devices attached to this buffer
*/
struct ion_buffer {
union {
@@ -174,12 +152,16 @@ struct ion_heap {
unsigned long flags;
unsigned int id;
const char *name;
+
+ /* deferred free support */
struct shrinker shrinker;
struct list_head free_list;
size_t free_list_size;
spinlock_t free_lock;
wait_queue_head_t waitqueue;
struct task_struct *task;
+
+ /* heap statistics */
u64 num_of_buffers;
u64 num_of_alloc_bytes;
u64 alloc_bytes_wm;
@@ -205,10 +187,6 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
-int ion_alloc(size_t len,
- unsigned int heap_id_mask,
- unsigned int flags);
-
/**
* ion_heap_init_shrinker
* @heap: the heap
@@ -330,8 +308,4 @@ void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
int nr_to_scan);
-long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-
-int ion_query_heaps(struct ion_heap_query *query);
-
#endif /* _ION_H */
diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c
index e129237a0417..bb9d614767a2 100644
--- a/drivers/staging/android/ion/ion_carveout_heap.c
+++ b/drivers/staging/android/ion/ion_carveout_heap.c
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_carveout_heap.c
+ * ION Memory Allocator carveout heap helper
*
* Copyright (C) 2011 Google, Inc.
*/
-#include <linux/spinlock.h>
+
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/genalloc.h>
@@ -12,7 +12,7 @@
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
+
#include "ion.h"
#define ION_CARVEOUT_ALLOCATE_FAIL -1
@@ -20,7 +20,6 @@
struct ion_carveout_heap {
struct ion_heap heap;
struct gen_pool *pool;
- phys_addr_t base;
};
static phys_addr_t ion_carveout_allocate(struct ion_heap *heap,
@@ -44,6 +43,7 @@ static void ion_carveout_free(struct ion_heap *heap, phys_addr_t addr,
if (addr == ION_CARVEOUT_ALLOCATE_FAIL)
return;
+
gen_pool_free(carveout_heap->pool, addr, size);
}
@@ -103,17 +103,14 @@ static struct ion_heap_ops carveout_heap_ops = {
.unmap_kernel = ion_heap_unmap_kernel,
};
-struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
+struct ion_heap *ion_carveout_heap_create(phys_addr_t base, size_t size)
{
struct ion_carveout_heap *carveout_heap;
int ret;
struct page *page;
- size_t size;
-
- page = pfn_to_page(PFN_DOWN(heap_data->base));
- size = heap_data->size;
+ page = pfn_to_page(PFN_DOWN(base));
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret)
return ERR_PTR(ret);
@@ -127,9 +124,7 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
kfree(carveout_heap);
return ERR_PTR(-ENOMEM);
}
- carveout_heap->base = heap_data->base;
- gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size,
- -1);
+ gen_pool_add(carveout_heap->pool, base, size, -1);
carveout_heap->heap.ops = &carveout_heap_ops;
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
carveout_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c
index 159d72f5bc42..3cdde9c1a717 100644
--- a/drivers/staging/android/ion/ion_chunk_heap.c
+++ b/drivers/staging/android/ion/ion_chunk_heap.c
@@ -1,23 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_chunk_heap.c
+ * ION memory allocator chunk heap helper
*
* Copyright (C) 2012 Google, Inc.
*/
+
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/genalloc.h>
-#include <linux/io.h>
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
+
#include "ion.h"
struct ion_chunk_heap {
struct ion_heap heap;
struct gen_pool *pool;
- phys_addr_t base;
unsigned long chunk_size;
unsigned long size;
unsigned long allocated;
@@ -108,16 +107,13 @@ static struct ion_heap_ops chunk_heap_ops = {
.unmap_kernel = ion_heap_unmap_kernel,
};
-struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
+struct ion_heap *ion_chunk_heap_create(phys_addr_t base, size_t size, size_t chunk_size)
{
struct ion_chunk_heap *chunk_heap;
int ret;
struct page *page;
- size_t size;
-
- page = pfn_to_page(PFN_DOWN(heap_data->base));
- size = heap_data->size;
+ page = pfn_to_page(PFN_DOWN(base));
ret = ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));
if (ret)
return ERR_PTR(ret);
@@ -126,23 +122,21 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data)
if (!chunk_heap)
return ERR_PTR(-ENOMEM);
- chunk_heap->chunk_size = (unsigned long)heap_data->priv;
+ chunk_heap->chunk_size = chunk_size;
chunk_heap->pool = gen_pool_create(get_order(chunk_heap->chunk_size) +
PAGE_SHIFT, -1);
if (!chunk_heap->pool) {
ret = -ENOMEM;
goto error_gen_pool_create;
}
- chunk_heap->base = heap_data->base;
- chunk_heap->size = heap_data->size;
+ chunk_heap->size = size;
chunk_heap->allocated = 0;
- gen_pool_add(chunk_heap->pool, chunk_heap->base, heap_data->size, -1);
+ gen_pool_add(chunk_heap->pool, base, size, -1);
chunk_heap->heap.ops = &chunk_heap_ops;
chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK;
chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
- pr_debug("%s: base %pa size %zu\n", __func__,
- &chunk_heap->base, heap_data->size);
+ pr_debug("%s: base %pa size %zu\n", __func__, &base, size);
return &chunk_heap->heap;
@@ -150,4 +144,3 @@ error_gen_pool_create:
kfree(chunk_heap);
return ERR_PTR(ret);
}
-
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index 3fafd013d80a..bf65e67ef9d8 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_cma_heap.c
+ * ION Memory Allocator CMA heap exporter
*
* Copyright (C) Linaro 2012
* Author: <benjamin.gaignard@linaro.org> for ST-Ericsson.
@@ -111,10 +111,6 @@ static struct ion_heap *__ion_cma_heap_create(struct cma *cma)
return ERR_PTR(-ENOMEM);
cma_heap->heap.ops = &ion_cma_ops;
- /*
- * get device from private heaps data, later it will be
- * used to make the link with reserved CMA memory
- */
cma_heap->cma = cma;
cma_heap->heap.type = ION_HEAP_TYPE_DMA;
return &cma_heap->heap;
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 31db510018a9..473b465724f1 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_heap.c
+ * ION Memory Allocator generic heap helpers
*
* Copyright (C) 2011 Google, Inc.
*/
@@ -14,6 +14,7 @@
#include <uapi/linux/sched/types.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
+
#include "ion.h"
void *ion_heap_map_kernel(struct ion_heap *heap,
@@ -92,6 +93,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
if (addr >= vma->vm_end)
return 0;
}
+
return 0;
}
@@ -254,6 +256,7 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
return PTR_ERR_OR_ZERO(heap->task);
}
sched_setscheduler(heap->task, SCHED_IDLE, &param);
+
return 0;
}
@@ -265,8 +268,10 @@ static unsigned long ion_heap_shrink_count(struct shrinker *shrinker,
int total = 0;
total = ion_heap_freelist_size(heap) / PAGE_SIZE;
+
if (heap->ops->shrink)
total += heap->ops->shrink(heap, sc->gfp_mask, 0);
+
return total;
}
@@ -295,6 +300,7 @@ static unsigned long ion_heap_shrink_scan(struct shrinker *shrinker,
if (heap->ops->shrink)
freed += heap->ops->shrink(heap, sc->gfp_mask, to_scan);
+
return freed;
}
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index 0d2a95957ee8..fd4995fb676e 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_mem_pool.c
+ * ION Memory Allocator page pool helpers
*
* Copyright (C) 2011 Google, Inc.
*/
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 0383f7548d48..aa8d8425be25 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * drivers/staging/android/ion/ion_system_heap.c
+ * ION Memory Allocator system heap exporter
*
* Copyright (C) 2011 Google, Inc.
*/
@@ -13,6 +13,7 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+
#include "ion.h"
#define NUM_ORDERS ARRAY_SIZE(orders)
@@ -223,10 +224,10 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools)
static int ion_system_heap_create_pools(struct ion_page_pool **pools)
{
int i;
- gfp_t gfp_flags = low_order_gfp_flags;
for (i = 0; i < NUM_ORDERS; i++) {
struct ion_page_pool *pool;
+ gfp_t gfp_flags = low_order_gfp_flags;
if (orders[i] > 4)
gfp_flags = high_order_gfp_flags;
@@ -236,6 +237,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools)
goto err_create_pool;
pools[i] = pool;
}
+
return 0;
err_create_pool:
@@ -274,6 +276,7 @@ static int ion_system_heap_create(void)
heap->name = "ion_system_heap";
ion_device_add_heap(heap);
+
return 0;
}
device_initcall(ion_system_heap_create);
@@ -355,6 +358,7 @@ static struct ion_heap *__ion_system_contig_heap_create(void)
heap->ops = &kmalloc_ops;
heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
heap->name = "ion_system_contig_heap";
+
return heap;
}
@@ -367,7 +371,7 @@ static int ion_system_contig_heap_create(void)
return PTR_ERR(heap);
ion_device_add_heap(heap);
+
return 0;
}
device_initcall(ion_system_contig_heap_create);
-
diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h
index 5d7009884c13..46c93fcb46d6 100644
--- a/drivers/staging/android/uapi/ion.h
+++ b/drivers/staging/android/uapi/ion.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* drivers/staging/android/uapi/ion.h
*
diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c
index 22571abcaa4e..8a75bd27c413 100644
--- a/drivers/staging/android/vsoc.c
+++ b/drivers/staging/android/vsoc.c
@@ -29,7 +29,6 @@
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
-#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/file.h>
#include "uapi/vsoc_shm.h"
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 5d2fcbfe02af..0caae4a5c471 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1605,9 +1605,8 @@ static int do_insn_ioctl(struct comedi_device *dev,
unsigned int n_data = MIN_SAMPLES;
int ret = 0;
- if (copy_from_user(&insn, arg, sizeof(insn))) {
+ if (copy_from_user(&insn, arg, sizeof(insn)))
return -EFAULT;
- }
n_data = max(n_data, insn.n);
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 4e72a0778086..a9d052bfda38 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -252,9 +252,9 @@ static int cb_pcimdas_di_insn_bits(struct comedi_device *dev,
}
static int cb_pcimdas_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct cb_pcimdas_private *devpriv = dev->private;
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index e70a461e723f..405573e927cf 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -656,6 +656,7 @@ static int ni_660x_set_pfi_routing(struct comedi_device *dev,
case NI_660X_PFI_OUTPUT_DIO:
if (chan > 31)
return -EINVAL;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index b9a0dc6eac44..4bdef87d5dd7 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -49,116 +49,117 @@
/* defines for the PCI-DIO-32HS */
-#define Window_Address 4 /* W */
-#define Interrupt_And_Window_Status 4 /* R */
-#define IntStatus1 BIT(0)
-#define IntStatus2 BIT(1)
-#define WindowAddressStatus_mask 0x7c
-
-#define Master_DMA_And_Interrupt_Control 5 /* W */
-#define InterruptLine(x) ((x) & 3)
-#define OpenInt BIT(2)
-#define Group_Status 5 /* R */
-#define DataLeft BIT(0)
-#define Req BIT(2)
-#define StopTrig BIT(3)
-
-#define Group_1_Flags 6 /* R */
-#define Group_2_Flags 7 /* R */
-#define TransferReady BIT(0)
-#define CountExpired BIT(1)
-#define Waited BIT(5)
-#define PrimaryTC BIT(6)
-#define SecondaryTC BIT(7)
+#define WINDOW_ADDRESS 4 /* W */
+#define INTERRUPT_AND_WINDOW_STATUS 4 /* R */
+#define INT_STATUS_1 BIT(0)
+#define INT_STATUS_2 BIT(1)
+#define WINDOW_ADDRESS_STATUS_MASK 0x7c
+
+#define MASTER_DMA_AND_INTERRUPT_CONTROL 5 /* W */
+#define INTERRUPT_LINE(x) ((x) & 3)
+#define OPEN_INT BIT(2)
+#define GROUP_STATUS 5 /* R */
+#define DATA_LEFT BIT(0)
+#define REQ BIT(2)
+#define STOP_TRIG BIT(3)
+
+#define GROUP_1_FLAGS 6 /* R */
+#define GROUP_2_FLAGS 7 /* R */
+#define TRANSFER_READY BIT(0)
+#define COUNT_EXPIRED BIT(1)
+#define WAITED BIT(5)
+#define PRIMARY_TC BIT(6)
+#define SECONDARY_TC BIT(7)
/* #define SerialRose */
/* #define ReqRose */
/* #define Paused */
-#define Group_1_First_Clear 6 /* W */
-#define Group_2_First_Clear 7 /* W */
-#define ClearWaited BIT(3)
-#define ClearPrimaryTC BIT(4)
-#define ClearSecondaryTC BIT(5)
-#define DMAReset BIT(6)
-#define FIFOReset BIT(7)
-#define ClearAll 0xf8
-
-#define Group_1_FIFO 8 /* W */
-#define Group_2_FIFO 12 /* W */
-
-#define Transfer_Count 20
-#define Chip_ID_D 24
-#define Chip_ID_I 25
-#define Chip_ID_O 26
-#define Chip_Version 27
-#define Port_IO(x) (28 + (x))
-#define Port_Pin_Directions(x) (32 + (x))
-#define Port_Pin_Mask(x) (36 + (x))
-#define Port_Pin_Polarities(x) (40 + (x))
-
-#define Master_Clock_Routing 45
-#define RTSIClocking(x) (((x) & 3) << 4)
-
-#define Group_1_Second_Clear 46 /* W */
-#define Group_2_Second_Clear 47 /* W */
-#define ClearExpired BIT(0)
-
-#define Port_Pattern(x) (48 + (x))
-
-#define Data_Path 64
-#define FIFOEnableA BIT(0)
-#define FIFOEnableB BIT(1)
-#define FIFOEnableC BIT(2)
-#define FIFOEnableD BIT(3)
-#define Funneling(x) (((x) & 3) << 4)
-#define GroupDirection BIT(7)
-
-#define Protocol_Register_1 65
-#define OpMode Protocol_Register_1
-#define RunMode(x) ((x) & 7)
-#define Numbered BIT(3)
-
-#define Protocol_Register_2 66
-#define ClockReg Protocol_Register_2
-#define ClockLine(x) (((x) & 3) << 5)
-#define InvertStopTrig BIT(7)
-#define DataLatching(x) (((x) & 3) << 5)
-
-#define Protocol_Register_3 67
-#define Sequence Protocol_Register_3
-
-#define Protocol_Register_14 68 /* 16 bit */
-#define ClockSpeed Protocol_Register_14
-
-#define Protocol_Register_4 70
-#define ReqReg Protocol_Register_4
-#define ReqConditioning(x) (((x) & 7) << 3)
-
-#define Protocol_Register_5 71
-#define BlockMode Protocol_Register_5
+#define GROUP_1_FIRST_CLEAR 6 /* W */
+#define GROUP_2_FIRST_CLEAR 7 /* W */
+#define CLEAR_WAITED BIT(3)
+#define CLEAR_PRIMARY_TC BIT(4)
+#define CLEAR_SECONDARY_TC BIT(5)
+#define DMA_RESET BIT(6)
+#define FIFO_RESET BIT(7)
+#define CLEAR_ALL 0xf8
+
+#define GROUP_1_FIFO 8 /* W */
+#define GROUP_2_FIFO 12 /* W */
+
+#define TRANSFER_COUNT 20
+#define CHIP_ID_D 24
+#define CHIP_ID_I 25
+#define CHIP_ID_O 26
+#define CHIP_VERSION 27
+#define PORT_IO(x) (28 + (x))
+#define PORT_PIN_DIRECTIONS(x) (32 + (x))
+#define PORT_PIN_MASK(x) (36 + (x))
+#define PORT_PIN_POLARITIES(x) (40 + (x))
+
+#define MASTER_CLOCK_ROUTING 45
+#define RTSI_CLOCKING(x) (((x) & 3) << 4)
+
+#define GROUP_1_SECOND_CLEAR 46 /* W */
+#define GROUP_2_SECOND_CLEAR 47 /* W */
+#define CLEAR_EXPIRED BIT(0)
+
+#define PORT_PATTERN(x) (48 + (x))
+
+#define DATA_PATH 64
+#define FIFO_ENABLE_A BIT(0)
+#define FIFO_ENABLE_B BIT(1)
+#define FIFO_ENABLE_C BIT(2)
+#define FIFO_ENABLE_D BIT(3)
+#define FUNNELING(x) (((x) & 3) << 4)
+#define GROUP_DIRECTION BIT(7)
+
+#define PROTOCOL_REGISTER_1 65
+#define OP_MODE PROTOCOL_REGISTER_1
+#define RUN_MODE(x) ((x) & 7)
+#define NUMBERED BIT(3)
+
+#define PROTOCOL_REGISTER_2 66
+#define CLOCK_REG PROTOCOL_REGISTER_2
+#define CLOCK_LINE(x) (((x) & 3) << 5)
+#define INVERT_STOP_TRIG BIT(7)
+#define DATA_LATCHING(x) (((x) & 3) << 5)
+
+#define PROTOCOL_REGISTER_3 67
+#define SEQUENCE PROTOCOL_REGISTER_3
+
+#define PROTOCOL_REGISTER_14 68 /* 16 bit */
+#define CLOCK_SPEED PROTOCOL_REGISTER_14
+
+#define PROTOCOL_REGISTER_4 70
+#define REQ_REG PROTOCOL_REGISTER_4
+#define REQ_CONDITIONING(x) (((x) & 7) << 3)
+
+#define PROTOCOL_REGISTER_5 71
+#define BLOCK_MODE PROTOCOL_REGISTER_5
#define FIFO_Control 72
-#define ReadyLevel(x) ((x) & 7)
-
-#define Protocol_Register_6 73
-#define LinePolarities Protocol_Register_6
-#define InvertAck BIT(0)
-#define InvertReq BIT(1)
-#define InvertClock BIT(2)
-#define InvertSerial BIT(3)
-#define OpenAck BIT(4)
-#define OpenClock BIT(5)
-
-#define Protocol_Register_7 74
-#define AckSer Protocol_Register_7
-#define AckLine(x) (((x) & 3) << 2)
-#define ExchangePins BIT(7)
-
-#define Interrupt_Control 75
- /* bits same as flags */
-
-#define DMA_Line_Control_Group1 76
-#define DMA_Line_Control_Group2 108
+#define READY_LEVEL(x) ((x) & 7)
+
+#define PROTOCOL_REGISTER_6 73
+#define LINE_POLARITIES PROTOCOL_REGISTER_6
+#define INVERT_ACK BIT(0)
+#define INVERT_REQ BIT(1)
+#define INVERT_CLOCK BIT(2)
+#define INVERT_SERIAL BIT(3)
+#define OPEN_ACK BIT(4)
+#define OPEN_CLOCK BIT(5)
+
+#define PROTOCOL_REGISTER_7 74
+#define ACK_SER PROTOCOL_REGISTER_7
+#define ACK_LINE(x) (((x) & 3) << 2)
+#define EXCHANGE_PINS BIT(7)
+
+#define INTERRUPT_CONTROL 75
+/* bits same as flags */
+
+#define DMA_LINE_CONTROL_GROUP1 76
+#define DMA_LINE_CONTROL_GROUP2 108
+
/* channel zero is none */
static inline unsigned int primary_DMAChannel_bits(unsigned int channel)
{
@@ -170,41 +171,41 @@ static inline unsigned int secondary_DMAChannel_bits(unsigned int channel)
return (channel << 2) & 0xc;
}
-#define Transfer_Size_Control 77
-#define TransferWidth(x) ((x) & 3)
-#define TransferLength(x) (((x) & 3) << 3)
-#define RequireRLevel BIT(5)
+#define TRANSFER_SIZE_CONTROL 77
+#define TRANSFER_WIDTH(x) ((x) & 3)
+#define TRANSFER_LENGTH(x) (((x) & 3) << 3)
+#define REQUIRE_R_LEVEL BIT(5)
-#define Protocol_Register_15 79
-#define DAQOptions Protocol_Register_15
-#define StartSource(x) ((x) & 0x3)
-#define InvertStart BIT(2)
-#define StopSource(x) (((x) & 0x3) << 3)
-#define ReqStart BIT(6)
-#define PreStart BIT(7)
+#define PROTOCOL_REGISTER_15 79
+#define DAQ_OPTIONS PROTOCOL_REGISTER_15
+#define START_SOURCE(x) ((x) & 0x3)
+#define INVERT_START BIT(2)
+#define STOP_SOURCE(x) (((x) & 0x3) << 3)
+#define REQ_START BIT(6)
+#define PRE_START BIT(7)
-#define Pattern_Detection 81
-#define DetectionMethod BIT(0)
-#define InvertMatch BIT(1)
-#define IE_Pattern_Detection BIT(2)
+#define PATTERN_DETECTION 81
+#define DETECTION_METHOD BIT(0)
+#define INVERT_MATCH BIT(1)
+#define IE_PATTERN_DETECTION BIT(2)
-#define Protocol_Register_9 82
-#define ReqDelay Protocol_Register_9
+#define PROTOCOL_REGISTER_9 82
+#define REQ_DELAY PROTOCOL_REGISTER_9
-#define Protocol_Register_10 83
-#define ReqNotDelay Protocol_Register_10
+#define PROTOCOL_REGISTER_10 83
+#define REQ_NOT_DELAY PROTOCOL_REGISTER_10
-#define Protocol_Register_11 84
-#define AckDelay Protocol_Register_11
+#define PROTOCOL_REGISTER_11 84
+#define ACK_DELAY PROTOCOL_REGISTER_11
-#define Protocol_Register_12 85
-#define AckNotDelay Protocol_Register_12
+#define PROTOCOL_REGISTER_12 85
+#define ACK_NOT_DELAY PROTOCOL_REGISTER_12
-#define Protocol_Register_13 86
-#define Data1Delay Protocol_Register_13
+#define PROTOCOL_REGISTER_13 86
+#define DATA_1_DELAY PROTOCOL_REGISTER_13
-#define Protocol_Register_8 88 /* 32 bit */
-#define StartDelay Protocol_Register_8
+#define PROTOCOL_REGISTER_8 88 /* 32 bit */
+#define START_DELAY PROTOCOL_REGISTER_8
/* Firmware files for PCI-6524 */
#define FW_PCI_6534_MAIN "ni6534a.bin"
@@ -246,9 +247,10 @@ enum FPGA_Control_Bits {
#define TIMER_BASE 50 /* nanoseconds */
#ifdef USE_DMA
-#define IntEn (CountExpired | Waited | PrimaryTC | SecondaryTC)
+#define INT_EN (COUNT_EXPIRED | WAITED | PRIMARY_TC | SECONDARY_TC)
#else
-#define IntEn (TransferReady | CountExpired | Waited | PrimaryTC | SecondaryTC)
+#define INT_EN (TRANSFER_READY | COUNT_EXPIRED | WAITED \
+ | PRIMARY_TC | SECONDARY_TC)
#endif
enum nidio_boardid {
@@ -283,7 +285,7 @@ struct nidio96_private {
struct mite *mite;
int boardtype;
int dio;
- unsigned short OpModeBits;
+ unsigned short OP_MODEBits;
struct mite_channel *di_mite_chan;
struct mite_ring *di_mite_ring;
spinlock_t mite_channel_lock;
@@ -307,7 +309,7 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev)
devpriv->di_mite_chan->dir = COMEDI_INPUT;
writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) |
secondary_DMAChannel_bits(devpriv->di_mite_chan->channel),
- dev->mmio + DMA_Line_Control_Group1);
+ dev->mmio + DMA_LINE_CONTROL_GROUP1);
mmiowb();
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
return 0;
@@ -324,7 +326,7 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev)
devpriv->di_mite_chan = NULL;
writeb(primary_DMAChannel_bits(0) |
secondary_DMAChannel_bits(0),
- dev->mmio + DMA_Line_Control_Group1);
+ dev->mmio + DMA_LINE_CONTROL_GROUP1);
mmiowb();
}
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
@@ -391,8 +393,8 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
/* Lock to avoid race with comedi_poll */
spin_lock(&dev->spinlock);
- status = readb(dev->mmio + Interrupt_And_Window_Status);
- flags = readb(dev->mmio + Group_1_Flags);
+ status = readb(dev->mmio + INTERRUPT_AND_WINDOW_STATUS);
+ flags = readb(dev->mmio + GROUP_1_FLAGS);
spin_lock(&devpriv->mite_channel_lock);
if (devpriv->di_mite_chan) {
@@ -401,63 +403,63 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
}
spin_unlock(&devpriv->mite_channel_lock);
- while (status & DataLeft) {
+ while (status & DATA_LEFT) {
work++;
if (work > 20) {
dev_dbg(dev->class_dev, "too much work in interrupt\n");
writeb(0x00,
- dev->mmio + Master_DMA_And_Interrupt_Control);
+ dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL);
break;
}
- flags &= IntEn;
+ flags &= INT_EN;
- if (flags & TransferReady) {
- while (flags & TransferReady) {
+ if (flags & TRANSFER_READY) {
+ while (flags & TRANSFER_READY) {
work++;
if (work > 100) {
dev_dbg(dev->class_dev,
"too much work in interrupt\n");
writeb(0x00, dev->mmio +
- Master_DMA_And_Interrupt_Control
+ MASTER_DMA_AND_INTERRUPT_CONTROL
);
goto out;
}
- auxdata = readl(dev->mmio + Group_1_FIFO);
+ auxdata = readl(dev->mmio + GROUP_1_FIFO);
comedi_buf_write_samples(s, &auxdata, 1);
- flags = readb(dev->mmio + Group_1_Flags);
+ flags = readb(dev->mmio + GROUP_1_FLAGS);
}
}
- if (flags & CountExpired) {
- writeb(ClearExpired, dev->mmio + Group_1_Second_Clear);
+ if (flags & COUNT_EXPIRED) {
+ writeb(CLEAR_EXPIRED, dev->mmio + GROUP_1_SECOND_CLEAR);
async->events |= COMEDI_CB_EOA;
- writeb(0x00, dev->mmio + OpMode);
+ writeb(0x00, dev->mmio + OP_MODE);
break;
- } else if (flags & Waited) {
- writeb(ClearWaited, dev->mmio + Group_1_First_Clear);
+ } else if (flags & WAITED) {
+ writeb(CLEAR_WAITED, dev->mmio + GROUP_1_FIRST_CLEAR);
async->events |= COMEDI_CB_ERROR;
break;
- } else if (flags & PrimaryTC) {
- writeb(ClearPrimaryTC,
- dev->mmio + Group_1_First_Clear);
+ } else if (flags & PRIMARY_TC) {
+ writeb(CLEAR_PRIMARY_TC,
+ dev->mmio + GROUP_1_FIRST_CLEAR);
async->events |= COMEDI_CB_EOA;
- } else if (flags & SecondaryTC) {
- writeb(ClearSecondaryTC,
- dev->mmio + Group_1_First_Clear);
+ } else if (flags & SECONDARY_TC) {
+ writeb(CLEAR_SECONDARY_TC,
+ dev->mmio + GROUP_1_FIRST_CLEAR);
async->events |= COMEDI_CB_EOA;
}
- flags = readb(dev->mmio + Group_1_Flags);
- status = readb(dev->mmio + Interrupt_And_Window_Status);
+ flags = readb(dev->mmio + GROUP_1_FLAGS);
+ status = readb(dev->mmio + INTERRUPT_AND_WINDOW_STATUS);
}
out:
comedi_handle_events(dev, s);
#if 0
if (!tag)
- writeb(0x03, dev->mmio + Master_DMA_And_Interrupt_Control);
+ writeb(0x03, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL);
#endif
spin_unlock(&dev->spinlock);
@@ -484,7 +486,7 @@ static int ni_pcidio_insn_config(struct comedi_device *dev,
if (ret)
return ret;
- writel(s->io_bits, dev->mmio + Port_Pin_Directions(0));
+ writel(s->io_bits, dev->mmio + PORT_PIN_DIRECTIONS(0));
return insn->n;
}
@@ -495,9 +497,9 @@ static int ni_pcidio_insn_bits(struct comedi_device *dev,
unsigned int *data)
{
if (comedi_dio_update_state(s, data))
- writel(s->state, dev->mmio + Port_IO(0));
+ writel(s->state, dev->mmio + PORT_IO(0));
- data[1] = readl(dev->mmio + Port_IO(0));
+ data[1] = readl(dev->mmio + PORT_IO(0));
return insn->n;
}
@@ -609,7 +611,7 @@ static int ni_pcidio_inttrig(struct comedi_device *dev,
if (trig_num != cmd->start_arg)
return -EINVAL;
- writeb(devpriv->OpModeBits, dev->mmio + OpMode);
+ writeb(devpriv->OP_MODEBits, dev->mmio + OP_MODE);
s->async->inttrig = NULL;
return 1;
@@ -621,78 +623,78 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
struct comedi_cmd *cmd = &s->async->cmd;
/* XXX configure ports for input */
- writel(0x0000, dev->mmio + Port_Pin_Directions(0));
+ writel(0x0000, dev->mmio + PORT_PIN_DIRECTIONS(0));
if (1) {
/* enable fifos A B C D */
- writeb(0x0f, dev->mmio + Data_Path);
+ writeb(0x0f, dev->mmio + DATA_PATH);
/* set transfer width a 32 bits */
- writeb(TransferWidth(0) | TransferLength(0),
- dev->mmio + Transfer_Size_Control);
+ writeb(TRANSFER_WIDTH(0) | TRANSFER_LENGTH(0),
+ dev->mmio + TRANSFER_SIZE_CONTROL);
} else {
- writeb(0x03, dev->mmio + Data_Path);
- writeb(TransferWidth(3) | TransferLength(0),
- dev->mmio + Transfer_Size_Control);
+ writeb(0x03, dev->mmio + DATA_PATH);
+ writeb(TRANSFER_WIDTH(3) | TRANSFER_LENGTH(0),
+ dev->mmio + TRANSFER_SIZE_CONTROL);
}
/* protocol configuration */
if (cmd->scan_begin_src == TRIG_TIMER) {
/* page 4-5, "input with internal REQs" */
- writeb(0, dev->mmio + OpMode);
- writeb(0x00, dev->mmio + ClockReg);
- writeb(1, dev->mmio + Sequence);
- writeb(0x04, dev->mmio + ReqReg);
- writeb(4, dev->mmio + BlockMode);
- writeb(3, dev->mmio + LinePolarities);
- writeb(0xc0, dev->mmio + AckSer);
+ writeb(0, dev->mmio + OP_MODE);
+ writeb(0x00, dev->mmio + CLOCK_REG);
+ writeb(1, dev->mmio + SEQUENCE);
+ writeb(0x04, dev->mmio + REQ_REG);
+ writeb(4, dev->mmio + BLOCK_MODE);
+ writeb(3, dev->mmio + LINE_POLARITIES);
+ writeb(0xc0, dev->mmio + ACK_SER);
writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg,
CMDF_ROUND_NEAREST),
- dev->mmio + StartDelay);
- writeb(1, dev->mmio + ReqDelay);
- writeb(1, dev->mmio + ReqNotDelay);
- writeb(1, dev->mmio + AckDelay);
- writeb(0x0b, dev->mmio + AckNotDelay);
- writeb(0x01, dev->mmio + Data1Delay);
+ dev->mmio + START_DELAY);
+ writeb(1, dev->mmio + REQ_DELAY);
+ writeb(1, dev->mmio + REQ_NOT_DELAY);
+ writeb(1, dev->mmio + ACK_DELAY);
+ writeb(0x0b, dev->mmio + ACK_NOT_DELAY);
+ writeb(0x01, dev->mmio + DATA_1_DELAY);
/*
* manual, page 4-5:
- * ClockSpeed comment is incorrectly listed on DAQOptions
+ * CLOCK_SPEED comment is incorrectly listed on DAQ_OPTIONS
*/
- writew(0, dev->mmio + ClockSpeed);
- writeb(0, dev->mmio + DAQOptions);
+ writew(0, dev->mmio + CLOCK_SPEED);
+ writeb(0, dev->mmio + DAQ_OPTIONS);
} else {
/* TRIG_EXT */
/* page 4-5, "input with external REQs" */
- writeb(0, dev->mmio + OpMode);
- writeb(0x00, dev->mmio + ClockReg);
- writeb(0, dev->mmio + Sequence);
- writeb(0x00, dev->mmio + ReqReg);
- writeb(4, dev->mmio + BlockMode);
+ writeb(0, dev->mmio + OP_MODE);
+ writeb(0x00, dev->mmio + CLOCK_REG);
+ writeb(0, dev->mmio + SEQUENCE);
+ writeb(0x00, dev->mmio + REQ_REG);
+ writeb(4, dev->mmio + BLOCK_MODE);
if (!(cmd->scan_begin_arg & CR_INVERT)) /* Leading Edge */
- writeb(0, dev->mmio + LinePolarities);
+ writeb(0, dev->mmio + LINE_POLARITIES);
else /* Trailing Edge */
- writeb(2, dev->mmio + LinePolarities);
- writeb(0x00, dev->mmio + AckSer);
- writel(1, dev->mmio + StartDelay);
- writeb(1, dev->mmio + ReqDelay);
- writeb(1, dev->mmio + ReqNotDelay);
- writeb(1, dev->mmio + AckDelay);
- writeb(0x0C, dev->mmio + AckNotDelay);
- writeb(0x10, dev->mmio + Data1Delay);
- writew(0, dev->mmio + ClockSpeed);
- writeb(0x60, dev->mmio + DAQOptions);
+ writeb(2, dev->mmio + LINE_POLARITIES);
+ writeb(0x00, dev->mmio + ACK_SER);
+ writel(1, dev->mmio + START_DELAY);
+ writeb(1, dev->mmio + REQ_DELAY);
+ writeb(1, dev->mmio + REQ_NOT_DELAY);
+ writeb(1, dev->mmio + ACK_DELAY);
+ writeb(0x0C, dev->mmio + ACK_NOT_DELAY);
+ writeb(0x10, dev->mmio + DATA_1_DELAY);
+ writew(0, dev->mmio + CLOCK_SPEED);
+ writeb(0x60, dev->mmio + DAQ_OPTIONS);
}
if (cmd->stop_src == TRIG_COUNT) {
writel(cmd->stop_arg,
- dev->mmio + Transfer_Count);
+ dev->mmio + TRANSFER_COUNT);
} else {
/* XXX */
}
#ifdef USE_DMA
- writeb(ClearPrimaryTC | ClearSecondaryTC,
- dev->mmio + Group_1_First_Clear);
+ writeb(CLEAR_PRIMARY_TC | CLEAR_SECONDARY_TC,
+ dev->mmio + GROUP_1_FIRST_CLEAR);
{
int retval = setup_mite_dma(dev, s);
@@ -701,25 +703,25 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return retval;
}
#else
- writeb(0x00, dev->mmio + DMA_Line_Control_Group1);
+ writeb(0x00, dev->mmio + DMA_LINE_CONTROL_GROUP1);
#endif
- writeb(0x00, dev->mmio + DMA_Line_Control_Group2);
+ writeb(0x00, dev->mmio + DMA_LINE_CONTROL_GROUP2);
/* clear and enable interrupts */
- writeb(0xff, dev->mmio + Group_1_First_Clear);
- /* writeb(ClearExpired, dev->mmio+Group_1_Second_Clear); */
+ writeb(0xff, dev->mmio + GROUP_1_FIRST_CLEAR);
+ /* writeb(CLEAR_EXPIRED, dev->mmio+GROUP_1_SECOND_CLEAR); */
- writeb(IntEn, dev->mmio + Interrupt_Control);
- writeb(0x03, dev->mmio + Master_DMA_And_Interrupt_Control);
+ writeb(INT_EN, dev->mmio + INTERRUPT_CONTROL);
+ writeb(0x03, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL);
if (cmd->stop_src == TRIG_NONE) {
- devpriv->OpModeBits = DataLatching(0) | RunMode(7);
+ devpriv->OP_MODEBits = DATA_LATCHING(0) | RUN_MODE(7);
} else { /* TRIG_TIMER */
- devpriv->OpModeBits = Numbered | RunMode(7);
+ devpriv->OP_MODEBits = NUMBERED | RUN_MODE(7);
}
if (cmd->start_src == TRIG_NOW) {
/* start */
- writeb(devpriv->OpModeBits, dev->mmio + OpMode);
+ writeb(devpriv->OP_MODEBits, dev->mmio + OP_MODE);
s->async->inttrig = NULL;
} else {
/* TRIG_INT */
@@ -732,7 +734,7 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int ni_pcidio_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- writeb(0x00, dev->mmio + Master_DMA_And_Interrupt_Control);
+ writeb(0x00, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL);
ni_pcidio_release_di_mite_channel(dev);
return 0;
@@ -869,12 +871,12 @@ static int pci_6534_upload_firmware(struct comedi_device *dev)
static void nidio_reset_board(struct comedi_device *dev)
{
- writel(0, dev->mmio + Port_IO(0));
- writel(0, dev->mmio + Port_Pin_Directions(0));
- writel(0, dev->mmio + Port_Pin_Mask(0));
+ writel(0, dev->mmio + PORT_IO(0));
+ writel(0, dev->mmio + PORT_PIN_DIRECTIONS(0));
+ writel(0, dev->mmio + PORT_PIN_MASK(0));
/* disable interrupts on board */
- writeb(0, dev->mmio + Master_DMA_And_Interrupt_Control);
+ writeb(0, dev->mmio + MASTER_DMA_AND_INTERRUPT_CONTROL);
}
static int nidio_auto_attach(struct comedi_device *dev,
@@ -925,7 +927,7 @@ static int nidio_auto_attach(struct comedi_device *dev,
return ret;
dev_info(dev->class_dev, "%s rev=%d\n", dev->board_name,
- readb(dev->mmio + Chip_Version));
+ readb(dev->mmio + CHIP_VERSION));
s = &dev->subdevices[0];
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index 0eb388c0e1f0..048cb35723ad 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -224,13 +224,16 @@ static void ni_tio_set_bits_transient(struct ni_gpct *counter,
unsigned int transient)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned int chip = counter->chip_index;
unsigned long flags;
- if (reg < NITIO_NUM_REGS) {
+ if (reg < NITIO_NUM_REGS && chip < counter_dev->num_chips) {
+ unsigned int *regs = counter_dev->regs[chip];
+
spin_lock_irqsave(&counter_dev->regs_lock, flags);
- counter_dev->regs[reg] &= ~mask;
- counter_dev->regs[reg] |= (value & mask);
- ni_tio_write(counter, counter_dev->regs[reg] | transient, reg);
+ regs[reg] &= ~mask;
+ regs[reg] |= (value & mask);
+ ni_tio_write(counter, regs[reg] | transient, reg);
mmiowb();
spin_unlock_irqrestore(&counter_dev->regs_lock, flags);
}
@@ -267,12 +270,13 @@ unsigned int ni_tio_get_soft_copy(const struct ni_gpct *counter,
enum ni_gpct_register reg)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
+ unsigned int chip = counter->chip_index;
unsigned int value = 0;
unsigned long flags;
- if (reg < NITIO_NUM_REGS) {
+ if (reg < NITIO_NUM_REGS && chip < counter_dev->num_chips) {
spin_lock_irqsave(&counter_dev->regs_lock, flags);
- value = counter_dev->regs[reg];
+ value = counter_dev->regs[chip][reg];
spin_unlock_irqrestore(&counter_dev->regs_lock, flags);
}
return value;
@@ -302,6 +306,7 @@ static int ni_m_series_clock_src_select(const struct ni_gpct *counter,
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
unsigned int second_gate_reg = NITIO_GATE2_REG(cidx);
unsigned int clock_source = 0;
unsigned int src;
@@ -318,7 +323,7 @@ static int ni_m_series_clock_src_select(const struct ni_gpct *counter,
clock_source = NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS;
break;
case NI_M_TIMEBASE_3_CLK:
- if (counter_dev->regs[second_gate_reg] & GI_SRC_SUBSEL)
+ if (counter_dev->regs[chip][second_gate_reg] & GI_SRC_SUBSEL)
clock_source =
NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS;
else
@@ -328,7 +333,7 @@ static int ni_m_series_clock_src_select(const struct ni_gpct *counter,
clock_source = NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS;
break;
case NI_M_NEXT_GATE_CLK:
- if (counter_dev->regs[second_gate_reg] & GI_SRC_SUBSEL)
+ if (counter_dev->regs[chip][second_gate_reg] & GI_SRC_SUBSEL)
clock_source = NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS;
else
clock_source = NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS;
@@ -721,6 +726,7 @@ static void ni_tio_set_source_subselect(struct ni_gpct *counter,
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
unsigned int second_gate_reg = NITIO_GATE2_REG(cidx);
if (counter_dev->variant != ni_gpct_variant_m_series)
@@ -729,18 +735,18 @@ static void ni_tio_set_source_subselect(struct ni_gpct *counter,
/* Gi_Source_Subselect is zero */
case NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS:
case NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS:
- counter_dev->regs[second_gate_reg] &= ~GI_SRC_SUBSEL;
+ counter_dev->regs[chip][second_gate_reg] &= ~GI_SRC_SUBSEL;
break;
/* Gi_Source_Subselect is one */
case NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS:
case NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS:
- counter_dev->regs[second_gate_reg] |= GI_SRC_SUBSEL;
+ counter_dev->regs[chip][second_gate_reg] |= GI_SRC_SUBSEL;
break;
/* Gi_Source_Subselect doesn't matter */
default:
return;
}
- ni_tio_write(counter, counter_dev->regs[second_gate_reg],
+ ni_tio_write(counter, counter_dev->regs[chip][second_gate_reg],
second_gate_reg);
}
@@ -1116,6 +1122,7 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned int index,
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
unsigned int abz_reg, shift, mask;
if (counter_dev->variant != ni_gpct_variant_m_series)
@@ -1141,9 +1148,9 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned int index,
if (source > 0x1f)
source = 0x1f; /* Disable gate */
- counter_dev->regs[abz_reg] &= ~mask;
- counter_dev->regs[abz_reg] |= (source << shift) & mask;
- ni_tio_write(counter, counter_dev->regs[abz_reg], abz_reg);
+ counter_dev->regs[chip][abz_reg] &= ~mask;
+ counter_dev->regs[chip][abz_reg] |= (source << shift) & mask;
+ ni_tio_write(counter, counter_dev->regs[chip][abz_reg], abz_reg);
return 0;
}
@@ -1632,6 +1639,7 @@ int ni_tio_insn_read(struct comedi_device *dev,
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int channel = CR_CHAN(insn->chanspec);
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
int i;
for (i = 0; i < insn->n; i++) {
@@ -1640,10 +1648,12 @@ int ni_tio_insn_read(struct comedi_device *dev,
data[i] = ni_tio_read_sw_save_reg(dev, s);
break;
case 1:
- data[i] = counter_dev->regs[NITIO_LOADA_REG(cidx)];
+ data[i] =
+ counter_dev->regs[chip][NITIO_LOADA_REG(cidx)];
break;
case 2:
- data[i] = counter_dev->regs[NITIO_LOADB_REG(cidx)];
+ data[i] =
+ counter_dev->regs[chip][NITIO_LOADB_REG(cidx)];
break;
}
}
@@ -1670,6 +1680,7 @@ int ni_tio_insn_write(struct comedi_device *dev,
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int channel = CR_CHAN(insn->chanspec);
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
unsigned int load_reg;
if (insn->n < 1)
@@ -1690,14 +1701,15 @@ int ni_tio_insn_write(struct comedi_device *dev,
ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx),
0, 0, GI_LOAD);
/* restore load reg */
- ni_tio_write(counter, counter_dev->regs[load_reg], load_reg);
+ ni_tio_write(counter, counter_dev->regs[chip][load_reg],
+ load_reg);
break;
case 1:
- counter_dev->regs[NITIO_LOADA_REG(cidx)] = data[0];
+ counter_dev->regs[chip][NITIO_LOADA_REG(cidx)] = data[0];
ni_tio_write(counter, data[0], NITIO_LOADA_REG(cidx));
break;
case 2:
- counter_dev->regs[NITIO_LOADB_REG(cidx)] = data[0];
+ counter_dev->regs[chip][NITIO_LOADB_REG(cidx)] = data[0];
ni_tio_write(counter, data[0], NITIO_LOADB_REG(cidx));
break;
default:
@@ -1711,11 +1723,12 @@ void ni_tio_init_counter(struct ni_gpct *counter)
{
struct ni_gpct_device *counter_dev = counter->counter_dev;
unsigned int cidx = counter->counter_index;
+ unsigned int chip = counter->chip_index;
ni_tio_reset_count_and_disarm(counter);
/* initialize counter registers */
- counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0;
+ counter_dev->regs[chip][NITIO_AUTO_INC_REG(cidx)] = 0x0;
ni_tio_write(counter, 0x0, NITIO_AUTO_INC_REG(cidx));
ni_tio_set_bits(counter, NITIO_CMD_REG(cidx),
@@ -1723,10 +1736,10 @@ void ni_tio_init_counter(struct ni_gpct *counter)
ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0);
- counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0;
+ counter_dev->regs[chip][NITIO_LOADA_REG(cidx)] = 0x0;
ni_tio_write(counter, 0x0, NITIO_LOADA_REG(cidx));
- counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0;
+ counter_dev->regs[chip][NITIO_LOADB_REG(cidx)] = 0x0;
ni_tio_write(counter, 0x0, NITIO_LOADB_REG(cidx));
ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0);
@@ -1735,7 +1748,7 @@ void ni_tio_init_counter(struct ni_gpct *counter)
ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0);
if (ni_tio_has_gate2_registers(counter_dev)) {
- counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0;
+ counter_dev->regs[chip][NITIO_GATE2_REG(cidx)] = 0x0;
ni_tio_write(counter, 0x0, NITIO_GATE2_REG(cidx));
}
@@ -1776,9 +1789,16 @@ ni_gpct_device_construct(struct comedi_device *dev,
spin_lock_init(&counter_dev->regs_lock);
+ counter_dev->num_counters = num_counters;
+ counter_dev->num_chips = DIV_ROUND_UP(num_counters, counters_per_chip);
+
counter_dev->counters = kcalloc(num_counters, sizeof(*counter),
GFP_KERNEL);
- if (!counter_dev->counters) {
+ counter_dev->regs = kcalloc(counter_dev->num_chips,
+ sizeof(*counter_dev->regs), GFP_KERNEL);
+ if (!counter_dev->regs || !counter_dev->counters) {
+ kfree(counter_dev->regs);
+ kfree(counter_dev->counters);
kfree(counter_dev);
return NULL;
}
@@ -1790,8 +1810,6 @@ ni_gpct_device_construct(struct comedi_device *dev,
counter->counter_index = i % counters_per_chip;
spin_lock_init(&counter->lock);
}
- counter_dev->num_counters = num_counters;
- counter_dev->counters_per_chip = counters_per_chip;
return counter_dev;
}
@@ -1801,6 +1819,7 @@ void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev)
{
if (!counter_dev)
return;
+ kfree(counter_dev->regs);
kfree(counter_dev->counters);
kfree(counter_dev);
}
diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h
index 1e85d0a53715..e7b05718df9b 100644
--- a/drivers/staging/comedi/drivers/ni_tio.h
+++ b/drivers/staging/comedi/drivers/ni_tio.h
@@ -107,8 +107,8 @@ struct ni_gpct_device {
enum ni_gpct_variant variant;
struct ni_gpct *counters;
unsigned int num_counters;
- unsigned int counters_per_chip;
- unsigned int regs[NITIO_NUM_REGS];
+ unsigned int num_chips;
+ unsigned int (*regs)[NITIO_NUM_REGS]; /* [num_chips][NITIO_NUM_REGS] */
spinlock_t regs_lock; /* protects 'regs' */
const struct ni_route_tables *routing_tables; /* link to routes */
};
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index e18c0723b760..0d54f394dbd2 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -61,7 +61,7 @@
#define USBDUXFASTSUB_CPUCS 0xE600
/*
- * max lenghth of the transfer-buffer for software upload
+ * max length of the transfer-buffer for software upload
*/
#define TB_LEN 0x2000
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index 8e8f57c4f029..a913d40f0801 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -27,7 +27,7 @@
#include <linux/usb/gadget.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include "emxx_udc.h"
@@ -2220,7 +2220,7 @@ static inline void _nbu2ss_check_vbus(struct nbu2ss_udc *udc)
mdelay(VBUS_CHATTERING_MDELAY); /* wait (ms) */
/* VBUS ON Check*/
- reg_dt = gpio_get_value(VBUS_VALUE);
+ reg_dt = gpiod_get_value(vbus_gpio);
if (reg_dt == 0) {
udc->linux_suspended = 0;
@@ -2247,7 +2247,7 @@ static inline void _nbu2ss_check_vbus(struct nbu2ss_udc *udc)
}
} else {
mdelay(5); /* wait (5ms) */
- reg_dt = gpio_get_value(VBUS_VALUE);
+ reg_dt = gpiod_get_value(vbus_gpio);
if (reg_dt == 0)
return;
@@ -2311,7 +2311,7 @@ static inline void _nbu2ss_int_usb_suspend(struct nbu2ss_udc *udc)
u32 reg_dt;
if (udc->usb_suspended == 0) {
- reg_dt = gpio_get_value(VBUS_VALUE);
+ reg_dt = gpiod_get_value(vbus_gpio);
if (reg_dt == 0)
return;
@@ -2351,7 +2351,7 @@ static irqreturn_t _nbu2ss_udc_irq(int irq, void *_udc)
struct nbu2ss_udc *udc = (struct nbu2ss_udc *)_udc;
struct fc_regs __iomem *preg = udc->p_regs;
- if (gpio_get_value(VBUS_VALUE) == 0) {
+ if (gpiod_get_value(vbus_gpio) == 0) {
_nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW);
_nbu2ss_writel(&preg->USB_INT_ENA, 0);
return IRQ_HANDLED;
@@ -2360,7 +2360,7 @@ static irqreturn_t _nbu2ss_udc_irq(int irq, void *_udc)
spin_lock(&udc->lock);
for (;;) {
- if (gpio_get_value(VBUS_VALUE) == 0) {
+ if (gpiod_get_value(vbus_gpio) == 0) {
_nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW);
_nbu2ss_writel(&preg->USB_INT_ENA, 0);
status = 0;
@@ -2750,7 +2750,7 @@ static int nbu2ss_ep_fifo_status(struct usb_ep *_ep)
preg = udc->p_regs;
- data = gpio_get_value(VBUS_VALUE);
+ data = gpiod_get_value(vbus_gpio);
if (data == 0)
return -EINVAL;
@@ -2790,7 +2790,7 @@ static void nbu2ss_ep_fifo_flush(struct usb_ep *_ep)
return;
}
- data = gpio_get_value(VBUS_VALUE);
+ data = gpiod_get_value(vbus_gpio);
if (data == 0)
return;
@@ -2832,7 +2832,7 @@ static int nbu2ss_gad_get_frame(struct usb_gadget *pgadget)
}
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
- data = gpio_get_value(VBUS_VALUE);
+ data = gpiod_get_value(vbus_gpio);
if (data == 0)
return -EINVAL;
@@ -2854,7 +2854,7 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
- data = gpio_get_value(VBUS_VALUE);
+ data = gpiod_get_value(vbus_gpio);
if (data == 0) {
dev_warn(&pgadget->dev, "VBUS LEVEL = %d\n", data);
return -EINVAL;
@@ -3119,12 +3119,13 @@ static int nbu2ss_drv_probe(struct platform_device *pdev)
}
/* VBUS Interrupt */
- irq_set_irq_type(INT_VBUS, IRQ_TYPE_EDGE_BOTH);
- status = request_irq(INT_VBUS,
+ vbus_irq = gpiod_to_irq(vbus_gpio);
+ irq_set_irq_type(vbus_irq, IRQ_TYPE_EDGE_BOTH);
+ status = request_irq(vbus_irq,
_nbu2ss_vbus_irq, IRQF_SHARED, driver_name, udc);
if (status != 0) {
- dev_err(udc->dev, "request_irq(INT_VBUS) failed\n");
+ dev_err(udc->dev, "request_irq(vbus_irq) failed\n");
return status;
}
@@ -3160,7 +3161,7 @@ static int nbu2ss_drv_remove(struct platform_device *pdev)
}
/* Interrupt Handler - Release */
- free_irq(INT_VBUS, udc);
+ free_irq(vbus_irq, udc);
return 0;
}
@@ -3201,7 +3202,7 @@ static int nbu2ss_drv_resume(struct platform_device *pdev)
if (!udc)
return 0;
- data = gpio_get_value(VBUS_VALUE);
+ data = gpiod_get_value(vbus_gpio);
if (data) {
udc->vbus_active = 1;
udc->devstate = USB_STATE_POWERED;
diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h
index e28a74da9633..b8c3dee5626c 100644
--- a/drivers/staging/emxx_udc/emxx_udc.h
+++ b/drivers/staging/emxx_udc/emxx_udc.h
@@ -30,6 +30,8 @@
/* below hacked up for staging integration */
#define GPIO_VBUS 0 /* GPIO_P153 on KZM9D */
#define INT_VBUS 0 /* IRQ for GPIO_P153 */
+struct gpio_desc *vbus_gpio;
+int vbus_irq;
/*------------ Board dependence(Wait) */
diff --git a/drivers/staging/erofs/Documentation/filesystems/erofs.txt b/drivers/staging/erofs/Documentation/filesystems/erofs.txt
new file mode 100644
index 000000000000..961ec4da7705
--- /dev/null
+++ b/drivers/staging/erofs/Documentation/filesystems/erofs.txt
@@ -0,0 +1,208 @@
+Overview
+========
+
+EROFS file-system stands for Enhanced Read-Only File System. Different
+from other read-only file systems, it aims to be designed for flexibility,
+scalability, but be kept simple and high performance.
+
+It is designed as a better filesystem solution for the following scenarios:
+ - read-only storage media or
+
+ - part of a fully trusted read-only solution, which means it needs to be
+ immutable and bit-for-bit identical to the official golden image for
+ their releases due to security and other considerations and
+
+ - hope to save some extra storage space with guaranteed end-to-end performance
+ by using reduced metadata and transparent file compression, especially
+ for those embedded devices with limited memory (ex, smartphone);
+
+Here is the main features of EROFS:
+ - Little endian on-disk design;
+
+ - Currently 4KB block size (nobh) and therefore maximum 16TB address space;
+
+ - Metadata & data could be mixed by design;
+
+ - 2 inode versions for different requirements:
+ v1 v2
+ Inode metadata size: 32 bytes 64 bytes
+ Max file size: 4 GB 16 EB (also limited by max. vol size)
+ Max uids/gids: 65536 4294967296
+ File creation time: no yes (64 + 32-bit timestamp)
+ Max hardlinks: 65536 4294967296
+ Metadata reserved: 4 bytes 14 bytes
+
+ - Support extended attributes (xattrs) as an option;
+
+ - Support xattr inline and tail-end data inline for all files;
+
+ - Support POSIX.1e ACLs by using xattrs;
+
+ - Support transparent file compression as an option:
+ LZ4 algorithm with 4 KB fixed-output compression for high performance;
+
+The following git tree provides the file system user-space tools under
+development (ex, formatting tool mkfs.erofs):
+>> git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
+
+Bugs and patches are welcome, please kindly help us and send to the following
+linux-erofs mailing list:
+>> linux-erofs mailing list <linux-erofs@lists.ozlabs.org>
+
+Note that EROFS is still working in progress as a Linux staging driver,
+Cc the staging mailing list as well is highly recommended:
+>> Linux Driver Project Developer List <devel@driverdev.osuosl.org>
+
+Mount options
+=============
+
+fault_injection=%d Enable fault injection in all supported types with
+ specified injection rate. Supported injection type:
+ Type_Name Type_Value
+ FAULT_KMALLOC 0x000000001
+(no)user_xattr Setup Extended User Attributes. Note: xattr is enabled
+ by default if CONFIG_EROFS_FS_XATTR is selected.
+(no)acl Setup POSIX Access Control List. Note: acl is enabled
+ by default if CONFIG_EROFS_FS_POSIX_ACL is selected.
+
+On-disk details
+===============
+
+Summary
+-------
+Different from other read-only file systems, an EROFS volume is designed
+to be as simple as possible:
+
+ |-> aligned with the block size
+ ____________________________________________________________
+ | |SB| | ... | Metadata | ... | Data | Metadata | ... | Data |
+ |_|__|_|_____|__________|_____|______|__________|_____|______|
+ 0 +1K
+
+All data areas should be aligned with the block size, but metadata areas
+may not. All metadatas can be now observed in two different spaces (views):
+ 1. Inode metadata space
+ Each valid inode should be aligned with an inode slot, which is a fixed
+ value (32 bytes) and designed to be kept in line with v1 inode size.
+
+ Each inode can be directly found with the following formula:
+ inode offset = meta_blkaddr * block_size + 32 * nid
+
+ |-> aligned with 8B
+ |-> followed closely
+ + meta_blkaddr blocks |-> another slot
+ _____________________________________________________________________
+ | ... | inode | xattrs | extents | data inline | ... | inode ...
+ |________|_______|(optional)|(optional)|__(optional)_|_____|__________
+ |-> aligned with the inode slot size
+ . .
+ . .
+ . .
+ . .
+ . .
+ . .
+ .____________________________________________________|-> aligned with 4B
+ | xattr_ibody_header | shared xattrs | inline xattrs |
+ |____________________|_______________|_______________|
+ |-> 12 bytes <-|->x * 4 bytes<-| .
+ . . .
+ . . .
+ . . .
+ ._______________________________.______________________.
+ | id | id | id | id | ... | id | ent | ... | ent| ... |
+ |____|____|____|____|______|____|_____|_____|____|_____|
+ |-> aligned with 4B
+ |-> aligned with 4B
+
+ Inode could be 32 or 64 bytes, which can be distinguished from a common
+ field which all inode versions have -- i_advise:
+
+ __________________ __________________
+ | i_advise | | i_advise |
+ |__________________| |__________________|
+ | ... | | ... |
+ | | | |
+ |__________________| 32 bytes | |
+ | |
+ |__________________| 64 bytes
+
+ Xattrs, extents, data inline are followed by the corresponding inode with
+ proper alignes, and they could be optional for different data mappings,
+ _currently_ there are totally 3 valid data mappings supported:
+
+ 1) flat file data without data inline (no extent);
+ 2) fixed-output size data compression (must have extents);
+ 3) flat file data with tail-end data inline (no extent);
+
+ The size of the optional xattrs is indicated by i_xattr_count in inode
+ header. Large xattrs or xattrs shared by many different files can be
+ stored in shared xattrs metadata rather than inlined right after inode.
+
+ 2. Shared xattrs metadata space
+ Shared xattrs space is similar to the above inode space, started with
+ a specific block indicated by xattr_blkaddr, organized one by one with
+ proper align.
+
+ Each share xattr can also be directly found by the following formula:
+ xattr offset = xattr_blkaddr * block_size + 4 * xattr_id
+
+ |-> aligned by 4 bytes
+ + xattr_blkaddr blocks |-> aligned with 4 bytes
+ _________________________________________________________________________
+ | ... | xattr_entry | xattr data | ... | xattr_entry | xattr data ...
+ |________|_____________|_____________|_____|______________|_______________
+
+Directories
+-----------
+All directories are now organized in a compact on-disk format. Note that
+each directory block is divided into index and name areas in order to support
+random file lookup, and all directory entries are _strictly_ recorded in
+alphabetical order in order to support improved prefix binary search
+algorithm (could refer to the related source code).
+
+ ___________________________
+ / |
+ / ______________|________________
+ / / | nameoff1 | nameoffN-1
+ ____________.______________._______________v________________v__________
+| dirent | dirent | ... | dirent | filename | filename | ... | filename |
+|___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____|
+ \ ^
+ \ | * could have
+ \ | trailing '\0'
+ \________________________| nameoff0
+
+ Directory block
+
+Note that apart from the offset of the first filename, nameoff0 also indicates
+the total number of directory entries in this block since it is no need to
+introduce another on-disk field at all.
+
+Compression
+-----------
+Currently, EROFS supports 4KB fixed-output clustersize transparent file
+compression, as illustrated below:
+
+ |---- Variant-Length Extent ----|-------- VLE --------|----- VLE -----
+ clusterofs clusterofs clusterofs
+ | | | logical data
+_________v_______________________________v_____________________v_______________
+... | . | | . | | . | ...
+____|____.________|_____________|________.____|_____________|__.__________|____
+ |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|
+ size size size size size
+ . . . .
+ . . . .
+ . . . .
+ _______._____________._____________._____________._____________________
+ ... | | | | ... physical data
+ _______|_____________|_____________|_____________|_____________________
+ |-> cluster <-|-> cluster <-|-> cluster <-|
+ size size size
+
+Currently each on-disk physical cluster can contain 4KB (un)compressed data
+at most. For each logical cluster, there is a corresponding on-disk index to
+describe its cluster type, physical cluster address, etc.
+
+See "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details.
+
diff --git a/drivers/staging/erofs/Makefile b/drivers/staging/erofs/Makefile
index c91b65223f99..38ab344a285e 100644
--- a/drivers/staging/erofs/Makefile
+++ b/drivers/staging/erofs/Makefile
@@ -6,7 +6,7 @@ ccflags-y += -Wall -DEROFS_VERSION=\"$(EROFS_VERSION)\"
obj-$(CONFIG_EROFS_FS) += erofs.o
# staging requirement: to be self-contained in its own directory
-ccflags-y += -I$(src)/include
+ccflags-y += -I $(srctree)/$(src)/include
erofs-objs := super.o inode.o data.o namei.o dir.o utils.o
erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o
erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o unzip_vle_lz4.o
diff --git a/drivers/staging/erofs/data.c b/drivers/staging/erofs/data.c
index 5a55f0bfdfbb..9c471f08ffd4 100644
--- a/drivers/staging/erofs/data.c
+++ b/drivers/staging/erofs/data.c
@@ -165,43 +165,16 @@ err_out:
return err;
}
-#ifdef CONFIG_EROFS_FS_ZIP
-extern int z_erofs_map_blocks_iter(struct inode *,
- struct erofs_map_blocks *,
- struct page **, int);
-#endif
-
-int erofs_map_blocks_iter(struct inode *inode,
- struct erofs_map_blocks *map,
- struct page **mpage_ret, int flags)
-{
- /* by default, reading raw data never use erofs_map_blocks_iter */
- if (unlikely(!is_inode_layout_compression(inode))) {
- if (*mpage_ret)
- put_page(*mpage_ret);
- *mpage_ret = NULL;
-
- return erofs_map_blocks(inode, map, flags);
- }
-
-#ifdef CONFIG_EROFS_FS_ZIP
- return z_erofs_map_blocks_iter(inode, map, mpage_ret, flags);
-#else
- /* data compression is not available */
- return -ENOTSUPP;
-#endif
-}
-
int erofs_map_blocks(struct inode *inode,
struct erofs_map_blocks *map, int flags)
{
if (unlikely(is_inode_layout_compression(inode))) {
- struct page *mpage = NULL;
- int err;
+ int err = z_erofs_map_blocks_iter(inode, map, flags);
- err = erofs_map_blocks_iter(inode, map, &mpage, flags);
- if (mpage)
- put_page(mpage);
+ if (map->mpage) {
+ put_page(map->mpage);
+ map->mpage = NULL;
+ }
return err;
}
return erofs_map_blocks_flatmode(inode, map, flags);
diff --git a/drivers/staging/erofs/dir.c b/drivers/staging/erofs/dir.c
index 833f052f79d0..829f7b12e0dc 100644
--- a/drivers/staging/erofs/dir.c
+++ b/drivers/staging/erofs/dir.c
@@ -24,8 +24,8 @@ static const unsigned char erofs_filetype_table[EROFS_FT_MAX] = {
};
static int erofs_fill_dentries(struct dir_context *ctx,
- void *dentry_blk, unsigned int *ofs,
- unsigned int nameoff, unsigned int maxsize)
+ void *dentry_blk, unsigned int *ofs,
+ unsigned int nameoff, unsigned int maxsize)
{
struct erofs_dirent *de = dentry_blk;
const struct erofs_dirent *end = dentry_blk + nameoff;
@@ -98,15 +98,14 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
if (IS_ERR(dentry_page))
continue;
- lock_page(dentry_page);
de = (struct erofs_dirent *)kmap(dentry_page);
nameoff = le16_to_cpu(de->nameoff);
if (unlikely(nameoff < sizeof(struct erofs_dirent) ||
- nameoff >= PAGE_SIZE)) {
+ nameoff >= PAGE_SIZE)) {
errln("%s, invalid de[0].nameoff %u",
- __func__, nameoff);
+ __func__, nameoff);
err = -EIO;
goto skip_this;
@@ -128,7 +127,6 @@ static int erofs_readdir(struct file *f, struct dir_context *ctx)
skip_this:
kunmap(dentry_page);
- unlock_page(dentry_page);
put_page(dentry_page);
ctx->pos = blknr_to_addr(i) + ofs;
@@ -144,6 +142,6 @@ skip_this:
const struct file_operations erofs_dir_fops = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
- .iterate = erofs_readdir,
+ .iterate_shared = erofs_readdir,
};
diff --git a/drivers/staging/erofs/inode.c b/drivers/staging/erofs/inode.c
index d7fbf5f4600f..924b8dfc7a8f 100644
--- a/drivers/staging/erofs/inode.c
+++ b/drivers/staging/erofs/inode.c
@@ -184,32 +184,18 @@ static int fill_inode(struct inode *inode, int isdir)
if (!err) {
/* setup the new inode */
if (S_ISREG(inode->i_mode)) {
-#ifdef CONFIG_EROFS_FS_XATTR
- if (vi->xattr_isize)
- inode->i_op = &erofs_generic_xattr_iops;
-#endif
+ inode->i_op = &erofs_generic_iops;
inode->i_fop = &generic_ro_fops;
} else if (S_ISDIR(inode->i_mode)) {
- inode->i_op =
-#ifdef CONFIG_EROFS_FS_XATTR
- vi->xattr_isize ? &erofs_dir_xattr_iops :
-#endif
- &erofs_dir_iops;
+ inode->i_op = &erofs_dir_iops;
inode->i_fop = &erofs_dir_fops;
} else if (S_ISLNK(inode->i_mode)) {
/* by default, page_get_link is used for symlink */
- inode->i_op =
-#ifdef CONFIG_EROFS_FS_XATTR
- &erofs_symlink_xattr_iops,
-#else
- &page_symlink_inode_operations;
-#endif
+ inode->i_op = &erofs_symlink_iops;
inode_nohighmem(inode);
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
-#ifdef CONFIG_EROFS_FS_XATTR
- inode->i_op = &erofs_special_inode_operations;
-#endif
+ inode->i_op = &erofs_generic_iops;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
} else {
err = -EIO;
@@ -297,23 +283,26 @@ struct inode *erofs_iget(struct super_block *sb,
return inode;
}
+const struct inode_operations erofs_generic_iops = {
#ifdef CONFIG_EROFS_FS_XATTR
-const struct inode_operations erofs_generic_xattr_iops = {
.listxattr = erofs_listxattr,
+#endif
+ .get_acl = erofs_get_acl,
};
-const struct inode_operations erofs_symlink_xattr_iops = {
+const struct inode_operations erofs_symlink_iops = {
.get_link = page_get_link,
+#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
+#endif
+ .get_acl = erofs_get_acl,
};
-const struct inode_operations erofs_special_inode_operations = {
- .listxattr = erofs_listxattr,
-};
-
-const struct inode_operations erofs_fast_symlink_xattr_iops = {
+const struct inode_operations erofs_fast_symlink_iops = {
.get_link = simple_get_link,
+#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
-};
#endif
+ .get_acl = erofs_get_acl,
+};
diff --git a/drivers/staging/erofs/internal.h b/drivers/staging/erofs/internal.h
index e049d00c087a..e3bfde00c7d2 100644
--- a/drivers/staging/erofs/internal.h
+++ b/drivers/staging/erofs/internal.h
@@ -252,47 +252,20 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
}
#endif
-static inline bool erofs_workgroup_get(struct erofs_workgroup *grp, int *ocnt)
-{
- int o;
-
-repeat:
- o = erofs_wait_on_workgroup_freezed(grp);
-
- if (unlikely(o <= 0))
- return -1;
-
- if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o))
- goto repeat;
-
- *ocnt = o;
- return 0;
-}
-
-#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount)
-#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount)
-
-extern int erofs_workgroup_put(struct erofs_workgroup *grp);
-
-extern struct erofs_workgroup *erofs_find_workgroup(
- struct super_block *sb, pgoff_t index, bool *tag);
-
-extern int erofs_register_workgroup(struct super_block *sb,
- struct erofs_workgroup *grp, bool tag);
-
-extern unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
- unsigned long nr_shrink, bool cleanup);
-
-static inline void erofs_workstation_cleanup_all(struct super_block *sb)
-{
- erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true);
-}
+int erofs_workgroup_put(struct erofs_workgroup *grp);
+struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
+ pgoff_t index, bool *tag);
+int erofs_register_workgroup(struct super_block *sb,
+ struct erofs_workgroup *grp, bool tag);
+unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
+ unsigned long nr_shrink, bool cleanup);
+void erofs_workgroup_free_rcu(struct erofs_workgroup *grp);
#ifdef EROFS_FS_HAS_MANAGED_CACHE
-extern int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
- struct erofs_workgroup *egrp);
-extern int erofs_try_to_free_cached_page(struct address_space *mapping,
- struct page *page);
+int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
+ struct erofs_workgroup *egrp);
+int erofs_try_to_free_cached_page(struct address_space *mapping,
+ struct page *page);
#define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping)
#else
@@ -354,12 +327,17 @@ static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
}
-#define inode_set_inited_xattr(inode) (EROFS_V(inode)->flags |= 1)
-#define inode_has_inited_xattr(inode) (EROFS_V(inode)->flags & 1)
+/* atomic flag definitions */
+#define EROFS_V_EA_INITED_BIT 0
+
+/* bitlock definitions (arranged in reverse order) */
+#define EROFS_V_BL_XATTR_BIT (BITS_PER_LONG - 1)
struct erofs_vnode {
erofs_nid_t nid;
- unsigned int flags;
+
+ /* atomic flags (including bitlocks) */
+ unsigned long flags;
unsigned char data_mapping_mode;
/* inline size in bytes */
@@ -412,8 +390,6 @@ static inline bool is_inode_layout_inline(struct inode *inode)
}
extern const struct super_operations erofs_sops;
-extern const struct inode_operations erofs_dir_iops;
-extern const struct file_operations erofs_dir_fops;
extern const struct address_space_operations erofs_raw_access_aops;
#ifdef CONFIG_EROFS_FS_ZIP
@@ -461,11 +437,26 @@ struct erofs_map_blocks {
u64 m_plen, m_llen;
unsigned int m_flags;
+
+ struct page *mpage;
};
/* Flags used by erofs_map_blocks() */
#define EROFS_GET_BLOCKS_RAW 0x0001
+#ifdef CONFIG_EROFS_FS_ZIP
+int z_erofs_map_blocks_iter(struct inode *inode,
+ struct erofs_map_blocks *map,
+ int flags);
+#else
+static inline int z_erofs_map_blocks_iter(struct inode *inode,
+ struct erofs_map_blocks *map,
+ int flags)
+{
+ return -ENOTSUPP;
+}
+#endif
+
/* data.c */
static inline struct bio *
erofs_grab_bio(struct super_block *sb,
@@ -506,8 +497,8 @@ static inline void __submit_bio(struct bio *bio, unsigned op, unsigned op_flags)
#define EROFS_IO_MAX_RETRIES_NOFAIL CONFIG_EROFS_FS_IO_MAX_RETRIES
#endif
-extern struct page *__erofs_get_meta_page(struct super_block *sb,
- erofs_blk_t blkaddr, bool prio, bool nofail);
+struct page *__erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr,
+ bool prio, bool nofail);
static inline struct page *erofs_get_meta_page(struct super_block *sb,
erofs_blk_t blkaddr, bool prio)
@@ -521,15 +512,7 @@ static inline struct page *erofs_get_meta_page_nofail(struct super_block *sb,
return __erofs_get_meta_page(sb, blkaddr, prio, true);
}
-extern int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int);
-extern int erofs_map_blocks_iter(struct inode *, struct erofs_map_blocks *,
- struct page **, int);
-
-struct erofs_map_blocks_iter {
- struct erofs_map_blocks map;
- struct page *mpage;
-};
-
+int erofs_map_blocks(struct inode *, struct erofs_map_blocks *, int);
static inline struct page *
erofs_get_inline_page(struct inode *inode,
@@ -549,41 +532,31 @@ static inline unsigned long erofs_inode_hash(erofs_nid_t nid)
#endif
}
-extern struct inode *erofs_iget(struct super_block *sb,
- erofs_nid_t nid, bool dir);
-
-/* dir.c */
-int erofs_namei(struct inode *dir, struct qstr *name,
- erofs_nid_t *nid, unsigned *d_type);
-
-#ifdef CONFIG_EROFS_FS_XATTR
-/* xattr.c */
-extern const struct xattr_handler *erofs_xattr_handlers[];
-
-/* symlink and special inode */
-extern const struct inode_operations erofs_symlink_xattr_iops;
-extern const struct inode_operations erofs_fast_symlink_xattr_iops;
-extern const struct inode_operations erofs_special_inode_operations;
-#endif
+extern const struct inode_operations erofs_generic_iops;
+extern const struct inode_operations erofs_symlink_iops;
+extern const struct inode_operations erofs_fast_symlink_iops;
static inline void set_inode_fast_symlink(struct inode *inode)
{
-#ifdef CONFIG_EROFS_FS_XATTR
- inode->i_op = &erofs_fast_symlink_xattr_iops;
-#else
- inode->i_op = &simple_symlink_inode_operations;
-#endif
+ inode->i_op = &erofs_fast_symlink_iops;
}
static inline bool is_inode_fast_symlink(struct inode *inode)
{
-#ifdef CONFIG_EROFS_FS_XATTR
- return inode->i_op == &erofs_fast_symlink_xattr_iops;
-#else
- return inode->i_op == &simple_symlink_inode_operations;
-#endif
+ return inode->i_op == &erofs_fast_symlink_iops;
}
+struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid, bool dir);
+
+/* namei.c */
+extern const struct inode_operations erofs_dir_iops;
+
+int erofs_namei(struct inode *dir, struct qstr *name,
+ erofs_nid_t *nid, unsigned int *d_type);
+
+/* dir.c */
+extern const struct file_operations erofs_dir_fops;
+
static inline void *erofs_vmap(struct page **pages, unsigned int count)
{
#ifdef CONFIG_EROFS_FS_USE_VM_MAP_RAM
@@ -612,15 +585,11 @@ static inline void erofs_vunmap(const void *mem, unsigned int count)
}
/* utils.c */
-extern struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp);
-
-extern void erofs_register_super(struct super_block *sb);
-extern void erofs_unregister_super(struct super_block *sb);
+extern struct shrinker erofs_shrinker_info;
-extern unsigned long erofs_shrink_count(struct shrinker *shrink,
- struct shrink_control *sc);
-extern unsigned long erofs_shrink_scan(struct shrinker *shrink,
- struct shrink_control *sc);
+struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp);
+void erofs_register_super(struct super_block *sb);
+void erofs_unregister_super(struct super_block *sb);
#ifndef lru_to_page
#define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
diff --git a/drivers/staging/erofs/namei.c b/drivers/staging/erofs/namei.c
index 5596c52e246d..3f4fa52c10fa 100644
--- a/drivers/staging/erofs/namei.c
+++ b/drivers/staging/erofs/namei.c
@@ -15,74 +15,77 @@
#include <trace/events/erofs.h>
-/* based on the value of qn->len is accurate */
-static inline int dirnamecmp(struct qstr *qn,
- struct qstr *qd, unsigned int *matched)
+struct erofs_qstr {
+ const unsigned char *name;
+ const unsigned char *end;
+};
+
+/* based on the end of qn is accurate and it must have the trailing '\0' */
+static inline int dirnamecmp(const struct erofs_qstr *qn,
+ const struct erofs_qstr *qd,
+ unsigned int *matched)
{
- unsigned int i = *matched, len = min(qn->len, qd->len);
-loop:
- if (unlikely(i >= len)) {
- *matched = i;
- if (qn->len < qd->len) {
- /*
- * actually (qn->len == qd->len)
- * when qd->name[i] == '\0'
- */
- return qd->name[i] == '\0' ? 0 : -1;
+ unsigned int i = *matched;
+
+ /*
+ * on-disk error, let's only BUG_ON in the debugging mode.
+ * otherwise, it will return 1 to just skip the invalid name
+ * and go on (in consideration of the lookup performance).
+ */
+ DBG_BUGON(qd->name > qd->end);
+
+ /* qd could not have trailing '\0' */
+ /* However it is absolutely safe if < qd->end */
+ while (qd->name + i < qd->end && qd->name[i] != '\0') {
+ if (qn->name[i] != qd->name[i]) {
+ *matched = i;
+ return qn->name[i] > qd->name[i] ? 1 : -1;
}
- return (qn->len > qd->len);
- }
-
- if (qn->name[i] != qd->name[i]) {
- *matched = i;
- return qn->name[i] > qd->name[i] ? 1 : -1;
+ ++i;
}
-
- ++i;
- goto loop;
+ *matched = i;
+ /* See comments in __d_alloc on the terminating NUL character */
+ return qn->name[i] == '\0' ? 0 : 1;
}
-static struct erofs_dirent *find_target_dirent(
- struct qstr *name,
- u8 *data, int maxsize)
+#define nameoff_from_disk(off, sz) (le16_to_cpu(off) & ((sz) - 1))
+
+static struct erofs_dirent *find_target_dirent(struct erofs_qstr *name,
+ u8 *data,
+ unsigned int dirblksize,
+ const int ndirents)
{
- unsigned int ndirents, head, back;
+ int head, back;
unsigned int startprfx, endprfx;
struct erofs_dirent *const de = (struct erofs_dirent *)data;
- /* make sure that maxsize is valid */
- BUG_ON(maxsize < sizeof(struct erofs_dirent));
-
- ndirents = le16_to_cpu(de->nameoff) / sizeof(*de);
-
- /* corrupted dir (may be unnecessary...) */
- BUG_ON(!ndirents);
-
- head = 0;
+ /* since the 1st dirent has been evaluated previously */
+ head = 1;
back = ndirents - 1;
startprfx = endprfx = 0;
while (head <= back) {
- unsigned int mid = head + (back - head) / 2;
- unsigned int nameoff = le16_to_cpu(de[mid].nameoff);
+ const int mid = head + (back - head) / 2;
+ const int nameoff = nameoff_from_disk(de[mid].nameoff,
+ dirblksize);
unsigned int matched = min(startprfx, endprfx);
-
- struct qstr dname = QSTR_INIT(data + nameoff,
- unlikely(mid >= ndirents - 1) ?
- maxsize - nameoff :
- le16_to_cpu(de[mid + 1].nameoff) - nameoff);
+ struct erofs_qstr dname = {
+ .name = data + nameoff,
+ .end = unlikely(mid >= ndirents - 1) ?
+ data + dirblksize :
+ data + nameoff_from_disk(de[mid + 1].nameoff,
+ dirblksize)
+ };
/* string comparison without already matched prefix */
int ret = dirnamecmp(name, &dname, &matched);
- if (unlikely(!ret))
+ if (unlikely(!ret)) {
return de + mid;
- else if (ret > 0) {
+ } else if (ret > 0) {
head = mid + 1;
startprfx = matched;
- } else if (unlikely(mid < 1)) /* fix "mid" overflow */
- break;
- else {
+ } else {
back = mid - 1;
endprfx = matched;
}
@@ -91,12 +94,12 @@ static struct erofs_dirent *find_target_dirent(
return ERR_PTR(-ENOENT);
}
-static struct page *find_target_block_classic(
- struct inode *dir,
- struct qstr *name, int *_diff)
+static struct page *find_target_block_classic(struct inode *dir,
+ struct erofs_qstr *name,
+ int *_ndirents)
{
unsigned int startprfx, endprfx;
- unsigned int head, back;
+ int head, back;
struct address_space *const mapping = dir->i_mapping;
struct page *candidate = ERR_PTR(-ENOENT);
@@ -105,89 +108,97 @@ static struct page *find_target_block_classic(
back = inode_datablocks(dir) - 1;
while (head <= back) {
- unsigned int mid = head + (back - head) / 2;
+ const int mid = head + (back - head) / 2;
struct page *page = read_mapping_page(mapping, mid, NULL);
- if (IS_ERR(page)) {
-exact_out:
- if (!IS_ERR(candidate)) /* valid candidate */
- put_page(candidate);
- return page;
- } else {
- int diff;
- unsigned int ndirents, matched;
- struct qstr dname;
+ if (!IS_ERR(page)) {
struct erofs_dirent *de = kmap_atomic(page);
- unsigned int nameoff = le16_to_cpu(de->nameoff);
-
- ndirents = nameoff / sizeof(*de);
+ const int nameoff = nameoff_from_disk(de->nameoff,
+ EROFS_BLKSIZ);
+ const int ndirents = nameoff / sizeof(*de);
+ int diff;
+ unsigned int matched;
+ struct erofs_qstr dname;
- /* corrupted dir (should have one entry at least) */
- BUG_ON(!ndirents || nameoff > PAGE_SIZE);
+ if (unlikely(!ndirents)) {
+ DBG_BUGON(1);
+ kunmap_atomic(de);
+ put_page(page);
+ page = ERR_PTR(-EIO);
+ goto out;
+ }
matched = min(startprfx, endprfx);
dname.name = (u8 *)de + nameoff;
- dname.len = ndirents == 1 ?
- /* since the rest of the last page is 0 */
- EROFS_BLKSIZ - nameoff
- : le16_to_cpu(de[1].nameoff) - nameoff;
+ if (ndirents == 1)
+ dname.end = (u8 *)de + EROFS_BLKSIZ;
+ else
+ dname.end = (u8 *)de +
+ nameoff_from_disk(de[1].nameoff,
+ EROFS_BLKSIZ);
/* string comparison without already matched prefix */
diff = dirnamecmp(name, &dname, &matched);
kunmap_atomic(de);
if (unlikely(!diff)) {
- *_diff = 0;
- goto exact_out;
+ *_ndirents = 0;
+ goto out;
} else if (diff > 0) {
head = mid + 1;
startprfx = matched;
- if (likely(!IS_ERR(candidate)))
+ if (!IS_ERR(candidate))
put_page(candidate);
candidate = page;
+ *_ndirents = ndirents;
} else {
put_page(page);
- if (unlikely(mid < 1)) /* fix "mid" overflow */
- break;
-
back = mid - 1;
endprfx = matched;
}
+ continue;
}
+out: /* free if the candidate is valid */
+ if (!IS_ERR(candidate))
+ put_page(candidate);
+ return page;
}
- *_diff = 1;
return candidate;
}
int erofs_namei(struct inode *dir,
- struct qstr *name,
- erofs_nid_t *nid, unsigned int *d_type)
+ struct qstr *name,
+ erofs_nid_t *nid, unsigned int *d_type)
{
- int diff;
+ int ndirents;
struct page *page;
- u8 *data;
+ void *data;
struct erofs_dirent *de;
+ struct erofs_qstr qn;
if (unlikely(!dir->i_size))
return -ENOENT;
- diff = 1;
- page = find_target_block_classic(dir, name, &diff);
+ qn.name = name->name;
+ qn.end = name->name + name->len;
+
+ ndirents = 0;
+ page = find_target_block_classic(dir, &qn, &ndirents);
- if (unlikely(IS_ERR(page)))
+ if (IS_ERR(page))
return PTR_ERR(page);
data = kmap_atomic(page);
/* the target page has been mapped */
- de = likely(diff) ?
- /* since the rest of the last page is 0 */
- find_target_dirent(name, data, EROFS_BLKSIZ) :
- (struct erofs_dirent *)data;
+ if (ndirents)
+ de = find_target_dirent(&qn, data, EROFS_BLKSIZ, ndirents);
+ else
+ de = (struct erofs_dirent *)data;
- if (likely(!IS_ERR(de))) {
+ if (!IS_ERR(de)) {
*nid = le64_to_cpu(de->nid);
*d_type = de->file_type;
}
@@ -235,12 +246,9 @@ static struct dentry *erofs_lookup(struct inode *dir,
const struct inode_operations erofs_dir_iops = {
.lookup = erofs_lookup,
-};
-
-const struct inode_operations erofs_dir_xattr_iops = {
- .lookup = erofs_lookup,
#ifdef CONFIG_EROFS_FS_XATTR
.listxattr = erofs_listxattr,
#endif
+ .get_acl = erofs_get_acl,
};
diff --git a/drivers/staging/erofs/super.c b/drivers/staging/erofs/super.c
index 1c2eb69682ef..15c784fba879 100644
--- a/drivers/staging/erofs/super.c
+++ b/drivers/staging/erofs/super.c
@@ -16,6 +16,7 @@
#include <linux/parser.h>
#include <linux/seq_file.h>
#include "internal.h"
+#include "xattr.h"
#define CREATE_TRACE_POINTS
#include <trace/events/erofs.h>
@@ -397,6 +398,11 @@ static int erofs_read_super(struct super_block *sb,
if (!silent)
infoln("root inode @ nid %llu", ROOT_NID(sbi));
+ if (test_opt(sbi, POSIX_ACL))
+ sb->s_flags |= SB_POSIXACL;
+ else
+ sb->s_flags &= ~SB_POSIXACL;
+
#ifdef CONFIG_EROFS_FS_ZIP
INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
#endif
@@ -420,13 +426,14 @@ static int erofs_read_super(struct super_block *sb,
errln("rootino(nid %llu) is not a directory(i_mode %o)",
ROOT_NID(sbi), inode->i_mode);
err = -EINVAL;
- goto err_isdir;
+ iput(inode);
+ goto err_iget;
}
sb->s_root = d_make_root(inode);
if (sb->s_root == NULL) {
err = -ENOMEM;
- goto err_makeroot;
+ goto err_iget;
}
/* save the device name to sbi */
@@ -452,10 +459,6 @@ static int erofs_read_super(struct super_block *sb,
*/
err_devname:
dput(sb->s_root);
-err_makeroot:
-err_isdir:
- if (sb->s_root == NULL)
- iput(inode);
err_iget:
#ifdef EROFS_FS_HAS_MANAGED_CACHE
iput(sbi->managed_cache);
@@ -493,7 +496,8 @@ static void erofs_put_super(struct super_block *sb)
mutex_lock(&sbi->umount_mutex);
#ifdef CONFIG_EROFS_FS_ZIP
- erofs_workstation_cleanup_all(sb);
+ /* clean up the compression space of this sb */
+ erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true);
#endif
erofs_unregister_super(sb);
@@ -537,12 +541,6 @@ static void erofs_kill_sb(struct super_block *sb)
kill_block_super(sb);
}
-static struct shrinker erofs_shrinker_info = {
- .scan_objects = erofs_shrink_scan,
- .count_objects = erofs_shrink_count,
- .seeks = DEFAULT_SEEKS,
-};
-
static struct file_system_type erofs_fs_type = {
.owner = THIS_MODULE,
.name = "erofs",
@@ -653,6 +651,11 @@ static int erofs_remount(struct super_block *sb, int *flags, char *data)
if (err)
goto out;
+ if (test_opt(sbi, POSIX_ACL))
+ sb->s_flags |= SB_POSIXACL;
+ else
+ sb->s_flags &= ~SB_POSIXACL;
+
*flags |= SB_RDONLY;
return 0;
out:
diff --git a/drivers/staging/erofs/unzip_vle.c b/drivers/staging/erofs/unzip_vle.c
index 4ac1099a39c6..02f34a83147d 100644
--- a/drivers/staging/erofs/unzip_vle.c
+++ b/drivers/staging/erofs/unzip_vle.c
@@ -107,15 +107,30 @@ enum z_erofs_vle_work_role {
Z_EROFS_VLE_WORK_SECONDARY,
Z_EROFS_VLE_WORK_PRIMARY,
/*
- * The current work has at least been linked with the following
- * processed chained works, which means if the processing page
- * is the tail partial page of the work, the current work can
- * safely use the whole page, as illustrated below:
- * +--------------+-------------------------------------------+
- * | tail page | head page (of the previous work) |
- * +--------------+-------------------------------------------+
- * /\ which belongs to the current work
- * [ (*) this page can be used for the current work itself. ]
+ * The current work was the tail of an exist chain, and the previous
+ * processed chained works are all decided to be hooked up to it.
+ * A new chain should be created for the remaining unprocessed works,
+ * therefore different from Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED,
+ * the next work cannot reuse the whole page in the following scenario:
+ * ________________________________________________________________
+ * | tail (partial) page | head (partial) page |
+ * | (belongs to the next work) | (belongs to the current work) |
+ * |_______PRIMARY_FOLLOWED_______|________PRIMARY_HOOKED___________|
+ */
+ Z_EROFS_VLE_WORK_PRIMARY_HOOKED,
+ /*
+ * The current work has been linked with the processed chained works,
+ * and could be also linked with the potential remaining works, which
+ * means if the processing page is the tail partial page of the work,
+ * the current work can safely use the whole page (since the next work
+ * is under control) for in-place decompression, as illustrated below:
+ * ________________________________________________________________
+ * | tail (partial) page | head (partial) page |
+ * | (of the current work) | (of the previous work) |
+ * | PRIMARY_FOLLOWED or | |
+ * |_____PRIMARY_HOOKED____|____________PRIMARY_FOLLOWED____________|
+ *
+ * [ (*) the above page can be used for the current work itself. ]
*/
Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED,
Z_EROFS_VLE_WORK_MAX
@@ -238,14 +253,9 @@ int erofs_try_to_free_cached_page(struct address_space *mapping,
{
struct erofs_sb_info *const sbi = EROFS_SB(mapping->host->i_sb);
const unsigned int clusterpages = erofs_clusterpages(sbi);
-
- struct z_erofs_vle_workgroup *grp;
+ struct z_erofs_vle_workgroup *const grp = (void *)page_private(page);
int ret = 0; /* 0 - busy */
- /* prevent the workgroup from being freed */
- rcu_read_lock();
- grp = (void *)page_private(page);
-
if (erofs_workgroup_try_to_freeze(&grp->obj, 1)) {
unsigned int i;
@@ -257,12 +267,11 @@ int erofs_try_to_free_cached_page(struct address_space *mapping,
}
}
erofs_workgroup_unfreeze(&grp->obj, 1);
- }
- rcu_read_unlock();
- if (ret) {
- ClearPagePrivate(page);
- put_page(page);
+ if (ret) {
+ ClearPagePrivate(page);
+ put_page(page);
+ }
}
return ret;
}
@@ -315,10 +324,10 @@ static int z_erofs_vle_work_add_page(
return ret ? 0 : -EAGAIN;
}
-static inline bool try_to_claim_workgroup(
- struct z_erofs_vle_workgroup *grp,
- z_erofs_vle_owned_workgrp_t *owned_head,
- bool *hosted)
+static enum z_erofs_vle_work_role
+try_to_claim_workgroup(struct z_erofs_vle_workgroup *grp,
+ z_erofs_vle_owned_workgrp_t *owned_head,
+ bool *hosted)
{
DBG_BUGON(*hosted == true);
@@ -332,6 +341,9 @@ retry:
*owned_head = &grp->next;
*hosted = true;
+ /* lucky, I am the followee :) */
+ return Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
+
} else if (grp->next == Z_EROFS_VLE_WORKGRP_TAIL) {
/*
* type 2, link to the end of a existing open chain,
@@ -341,12 +353,11 @@ retry:
if (cmpxchg(&grp->next, Z_EROFS_VLE_WORKGRP_TAIL,
*owned_head) != Z_EROFS_VLE_WORKGRP_TAIL)
goto retry;
-
*owned_head = Z_EROFS_VLE_WORKGRP_TAIL;
- } else
- return false; /* :( better luck next time */
+ return Z_EROFS_VLE_WORK_PRIMARY_HOOKED;
+ }
- return true; /* lucky, I am the followee :) */
+ return Z_EROFS_VLE_WORK_PRIMARY; /* :( better luck next time */
}
struct z_erofs_vle_work_finder {
@@ -424,12 +435,9 @@ z_erofs_vle_work_lookup(const struct z_erofs_vle_work_finder *f)
*f->hosted = false;
if (!primary)
*f->role = Z_EROFS_VLE_WORK_SECONDARY;
- /* claim the workgroup if possible */
- else if (try_to_claim_workgroup(grp, f->owned_head, f->hosted))
- *f->role = Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED;
- else
- *f->role = Z_EROFS_VLE_WORK_PRIMARY;
-
+ else /* claim the workgroup if possible */
+ *f->role = try_to_claim_workgroup(grp, f->owned_head,
+ f->hosted);
return work;
}
@@ -493,6 +501,9 @@ z_erofs_vle_work_register(const struct z_erofs_vle_work_finder *f,
return work;
}
+#define builder_is_hooked(builder) \
+ ((builder)->role >= Z_EROFS_VLE_WORK_PRIMARY_HOOKED)
+
#define builder_is_followed(builder) \
((builder)->role >= Z_EROFS_VLE_WORK_PRIMARY_FOLLOWED)
@@ -539,7 +550,7 @@ repeat:
if (unlikely(work == ERR_PTR(-EAGAIN)))
goto repeat;
- if (unlikely(IS_ERR(work)))
+ if (IS_ERR(work))
return PTR_ERR(work);
got_it:
z_erofs_pagevec_ctor_init(&builder->vector,
@@ -589,7 +600,7 @@ static void __z_erofs_vle_work_release(struct z_erofs_vle_workgroup *grp,
erofs_workgroup_put(&grp->obj);
}
-void z_erofs_vle_work_release(struct z_erofs_vle_work *work)
+static void z_erofs_vle_work_release(struct z_erofs_vle_work *work)
{
struct z_erofs_vle_workgroup *grp =
z_erofs_vle_work_workgroup(work, true);
@@ -636,7 +647,7 @@ struct z_erofs_vle_frontend {
struct inode *const inode;
struct z_erofs_vle_work_builder builder;
- struct erofs_map_blocks_iter m_iter;
+ struct erofs_map_blocks map;
z_erofs_vle_owned_workgrp_t owned_head;
@@ -647,8 +658,9 @@ struct z_erofs_vle_frontend {
#define VLE_FRONTEND_INIT(__i) { \
.inode = __i, \
- .m_iter = { \
- { .m_llen = 0, .m_plen = 0 }, \
+ .map = { \
+ .m_llen = 0, \
+ .m_plen = 0, \
.mpage = NULL \
}, \
.builder = VLE_WORK_BUILDER_INIT(), \
@@ -681,12 +693,11 @@ static int z_erofs_do_read_page(struct z_erofs_vle_frontend *fe,
{
struct super_block *const sb = fe->inode->i_sb;
struct erofs_sb_info *const sbi __maybe_unused = EROFS_SB(sb);
- struct erofs_map_blocks_iter *const m = &fe->m_iter;
- struct erofs_map_blocks *const map = &m->map;
+ struct erofs_map_blocks *const map = &fe->map;
struct z_erofs_vle_work_builder *const builder = &fe->builder;
const loff_t offset = page_offset(page);
- bool tight = builder_is_followed(builder);
+ bool tight = builder_is_hooked(builder);
struct z_erofs_vle_work *work = builder->work;
enum z_erofs_cache_alloctype cache_strategy;
@@ -704,8 +715,12 @@ repeat:
/* lucky, within the range of the current map_blocks */
if (offset + cur >= map->m_la &&
- offset + cur < map->m_la + map->m_llen)
+ offset + cur < map->m_la + map->m_llen) {
+ /* didn't get a valid unzip work previously (very rare) */
+ if (!builder->work)
+ goto restart_now;
goto hitted;
+ }
/* go ahead the next map_blocks */
debugln("%s: [out-of-range] pos %llu", __func__, offset + cur);
@@ -715,10 +730,11 @@ repeat:
map->m_la = offset + cur;
map->m_llen = 0;
- err = erofs_map_blocks_iter(fe->inode, map, &m->mpage, 0);
+ err = z_erofs_map_blocks_iter(fe->inode, map, 0);
if (unlikely(err))
goto err_out;
+restart_now:
if (unlikely(!(map->m_flags & EROFS_MAP_MAPPED)))
goto hitted;
@@ -740,7 +756,7 @@ repeat:
map->m_plen / PAGE_SIZE,
cache_strategy, page_pool, GFP_KERNEL);
- tight &= builder_is_followed(builder);
+ tight &= builder_is_hooked(builder);
work = builder->work;
hitted:
cur = end - min_t(unsigned int, offset + end - map->m_la, end);
@@ -755,6 +771,9 @@ hitted:
(tight ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED));
+ if (cur)
+ tight &= builder_is_followed(builder);
+
retry:
err = z_erofs_vle_work_add_page(builder, page, page_type);
/* should allocate an additional staging page for pagevec */
@@ -992,11 +1011,10 @@ repeat:
if (llen > grp->llen)
llen = grp->llen;
- err = z_erofs_vle_unzip_fast_percpu(compressed_pages,
- clusterpages, pages, llen, work->pageofs,
- z_erofs_onlinepage_endio);
+ err = z_erofs_vle_unzip_fast_percpu(compressed_pages, clusterpages,
+ pages, llen, work->pageofs);
if (err != -ENOTSUPP)
- goto out_percpu;
+ goto out;
if (sparsemem_pages >= nr_pages)
goto skip_allocpage;
@@ -1017,8 +1035,25 @@ skip_allocpage:
erofs_vunmap(vout, nr_pages);
out:
+ /* must handle all compressed pages before endding pages */
+ for (i = 0; i < clusterpages; ++i) {
+ page = compressed_pages[i];
+
+#ifdef EROFS_FS_HAS_MANAGED_CACHE
+ if (page->mapping == MNGD_MAPPING(sbi))
+ continue;
+#endif
+ /* recycle all individual staging pages */
+ (void)z_erofs_gather_if_stagingpage(page_pool, page);
+
+ WRITE_ONCE(compressed_pages[i], NULL);
+ }
+
for (i = 0; i < nr_pages; ++i) {
page = pages[i];
+ if (!page)
+ continue;
+
DBG_BUGON(!page->mapping);
/* recycle all individual staging pages */
@@ -1031,20 +1066,6 @@ out:
z_erofs_onlinepage_endio(page);
}
-out_percpu:
- for (i = 0; i < clusterpages; ++i) {
- page = compressed_pages[i];
-
-#ifdef EROFS_FS_HAS_MANAGED_CACHE
- if (page->mapping == MNGD_MAPPING(sbi))
- continue;
-#endif
- /* recycle all individual staging pages */
- (void)z_erofs_gather_if_stagingpage(page_pool, page);
-
- WRITE_ONCE(compressed_pages[i], NULL);
- }
-
if (pages == z_pagemap_global)
mutex_unlock(&z_pagemap_global_lock);
else if (unlikely(pages != pages_onstack))
@@ -1484,8 +1505,8 @@ static int z_erofs_vle_normalaccess_readpage(struct file *file,
z_erofs_submit_and_unzip(&f, &pagepool, true);
out:
- if (f.m_iter.mpage)
- put_page(f.m_iter.mpage);
+ if (f.map.mpage)
+ put_page(f.map.mpage);
/* clean up the remaining free pages */
put_pages_list(&pagepool);
@@ -1555,8 +1576,8 @@ static int z_erofs_vle_normalaccess_readpages(struct file *filp,
z_erofs_submit_and_unzip(&f, &pagepool, sync);
- if (f.m_iter.mpage)
- put_page(f.m_iter.mpage);
+ if (f.map.mpage)
+ put_page(f.map.mpage);
/* clean up the remaining free pages */
put_pages_list(&pagepool);
@@ -1701,14 +1722,14 @@ vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx,
int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
- struct page **mpage_ret, int flags)
+ int flags)
{
void *kaddr;
const struct vle_map_blocks_iter_ctx ctx = {
.inode = inode,
.sb = inode->i_sb,
.clusterbits = EROFS_I_SB(inode)->clusterbits,
- .mpage_ret = mpage_ret,
+ .mpage_ret = &map->mpage,
.kaddr_ret = &kaddr
};
const unsigned int clustersize = 1 << ctx.clusterbits;
@@ -1722,7 +1743,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
/* initialize `pblk' to keep gcc from printing foolish warnings */
erofs_blk_t mblk, pblk = 0;
- struct page *mpage = *mpage_ret;
+ struct page *mpage = map->mpage;
struct z_erofs_vle_decompressed_index *di;
unsigned int cluster_type, logical_cluster_ofs;
int err = 0;
@@ -1758,7 +1779,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
err = PTR_ERR(mpage);
goto out;
}
- *mpage_ret = mpage;
+ map->mpage = mpage;
} else {
lock_page(mpage);
DBG_BUGON(!PageUptodate(mpage));
@@ -1818,7 +1839,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
/* get the correspoinding first chunk */
err = vle_get_logical_extent_head(&ctx, lcn, &ofs,
&pblk, &map->m_flags);
- mpage = *mpage_ret;
+ mpage = map->mpage;
if (unlikely(err)) {
if (mpage)
diff --git a/drivers/staging/erofs/unzip_vle.h b/drivers/staging/erofs/unzip_vle.h
index 5a4e1b62c0d1..517e5ce8c5e9 100644
--- a/drivers/staging/erofs/unzip_vle.h
+++ b/drivers/staging/erofs/unzip_vle.h
@@ -212,18 +212,17 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
#define Z_EROFS_VLE_VMAP_GLOBAL_PAGES 2048
/* unzip_vle_lz4.c */
-extern int z_erofs_vle_plain_copy(struct page **compressed_pages,
- unsigned clusterpages, struct page **pages,
- unsigned nr_pages, unsigned short pageofs);
-
-extern int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
- unsigned clusterpages, struct page **pages,
- unsigned outlen, unsigned short pageofs,
- void (*endio)(struct page *));
-
-extern int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
- unsigned clusterpages, void *vaddr, unsigned llen,
- unsigned short pageofs, bool overlapped);
+int z_erofs_vle_plain_copy(struct page **compressed_pages,
+ unsigned int clusterpages, struct page **pages,
+ unsigned int nr_pages, unsigned short pageofs);
+int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
+ unsigned int clusterpages,
+ struct page **pages, unsigned int outlen,
+ unsigned short pageofs);
+int z_erofs_vle_unzip_vmap(struct page **compressed_pages,
+ unsigned int clusterpages,
+ void *vaddr, unsigned int llen,
+ unsigned short pageofs, bool overlapped);
#endif
diff --git a/drivers/staging/erofs/unzip_vle_lz4.c b/drivers/staging/erofs/unzip_vle_lz4.c
index 52797bd89da1..48b263a2731a 100644
--- a/drivers/staging/erofs/unzip_vle_lz4.c
+++ b/drivers/staging/erofs/unzip_vle_lz4.c
@@ -13,7 +13,7 @@
#include "unzip_vle.h"
#include <linux/lz4.h>
-int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen)
+static int z_erofs_unzip_lz4(void *in, void *out, size_t inlen, size_t outlen)
{
int ret = LZ4_decompress_safe_partial(in, out, inlen, outlen, outlen);
@@ -125,8 +125,7 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
unsigned int clusterpages,
struct page **pages,
unsigned int outlen,
- unsigned short pageofs,
- void (*endio)(struct page *))
+ unsigned short pageofs)
{
void *vin, *vout;
unsigned int nr_pages, i, j;
@@ -148,19 +147,16 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
ret = z_erofs_unzip_lz4(vin, vout + pageofs,
clusterpages * PAGE_SIZE, outlen);
- if (ret >= 0) {
- outlen = ret;
- ret = 0;
- }
+ if (ret < 0)
+ goto out;
+ ret = 0;
for (i = 0; i < nr_pages; ++i) {
j = min((unsigned int)PAGE_SIZE - pageofs, outlen);
if (pages[i]) {
- if (ret < 0) {
- SetPageError(pages[i]);
- } else if (clusterpages == 1 &&
- pages[i] == compressed_pages[0]) {
+ if (clusterpages == 1 &&
+ pages[i] == compressed_pages[0]) {
memcpy(vin + pageofs, vout + pageofs, j);
} else {
void *dst = kmap_atomic(pages[i]);
@@ -168,12 +164,13 @@ int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages,
memcpy(dst + pageofs, vout + pageofs, j);
kunmap_atomic(dst);
}
- endio(pages[i]);
}
vout += PAGE_SIZE;
outlen -= j;
pageofs = 0;
}
+
+out:
preempt_enable();
if (clusterpages == 1)
diff --git a/drivers/staging/erofs/utils.c b/drivers/staging/erofs/utils.c
index b535898ca753..5f61f99f4c10 100644
--- a/drivers/staging/erofs/utils.c
+++ b/drivers/staging/erofs/utils.c
@@ -31,13 +31,32 @@ struct page *erofs_allocpage(struct list_head *pool, gfp_t gfp)
static atomic_long_t erofs_global_shrink_cnt;
#ifdef CONFIG_EROFS_FS_ZIP
+#define __erofs_workgroup_get(grp) atomic_inc(&(grp)->refcount)
+#define __erofs_workgroup_put(grp) atomic_dec(&(grp)->refcount)
-struct erofs_workgroup *erofs_find_workgroup(
- struct super_block *sb, pgoff_t index, bool *tag)
+static int erofs_workgroup_get(struct erofs_workgroup *grp)
+{
+ int o;
+
+repeat:
+ o = erofs_wait_on_workgroup_freezed(grp);
+ if (unlikely(o <= 0))
+ return -1;
+
+ if (unlikely(atomic_cmpxchg(&grp->refcount, o, o + 1) != o))
+ goto repeat;
+
+ /* decrease refcount paired by erofs_workgroup_put */
+ if (unlikely(o == 1))
+ atomic_long_dec(&erofs_global_shrink_cnt);
+ return 0;
+}
+
+struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
+ pgoff_t index, bool *tag)
{
struct erofs_sb_info *sbi = EROFS_SB(sb);
struct erofs_workgroup *grp;
- int oldcount;
repeat:
rcu_read_lock();
@@ -46,15 +65,12 @@ repeat:
*tag = xa_pointer_tag(grp);
grp = xa_untag_pointer(grp);
- if (erofs_workgroup_get(grp, &oldcount)) {
+ if (erofs_workgroup_get(grp)) {
/* prefer to relax rcu read side */
rcu_read_unlock();
goto repeat;
}
- /* decrease refcount added by erofs_workgroup_put */
- if (unlikely(oldcount == 1))
- atomic_long_dec(&erofs_global_shrink_cnt);
DBG_BUGON(index != grp->index);
}
rcu_read_unlock();
@@ -104,8 +120,6 @@ int erofs_register_workgroup(struct super_block *sb,
return err;
}
-extern void erofs_workgroup_free_rcu(struct erofs_workgroup *grp);
-
static void __erofs_workgroup_free(struct erofs_workgroup *grp)
{
atomic_long_dec(&erofs_global_shrink_cnt);
@@ -131,9 +145,9 @@ static void erofs_workgroup_unfreeze_final(struct erofs_workgroup *grp)
__erofs_workgroup_free(grp);
}
-bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
- struct erofs_workgroup *grp,
- bool cleanup)
+static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
+ struct erofs_workgroup *grp,
+ bool cleanup)
{
/*
* for managed cache enabled, the refcount of workgroups
@@ -172,9 +186,9 @@ bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
#else
/* for nocache case, no customized reclaim path at all */
-bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
- struct erofs_workgroup *grp,
- bool cleanup)
+static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
+ struct erofs_workgroup *grp,
+ bool cleanup)
{
int cnt = atomic_read(&grp->refcount);
@@ -256,14 +270,14 @@ void erofs_unregister_super(struct super_block *sb)
spin_unlock(&erofs_sb_list_lock);
}
-unsigned long erofs_shrink_count(struct shrinker *shrink,
- struct shrink_control *sc)
+static unsigned long erofs_shrink_count(struct shrinker *shrink,
+ struct shrink_control *sc)
{
return atomic_long_read(&erofs_global_shrink_cnt);
}
-unsigned long erofs_shrink_scan(struct shrinker *shrink,
- struct shrink_control *sc)
+static unsigned long erofs_shrink_scan(struct shrinker *shrink,
+ struct shrink_control *sc)
{
struct erofs_sb_info *sbi;
struct list_head *p;
@@ -319,3 +333,9 @@ unsigned long erofs_shrink_scan(struct shrinker *shrink,
return freed;
}
+struct shrinker erofs_shrinker_info = {
+ .scan_objects = erofs_shrink_scan,
+ .count_objects = erofs_shrink_count,
+ .seeks = DEFAULT_SEEKS,
+};
+
diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c
index 80dca6a4adbe..f716ab0446e5 100644
--- a/drivers/staging/erofs/xattr.c
+++ b/drivers/staging/erofs/xattr.c
@@ -44,19 +44,48 @@ static inline void xattr_iter_end_final(struct xattr_iter *it)
static int init_inode_xattrs(struct inode *inode)
{
+ struct erofs_vnode *const vi = EROFS_V(inode);
struct xattr_iter it;
unsigned int i;
struct erofs_xattr_ibody_header *ih;
struct super_block *sb;
struct erofs_sb_info *sbi;
- struct erofs_vnode *vi;
bool atomic_map;
+ int ret = 0;
- if (likely(inode_has_inited_xattr(inode)))
+ /* the most case is that xattrs of this inode are initialized. */
+ if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
return 0;
- vi = EROFS_V(inode);
- BUG_ON(!vi->xattr_isize);
+ if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_XATTR_BIT, TASK_KILLABLE))
+ return -ERESTARTSYS;
+
+ /* someone has initialized xattrs for us? */
+ if (test_bit(EROFS_V_EA_INITED_BIT, &vi->flags))
+ goto out_unlock;
+
+ /*
+ * bypass all xattr operations if ->xattr_isize is not greater than
+ * sizeof(struct erofs_xattr_ibody_header), in detail:
+ * 1) it is not enough to contain erofs_xattr_ibody_header then
+ * ->xattr_isize should be 0 (it means no xattr);
+ * 2) it is just to contain erofs_xattr_ibody_header, which is on-disk
+ * undefined right now (maybe use later with some new sb feature).
+ */
+ if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) {
+ errln("xattr_isize %d of nid %llu is not supported yet",
+ vi->xattr_isize, vi->nid);
+ ret = -ENOTSUPP;
+ goto out_unlock;
+ } else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) {
+ if (unlikely(vi->xattr_isize)) {
+ DBG_BUGON(1);
+ ret = -EIO;
+ goto out_unlock; /* xattr ondisk layout error */
+ }
+ ret = -ENOATTR;
+ goto out_unlock;
+ }
sb = inode->i_sb;
sbi = EROFS_SB(sb);
@@ -64,8 +93,10 @@ static int init_inode_xattrs(struct inode *inode)
it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
it.page = erofs_get_inline_page(inode, it.blkaddr);
- if (IS_ERR(it.page))
- return PTR_ERR(it.page);
+ if (IS_ERR(it.page)) {
+ ret = PTR_ERR(it.page);
+ goto out_unlock;
+ }
/* read in shared xattr array (non-atomic, see kmalloc below) */
it.kaddr = kmap(it.page);
@@ -78,7 +109,8 @@ static int init_inode_xattrs(struct inode *inode)
sizeof(uint), GFP_KERNEL);
if (vi->xattr_shared_xattrs == NULL) {
xattr_iter_end(&it, atomic_map);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_unlock;
}
/* let's skip ibody header */
@@ -92,8 +124,12 @@ static int init_inode_xattrs(struct inode *inode)
it.page = erofs_get_meta_page(sb,
++it.blkaddr, S_ISDIR(inode->i_mode));
- if (IS_ERR(it.page))
- return PTR_ERR(it.page);
+ if (IS_ERR(it.page)) {
+ kfree(vi->xattr_shared_xattrs);
+ vi->xattr_shared_xattrs = NULL;
+ ret = PTR_ERR(it.page);
+ goto out_unlock;
+ }
it.kaddr = kmap_atomic(it.page);
atomic_map = true;
@@ -105,8 +141,11 @@ static int init_inode_xattrs(struct inode *inode)
}
xattr_iter_end(&it, atomic_map);
- inode_set_inited_xattr(inode);
- return 0;
+ set_bit(EROFS_V_EA_INITED_BIT, &vi->flags);
+
+out_unlock:
+ clear_and_wake_up_bit(EROFS_V_BL_XATTR_BIT, &vi->flags);
+ return ret;
}
/*
@@ -117,10 +156,12 @@ static int init_inode_xattrs(struct inode *inode)
* and need to be handled
*/
struct xattr_iter_handlers {
- int (*entry)(struct xattr_iter *, struct erofs_xattr_entry *);
- int (*name)(struct xattr_iter *, unsigned int, char *, unsigned int);
- int (*alloc_buffer)(struct xattr_iter *, unsigned int);
- void (*value)(struct xattr_iter *, unsigned int, char *, unsigned int);
+ int (*entry)(struct xattr_iter *_it, struct erofs_xattr_entry *entry);
+ int (*name)(struct xattr_iter *_it, unsigned int processed, char *buf,
+ unsigned int len);
+ int (*alloc_buffer)(struct xattr_iter *_it, unsigned int value_sz);
+ void (*value)(struct xattr_iter *_it, unsigned int processed, char *buf,
+ unsigned int len);
};
static inline int xattr_iter_fixup(struct xattr_iter *it)
@@ -422,7 +463,6 @@ static int erofs_xattr_generic_get(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *name, void *buffer, size_t size)
{
- struct erofs_vnode *const vi = EROFS_V(inode);
struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
switch (handler->flags) {
@@ -440,9 +480,6 @@ static int erofs_xattr_generic_get(const struct xattr_handler *handler,
return -EINVAL;
}
- if (!vi->xattr_isize)
- return -ENOATTR;
-
return erofs_getxattr(inode, handler->flags, name, buffer, size);
}
@@ -503,8 +540,7 @@ static int xattr_entrylist(struct xattr_iter *_it,
if (h == NULL || (h->list != NULL && !h->list(it->dentry)))
return 1;
- /* Note that at least one of 'prefix' and 'name' should be non-NULL */
- prefix = h->prefix != NULL ? h->prefix : h->name;
+ prefix = xattr_prefix(h);
prefix_len = strlen(prefix);
if (it->buffer == NULL) {
@@ -627,3 +663,40 @@ ssize_t erofs_listxattr(struct dentry *dentry,
return shared_listxattr(&it);
}
+#ifdef CONFIG_EROFS_FS_POSIX_ACL
+struct posix_acl *erofs_get_acl(struct inode *inode, int type)
+{
+ struct posix_acl *acl;
+ int prefix, rc;
+ char *value = NULL;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ prefix = EROFS_XATTR_INDEX_POSIX_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ prefix = EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ rc = erofs_getxattr(inode, prefix, "", NULL, 0);
+ if (rc > 0) {
+ value = kmalloc(rc, GFP_KERNEL);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ rc = erofs_getxattr(inode, prefix, "", value, rc);
+ }
+
+ if (rc == -ENOATTR)
+ acl = NULL;
+ else if (rc < 0)
+ acl = ERR_PTR(rc);
+ else
+ acl = posix_acl_from_xattr(&init_user_ns, value, rc);
+ kfree(value);
+ return acl;
+}
+#endif
+
diff --git a/drivers/staging/erofs/xattr.h b/drivers/staging/erofs/xattr.h
index 0c7379282fc5..35ba5ac2139a 100644
--- a/drivers/staging/erofs/xattr.h
+++ b/drivers/staging/erofs/xattr.h
@@ -68,9 +68,7 @@ static const struct xattr_handler *xattr_handler_map[] = {
}
#ifdef CONFIG_EROFS_FS_XATTR
-
-extern const struct inode_operations erofs_generic_xattr_iops;
-extern const struct inode_operations erofs_dir_xattr_iops;
+extern const struct xattr_handler *erofs_xattr_handlers[];
int erofs_getxattr(struct inode *, int, const char *, void *, size_t);
ssize_t erofs_listxattr(struct dentry *, char *, size_t);
@@ -89,5 +87,11 @@ static ssize_t __maybe_unused erofs_listxattr(struct dentry *dentry,
}
#endif
+#ifdef CONFIG_EROFS_FS_POSIX_ACL
+struct posix_acl *erofs_get_acl(struct inode *inode, int type);
+#else
+#define erofs_get_acl (NULL)
+#endif
+
#endif
diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c
index f6f30f5bf15a..8f27bd8da17d 100644
--- a/drivers/staging/fbtft/fb_agm1264k-fl.c
+++ b/drivers/staging/fbtft/fb_agm1264k-fl.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -79,14 +79,14 @@ static int init_display(struct fbtft_par *par)
static void reset(struct fbtft_par *par)
{
- if (par->gpio.reset == -1)
+ if (!par->gpio.reset)
return;
dev_dbg(par->info->device, "%s()\n", __func__);
- gpio_set_value(par->gpio.reset, 0);
+ gpiod_set_value(par->gpio.reset, 0);
udelay(20);
- gpio_set_value(par->gpio.reset, 1);
+ gpiod_set_value(par->gpio.reset, 1);
mdelay(120);
}
@@ -98,30 +98,30 @@ static int verify_gpios(struct fbtft_par *par)
dev_dbg(par->info->device,
"%s()\n", __func__);
- if (par->EPIN < 0) {
+ if (!par->EPIN) {
dev_err(par->info->device,
"Missing info about 'wr' (aka E) gpio. Aborting.\n");
return -EINVAL;
}
for (i = 0; i < 8; ++i) {
- if (par->gpio.db[i] < 0) {
+ if (!par->gpio.db[i]) {
dev_err(par->info->device,
"Missing info about 'db[%i]' gpio. Aborting.\n",
i);
return -EINVAL;
}
}
- if (par->CS0 < 0) {
+ if (!par->CS0) {
dev_err(par->info->device,
"Missing info about 'cs0' gpio. Aborting.\n");
return -EINVAL;
}
- if (par->CS1 < 0) {
+ if (!par->CS1) {
dev_err(par->info->device,
"Missing info about 'cs1' gpio. Aborting.\n");
return -EINVAL;
}
- if (par->RW < 0) {
+ if (!par->RW) {
dev_err(par->info->device,
"Missing info about 'rw' gpio. Aborting.\n");
return -EINVAL;
@@ -139,22 +139,22 @@ request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio)
if (strcasecmp(gpio->name, "wr") == 0) {
/* left ks0108 E pin */
par->EPIN = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
+ return GPIOD_OUT_LOW;
} else if (strcasecmp(gpio->name, "cs0") == 0) {
/* left ks0108 controller pin */
par->CS0 = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
+ return GPIOD_OUT_HIGH;
} else if (strcasecmp(gpio->name, "cs1") == 0) {
/* right ks0108 controller pin */
par->CS1 = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
+ return GPIOD_OUT_HIGH;
}
/* if write (rw = 0) e(1->0) perform write */
/* if read (rw = 1) e(0->1) set data on D0-7*/
else if (strcasecmp(gpio->name, "rw") == 0) {
par->RW = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
+ return GPIOD_OUT_LOW;
}
return FBTFT_GPIO_NO_MATCH;
@@ -194,15 +194,15 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
/* select chip */
if (*buf) {
/* cs1 */
- gpio_set_value(par->CS0, 1);
- gpio_set_value(par->CS1, 0);
+ gpiod_set_value(par->CS0, 1);
+ gpiod_set_value(par->CS1, 0);
} else {
/* cs0 */
- gpio_set_value(par->CS0, 0);
- gpio_set_value(par->CS1, 1);
+ gpiod_set_value(par->CS0, 0);
+ gpiod_set_value(par->CS1, 1);
}
- gpio_set_value(par->RS, 0); /* RS->0 (command mode) */
+ gpiod_set_value(par->RS, 0); /* RS->0 (command mode) */
len--;
if (len) {
@@ -364,7 +364,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
write_reg(par, 0x00, (0x17 << 3) | (u8)y);
/* write bitmap */
- gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+ gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */
ret = par->fbtftops.write(par, buf, len);
if (ret < 0)
dev_err(par->info->device,
@@ -387,7 +387,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
write_reg(par, 0x01, (0x17 << 3) | (u8)y);
/* write bitmap */
- gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+ gpiod_set_value(par->RS, 1); /* RS->1 (data mode) */
par->fbtftops.write(par, buf, len);
if (ret < 0)
dev_err(par->info->device,
@@ -397,8 +397,8 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
kfree(convert_buf);
- gpio_set_value(par->CS0, 1);
- gpio_set_value(par->CS1, 1);
+ gpiod_set_value(par->CS0, 1);
+ gpiod_set_value(par->CS1, 1);
return ret;
}
@@ -408,7 +408,7 @@ static int write(struct fbtft_par *par, void *buf, size_t len)
fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
"%s(len=%d): ", __func__, len);
- gpio_set_value(par->RW, 0); /* set write mode */
+ gpiod_set_value(par->RW, 0); /* set write mode */
while (len--) {
u8 i, data;
@@ -417,12 +417,12 @@ static int write(struct fbtft_par *par, void *buf, size_t len)
/* set data bus */
for (i = 0; i < 8; ++i)
- gpio_set_value(par->gpio.db[i], data & (1 << i));
+ gpiod_set_value(par->gpio.db[i], data & (1 << i));
/* set E */
- gpio_set_value(par->EPIN, 1);
+ gpiod_set_value(par->EPIN, 1);
udelay(5);
/* unset E - write */
- gpio_set_value(par->EPIN, 0);
+ gpiod_set_value(par->EPIN, 0);
udelay(1);
}
diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c
index a58c514f4721..b6c6d66e4eb1 100644
--- a/drivers/staging/fbtft/fb_bd663474.c
+++ b/drivers/staging/fbtft/fb_bd663474.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -24,8 +24,8 @@
static int init_display(struct fbtft_par *par)
{
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
par->fbtftops.reset(par);
diff --git a/drivers/staging/fbtft/fb_ili9163.c b/drivers/staging/fbtft/fb_ili9163.c
index 86e140244aab..d609a2b67db9 100644
--- a/drivers/staging/fbtft/fb_ili9163.c
+++ b/drivers/staging/fbtft/fb_ili9163.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
@@ -77,8 +77,8 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
write_reg(par, MIPI_DCS_SOFT_RESET); /* software reset */
mdelay(500);
diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c
index 740c0acbecd8..ea6e001288ce 100644
--- a/drivers/staging/fbtft/fb_ili9320.c
+++ b/drivers/staging/fbtft/fb_ili9320.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c
index 2cf75f2e03e2..b090e7ab6fdd 100644
--- a/drivers/staging/fbtft/fb_ili9325.c
+++ b/drivers/staging/fbtft/fb_ili9325.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -85,8 +85,8 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
bt &= 0x07;
vc &= 0x07;
diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c
index 430f21e50f4d..415183c7054a 100644
--- a/drivers/staging/fbtft/fb_ili9340.c
+++ b/drivers/staging/fbtft/fb_ili9340.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <video/mipi_display.h>
diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c
index 32172f8f79f0..ad49973ad594 100644
--- a/drivers/staging/fbtft/fb_pcd8544.c
+++ b/drivers/staging/fbtft/fb_pcd8544.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -119,7 +119,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
/* Write data */
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
ret = par->fbtftops.write(par, par->txbuf.buf, 6 * 84);
if (ret < 0)
dev_err(par->info->device, "write failed and returned: %d\n",
diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
index 5d3b76ca74d8..70b37fc7fb66 100644
--- a/drivers/staging/fbtft/fb_ra8875.c
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -9,7 +9,7 @@
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include "fbtft.h"
#define DRVNAME "fb_ra8875"
@@ -39,7 +39,7 @@ static int write_spi(struct fbtft_par *par, void *buf, size_t len)
static int init_display(struct fbtft_par *par)
{
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
"%s()\n", __func__);
diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c
index aa716f33420a..b3d0701880fe 100644
--- a/drivers/staging/fbtft/fb_s6d1121.c
+++ b/drivers/staging/fbtft/fb_s6d1121.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -29,8 +29,8 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
/* Initialization sequence from Lib_UTFT */
diff --git a/drivers/staging/fbtft/fb_sh1106.c b/drivers/staging/fbtft/fb_sh1106.c
index 00096f8d249a..6f7249493ea3 100644
--- a/drivers/staging/fbtft/fb_sh1106.c
+++ b/drivers/staging/fbtft/fb_sh1106.c
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c
index c9b18b3ba4ab..bbf75f795234 100644
--- a/drivers/staging/fbtft/fb_ssd1289.c
+++ b/drivers/staging/fbtft/fb_ssd1289.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include "fbtft.h"
@@ -28,8 +28,8 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
write_reg(par, 0x00, 0x0001);
write_reg(par, 0x03, 0xA8A4);
diff --git a/drivers/staging/fbtft/fb_ssd1305.c b/drivers/staging/fbtft/fb_ssd1305.c
index 3515888d94c9..020fe48fed0b 100644
--- a/drivers/staging/fbtft/fb_ssd1305.c
+++ b/drivers/staging/fbtft/fb_ssd1305.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -168,7 +168,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
/* Write data */
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
ret = par->fbtftops.write(par, par->txbuf.buf,
par->info->var.xres * par->info->var.yres /
8);
diff --git a/drivers/staging/fbtft/fb_ssd1306.c b/drivers/staging/fbtft/fb_ssd1306.c
index 50172ddd94ae..d7c5e2e0eee9 100644
--- a/drivers/staging/fbtft/fb_ssd1306.c
+++ b/drivers/staging/fbtft/fb_ssd1306.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -190,7 +190,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
/* Write data */
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
ret = par->fbtftops.write(par, par->txbuf.buf, xres * yres / 8);
if (ret < 0)
dev_err(par->info->device, "write failed and returned: %d\n",
diff --git a/drivers/staging/fbtft/fb_ssd1325.c b/drivers/staging/fbtft/fb_ssd1325.c
index f974f7fc4d79..8a3140d41d8b 100644
--- a/drivers/staging/fbtft/fb_ssd1325.c
+++ b/drivers/staging/fbtft/fb_ssd1325.c
@@ -6,7 +6,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -35,7 +35,7 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- gpio_set_value(par->gpio.cs, 0);
+ gpiod_set_value(par->gpio.cs, 0);
write_reg(par, 0xb3);
write_reg(par, 0xf0);
@@ -155,7 +155,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
}
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
/* Write data */
ret = par->fbtftops.write(par, par->txbuf.buf,
diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c
index 0b614c84822e..9f54fe28d511 100644
--- a/drivers/staging/fbtft/fb_ssd1331.c
+++ b/drivers/staging/fbtft/fb_ssd1331.c
@@ -2,7 +2,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -80,8 +80,8 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
va_start(args, len);
*buf = (u8)va_arg(args, unsigned int);
- if (par->gpio.dc != -1)
- gpio_set_value(par->gpio.dc, 0);
+ if (!par->gpio.dc)
+ gpiod_set_value(par->gpio.dc, 0);
ret = par->fbtftops.write(par, par->buf, sizeof(u8));
if (ret < 0) {
va_end(args);
@@ -103,8 +103,8 @@ static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
return;
}
}
- if (par->gpio.dc != -1)
- gpio_set_value(par->gpio.dc, 1);
+ if (!par->gpio.dc)
+ gpiod_set_value(par->gpio.dc, 1);
va_end(args);
}
diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c
index 3da091b4d297..9ac78ce30619 100644
--- a/drivers/staging/fbtft/fb_ssd1351.c
+++ b/drivers/staging/fbtft/fb_ssd1351.c
@@ -2,7 +2,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -164,7 +164,7 @@ static int set_gamma(struct fbtft_par *par, u32 *curves)
static int blank(struct fbtft_par *par, bool on)
{
fbtft_par_dbg(DEBUG_BLANK, par, "(%s=%s)\n",
- __func__, on ? "true" : "false");
+ __func__, on ? "true" : "false");
if (on)
write_reg(par, 0xAE);
else
diff --git a/drivers/staging/fbtft/fb_tinylcd.c b/drivers/staging/fbtft/fb_tinylcd.c
index e463b0ddf16d..9469248f2c50 100644
--- a/drivers/staging/fbtft/fb_tinylcd.c
+++ b/drivers/staging/fbtft/fb_tinylcd.c
@@ -38,7 +38,7 @@ static int init_display(struct fbtft_par *par)
write_reg(par, 0xE5, 0x00);
write_reg(par, 0xF0, 0x36, 0xA5, 0x53);
write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00,
- 0x00, 0x35, 0x33, 0x00, 0x00, 0x00);
+ 0x00, 0x35, 0x33, 0x00, 0x00, 0x00);
write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
udelay(250);
diff --git a/drivers/staging/fbtft/fb_tls8204.c b/drivers/staging/fbtft/fb_tls8204.c
index 277b6ed9c725..bec6dd0ffb01 100644
--- a/drivers/staging/fbtft/fb_tls8204.c
+++ b/drivers/staging/fbtft/fb_tls8204.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -94,7 +94,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
/* The display is 102x68 but the LCD is 84x48.
* Set the write pointer at the start of each row.
*/
- gpio_set_value(par->gpio.dc, 0);
+ gpiod_set_value(par->gpio.dc, 0);
write_reg(par, 0x80 | 0);
write_reg(par, 0x40 | y);
@@ -109,7 +109,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
*buf++ = ch;
}
/* Write the row */
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
if (ret < 0) {
dev_err(par->info->device,
diff --git a/drivers/staging/fbtft/fb_uc1611.c b/drivers/staging/fbtft/fb_uc1611.c
index dfaf8bc70f73..65681d0fe200 100644
--- a/drivers/staging/fbtft/fb_uc1611.c
+++ b/drivers/staging/fbtft/fb_uc1611.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -251,7 +251,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
}
break;
}
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
/* Write data */
ret = par->fbtftops.write(par, par->txbuf.buf, len / 2);
diff --git a/drivers/staging/fbtft/fb_uc1701.c b/drivers/staging/fbtft/fb_uc1701.c
index 0a3531d6eb39..e4ccc73868a7 100644
--- a/drivers/staging/fbtft/fb_uc1701.c
+++ b/drivers/staging/fbtft/fb_uc1701.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -136,9 +136,9 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
write_reg(par, LCD_PAGE_ADDRESS | (u8)y);
write_reg(par, 0x00);
write_reg(par, LCD_COL_ADDRESS);
- gpio_set_value(par->gpio.dc, 1);
+ gpiod_set_value(par->gpio.dc, 1);
ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
- gpio_set_value(par->gpio.dc, 0);
+ gpiod_set_value(par->gpio.dc, 0);
}
if (ret < 0)
diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c
index acc425fdf34e..564a38e34440 100644
--- a/drivers/staging/fbtft/fb_upd161704.c
+++ b/drivers/staging/fbtft/fb_upd161704.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -26,8 +26,8 @@ static int init_display(struct fbtft_par *par)
{
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
/* Initialization sequence from Lib_UTFT */
diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c
index e77178157f1b..0a5206d28da4 100644
--- a/drivers/staging/fbtft/fb_watterott.c
+++ b/drivers/staging/fbtft/fb_watterott.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include "fbtft.h"
@@ -213,7 +213,7 @@ static int set_var(struct fbtft_par *par)
static int verify_gpios(struct fbtft_par *par)
{
- if (par->gpio.reset < 0) {
+ if (!par->gpio.reset) {
dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n");
return -EINVAL;
}
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index 8ce1ff9b6c2a..2ea814d0dca5 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/export.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include "fbtft.h"
@@ -135,8 +135,8 @@ int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
remain = len / 2;
vmem16 = (u16 *)(par->info->screen_buffer + offset);
- if (par->gpio.dc != -1)
- gpio_set_value(par->gpio.dc, 1);
+ if (!par->gpio.dc)
+ gpiod_set_value(par->gpio.dc, 1);
/* non buffered write */
if (!par->txbuf.buf)
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index a2df02d97a8e..9b07badf4c6c 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -16,7 +16,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fb.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
@@ -24,7 +24,6 @@
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <video/mipi_display.h>
#include "fbtft.h"
@@ -38,8 +37,8 @@ int fbtft_write_buf_dc(struct fbtft_par *par, void *buf, size_t len, int dc)
{
int ret;
- if (gpio_is_valid(par->gpio.dc))
- gpio_set_value(par->gpio.dc, dc);
+ if (par->gpio.dc)
+ gpiod_set_value(par->gpio.dc, dc);
ret = par->fbtftops.write(par, buf, len);
if (ret < 0)
@@ -71,127 +70,26 @@ void fbtft_dbg_hex(const struct device *dev, int groupsize,
}
EXPORT_SYMBOL(fbtft_dbg_hex);
-static unsigned long fbtft_request_gpios_match(struct fbtft_par *par,
- const struct fbtft_gpio *gpio)
-{
- int ret;
- unsigned int val;
-
- fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n",
- __func__, gpio->name);
-
- if (strcasecmp(gpio->name, "reset") == 0) {
- par->gpio.reset = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
- } else if (strcasecmp(gpio->name, "dc") == 0) {
- par->gpio.dc = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
- } else if (strcasecmp(gpio->name, "cs") == 0) {
- par->gpio.cs = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
- } else if (strcasecmp(gpio->name, "wr") == 0) {
- par->gpio.wr = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
- } else if (strcasecmp(gpio->name, "rd") == 0) {
- par->gpio.rd = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
- } else if (strcasecmp(gpio->name, "latch") == 0) {
- par->gpio.latch = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
- } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') {
- ret = kstrtouint(&gpio->name[2], 10, &val);
- if (ret == 0 && val < 16) {
- par->gpio.db[val] = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
- }
- } else if (strcasecmp(gpio->name, "led") == 0) {
- par->gpio.led[0] = gpio->gpio;
- return GPIOF_OUT_INIT_LOW;
- } else if (strcasecmp(gpio->name, "led_") == 0) {
- par->gpio.led[0] = gpio->gpio;
- return GPIOF_OUT_INIT_HIGH;
- }
-
- return FBTFT_GPIO_NO_MATCH;
-}
-
-static int fbtft_request_gpios(struct fbtft_par *par)
-{
- struct fbtft_platform_data *pdata = par->pdata;
- const struct fbtft_gpio *gpio;
- unsigned long flags;
- int ret;
-
- if (!(pdata && pdata->gpios))
- return 0;
-
- gpio = pdata->gpios;
- while (gpio->name[0]) {
- flags = FBTFT_GPIO_NO_MATCH;
- /* if driver provides match function, try it first,
- * if no match use our own
- */
- if (par->fbtftops.request_gpios_match)
- flags = par->fbtftops.request_gpios_match(par, gpio);
- if (flags == FBTFT_GPIO_NO_MATCH)
- flags = fbtft_request_gpios_match(par, gpio);
- if (flags != FBTFT_GPIO_NO_MATCH) {
- ret = devm_gpio_request_one(par->info->device,
- gpio->gpio, flags,
- par->info->device->driver->name);
- if (ret < 0) {
- dev_err(par->info->device,
- "%s: gpio_request_one('%s'=%d) failed with %d\n",
- __func__, gpio->name,
- gpio->gpio, ret);
- return ret;
- }
- fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par,
- "%s: '%s' = GPIO%d\n",
- __func__, gpio->name, gpio->gpio);
- }
- gpio++;
- }
-
- return 0;
-}
-
#ifdef CONFIG_OF
static int fbtft_request_one_gpio(struct fbtft_par *par,
- const char *name, int index, int *gpiop)
+ const char *name, int index,
+ struct gpio_desc **gpiop)
{
struct device *dev = par->info->device;
struct device_node *node = dev->of_node;
- int gpio, flags, ret = 0;
- enum of_gpio_flags of_flags;
+ int ret = 0;
if (of_find_property(node, name, NULL)) {
- gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
- if (gpio == -ENOENT)
- return 0;
- if (gpio == -EPROBE_DEFER)
- return gpio;
- if (gpio < 0) {
- dev_err(dev,
- "failed to get '%s' from DT\n", name);
- return gpio;
- }
-
- /* active low translates to initially low */
- flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
- GPIOF_OUT_INIT_HIGH;
- ret = devm_gpio_request_one(dev, gpio, flags,
- dev->driver->name);
- if (ret) {
+ *gpiop = devm_gpiod_get_index(dev, dev->driver->name, index,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(*gpiop)) {
+ ret = PTR_ERR(*gpiop);
dev_err(dev,
- "gpio_request_one('%s'=%d) failed with %d\n",
- name, gpio, ret);
+ "Failed to request %s GPIO:%d\n", name, ret);
return ret;
}
- if (gpiop)
- *gpiop = gpio;
- fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
- __func__, name, gpio);
+ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO\n",
+ __func__, name);
}
return ret;
@@ -254,9 +152,9 @@ static int fbtft_backlight_update_status(struct backlight_device *bd)
if ((bd->props.power == FB_BLANK_UNBLANK) &&
(bd->props.fb_blank == FB_BLANK_UNBLANK))
- gpio_set_value(par->gpio.led[0], polarity);
+ gpiod_set_value(par->gpio.led[0], polarity);
else
- gpio_set_value(par->gpio.led[0], !polarity);
+ gpiod_set_value(par->gpio.led[0], !polarity);
return 0;
}
@@ -286,7 +184,7 @@ void fbtft_register_backlight(struct fbtft_par *par)
struct backlight_device *bd;
struct backlight_properties bl_props = { 0, };
- if (par->gpio.led[0] == -1) {
+ if (!par->gpio.led[0]) {
fbtft_par_dbg(DEBUG_BACKLIGHT, par,
"%s(): led pin not set, exiting.\n", __func__);
return;
@@ -295,7 +193,7 @@ void fbtft_register_backlight(struct fbtft_par *par)
bl_props.type = BACKLIGHT_RAW;
/* Assume backlight is off, get polarity from current state of pin */
bl_props.power = FB_BLANK_POWERDOWN;
- if (!gpio_get_value(par->gpio.led[0]))
+ if (!gpiod_get_value(par->gpio.led[0]))
par->polarity = true;
bd = backlight_device_register(dev_driver_string(par->info->device),
@@ -333,12 +231,12 @@ static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
static void fbtft_reset(struct fbtft_par *par)
{
- if (par->gpio.reset == -1)
+ if (!par->gpio.reset)
return;
fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
- gpio_set_value_cansleep(par->gpio.reset, 0);
+ gpiod_set_value_cansleep(par->gpio.reset, 0);
usleep_range(20, 40);
- gpio_set_value_cansleep(par->gpio.reset, 1);
+ gpiod_set_value_cansleep(par->gpio.reset, 1);
msleep(120);
}
@@ -538,9 +436,9 @@ static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
return chan << bf->offset;
}
-static int fbtft_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
- unsigned int blue, unsigned int transp,
- struct fb_info *info)
+static int fbtft_fb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
unsigned int val;
int ret = 1;
@@ -663,7 +561,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
int txbuflen = display->txbuflen;
unsigned int bpp = display->bpp;
unsigned int fps = display->fps;
- int vmem_size, i;
+ int vmem_size;
const s16 *init_sequence = display->init_sequence;
char *gamma = display->gamma;
u32 *gamma_curves = NULL;
@@ -841,19 +739,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
par->txbuf.len = txbuflen;
}
- /* Initialize gpios to disabled */
- par->gpio.reset = -1;
- par->gpio.dc = -1;
- par->gpio.rd = -1;
- par->gpio.wr = -1;
- par->gpio.cs = -1;
- par->gpio.latch = -1;
- for (i = 0; i < 16; i++) {
- par->gpio.db[i] = -1;
- par->gpio.led[i] = -1;
- par->gpio.aux[i] = -1;
- }
-
/* default fbtft operations */
par->fbtftops.write = fbtft_write_spi;
par->fbtftops.read = fbtft_read_spi;
@@ -863,7 +748,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
par->fbtftops.reset = fbtft_reset;
par->fbtftops.mkdirty = fbtft_mkdirty;
par->fbtftops.update_display = fbtft_update_display;
- par->fbtftops.request_gpios = fbtft_request_gpios;
if (display->backlight)
par->fbtftops.register_backlight = fbtft_register_backlight;
@@ -1035,8 +919,8 @@ static int fbtft_init_display_dt(struct fbtft_par *par)
return -EINVAL;
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
while (p) {
if (val & FBTFT_OF_INIT_CMD) {
@@ -1126,8 +1010,8 @@ int fbtft_init_display(struct fbtft_par *par)
}
par->fbtftops.reset(par);
- if (par->gpio.cs != -1)
- gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+ if (!par->gpio.cs)
+ gpiod_set_value(par->gpio.cs, 0); /* Activate chip */
i = 0;
while (i < FBTFT_MAX_INIT_SEQUENCE) {
@@ -1227,7 +1111,7 @@ static int fbtft_verify_gpios(struct fbtft_par *par)
fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
if (pdata->display.buswidth != 9 && par->startbyte == 0 &&
- par->gpio.dc < 0) {
+ !par->gpio.dc) {
dev_err(par->info->device,
"Missing info about 'dc' gpio. Aborting.\n");
return -EINVAL;
@@ -1236,12 +1120,12 @@ static int fbtft_verify_gpios(struct fbtft_par *par)
if (!par->pdev)
return 0;
- if (par->gpio.wr < 0) {
+ if (!par->gpio.wr) {
dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n");
return -EINVAL;
}
for (i = 0; i < pdata->display.buswidth; i++) {
- if (par->gpio.db[i] < 0) {
+ if (!par->gpio.db[i]) {
dev_err(par->info->device,
"Missing 'db%02d' gpio. Aborting.\n", i);
return -EINVAL;
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
index b5051d3d46a6..38cdad6203ea 100644
--- a/drivers/staging/fbtft/fbtft-io.c
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/export.h>
#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include "fbtft.h"
@@ -142,30 +142,30 @@ int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
data = *(u8 *)buf;
/* Start writing by pulling down /WR */
- gpio_set_value(par->gpio.wr, 0);
+ gpiod_set_value(par->gpio.wr, 0);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
- gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ gpiod_set_value(par->gpio.wr, 0); /* used as delay */
} else {
for (i = 0; i < 8; i++) {
if ((data & 1) != (prev_data & 1))
- gpio_set_value(par->gpio.db[i],
- data & 1);
+ gpiod_set_value(par->gpio.db[i],
+ data & 1);
data >>= 1;
prev_data >>= 1;
}
}
#else
for (i = 0; i < 8; i++) {
- gpio_set_value(par->gpio.db[i], data & 1);
+ gpiod_set_value(par->gpio.db[i], data & 1);
data >>= 1;
}
#endif
/* Pullup /WR */
- gpio_set_value(par->gpio.wr, 1);
+ gpiod_set_value(par->gpio.wr, 1);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u8 *)buf;
@@ -192,30 +192,30 @@ int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
data = *(u16 *)buf;
/* Start writing by pulling down /WR */
- gpio_set_value(par->gpio.wr, 0);
+ gpiod_set_value(par->gpio.wr, 0);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
- gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ gpiod_set_value(par->gpio.wr, 0); /* used as delay */
} else {
for (i = 0; i < 16; i++) {
if ((data & 1) != (prev_data & 1))
- gpio_set_value(par->gpio.db[i],
- data & 1);
+ gpiod_set_value(par->gpio.db[i],
+ data & 1);
data >>= 1;
prev_data >>= 1;
}
}
#else
for (i = 0; i < 16; i++) {
- gpio_set_value(par->gpio.db[i], data & 1);
+ gpiod_set_value(par->gpio.db[i], data & 1);
data >>= 1;
}
#endif
/* Pullup /WR */
- gpio_set_value(par->gpio.wr, 1);
+ gpiod_set_value(par->gpio.wr, 1);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u16 *)buf;
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
index ac427baa464a..7fdd3b0851ef 100644
--- a/drivers/staging/fbtft/fbtft.h
+++ b/drivers/staging/fbtft/fbtft.h
@@ -27,7 +27,7 @@
*/
struct fbtft_gpio {
char name[FBTFT_GPIO_NAME_SIZE];
- unsigned int gpio;
+ struct gpio_desc *gpio;
};
struct fbtft_par;
@@ -134,7 +134,6 @@ struct fbtft_display {
*/
struct fbtft_platform_data {
struct fbtft_display display;
- const struct fbtft_gpio *gpios;
unsigned int rotate;
bool bgr;
unsigned int fps;
@@ -207,15 +206,15 @@ struct fbtft_par {
unsigned int dirty_lines_start;
unsigned int dirty_lines_end;
struct {
- int reset;
- int dc;
- int rd;
- int wr;
- int latch;
- int cs;
- int db[16];
- int led[16];
- int aux[16];
+ struct gpio_desc *reset;
+ struct gpio_desc *dc;
+ struct gpio_desc *rd;
+ struct gpio_desc *wr;
+ struct gpio_desc *latch;
+ struct gpio_desc *cs;
+ struct gpio_desc *db[16];
+ struct gpio_desc *led[16];
+ struct gpio_desc *aux[16];
} gpio;
const s16 *init_sequence;
struct {
diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c
index 046f9d355ecb..5f6cd0816d58 100644
--- a/drivers/staging/fbtft/fbtft_device.c
+++ b/drivers/staging/fbtft/fbtft_device.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <video/mipi_display.h>
@@ -45,11 +45,6 @@ static int mode = -1;
module_param(mode, int, 0000);
MODULE_PARM_DESC(mode, "SPI mode (override device default)");
-static char *gpios;
-module_param(gpios, charp, 0000);
-MODULE_PARM_DESC(gpios,
- "List of gpios. Comma separated with the form: reset:23,dc:24 (when overriding the default, all gpios must be specified)");
-
static unsigned int fps;
module_param(fps, uint, 0000);
MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
@@ -101,7 +96,7 @@ MODULE_PARM_DESC(debug,
static unsigned int verbose = 3;
module_param(verbose, uint, 0000);
MODULE_PARM_DESC(verbose,
- "0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)");
+ "0 silent, >1 show devices, >2 show devices before (default=3)");
struct fbtft_device_display {
char *name;
@@ -279,12 +274,6 @@ static struct fbtft_device_display displays[] = {
.buswidth = 8,
.backlight = 1,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
.gamma = ADAFRUIT18_GAMMA,
}
}
@@ -302,12 +291,6 @@ static struct fbtft_device_display displays[] = {
adafruit18_green_tab_set_addr_win,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
.gamma = ADAFRUIT18_GAMMA,
}
}
@@ -323,11 +306,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "led", 23 },
- {},
- },
}
}
}, {
@@ -342,12 +320,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -362,12 +334,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -380,11 +346,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -399,12 +360,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
.init_sequence = cberry28_init_sequence,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 22 },
- { "led", 18 },
- {},
- },
.gamma = CBERRY28_GAMMA,
}
}
@@ -420,9 +375,6 @@ static struct fbtft_device_display displays[] = {
.buswidth = 8,
.backlight = FBTFT_ONBOARD_BACKLIGHT,
},
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
}
}
@@ -437,11 +389,6 @@ static struct fbtft_device_display displays[] = {
.buswidth = 8,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 13 },
- { "dc", 6 },
- {},
- },
}
}
}, {
@@ -458,11 +405,6 @@ static struct fbtft_device_display displays[] = {
.height = 272,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -479,11 +421,6 @@ static struct fbtft_device_display displays[] = {
.height = 480,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -496,10 +433,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -512,9 +445,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 9,
},
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
}
}
}, {
@@ -523,13 +453,6 @@ static struct fbtft_device_display displays[] = {
.modalias = "flexfb",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
- .platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
- }
}
}, {
.name = "flexpfb",
@@ -538,24 +461,6 @@ static struct fbtft_device_display displays[] = {
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
- .platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 17 },
- { "dc", 1 },
- { "wr", 0 },
- { "cs", 21 },
- { "db00", 9 },
- { "db01", 11 },
- { "db02", 18 },
- { "db03", 23 },
- { "db04", 24 },
- { "db05", 25 },
- { "db06", 8 },
- { "db07", 7 },
- { "led", 4 },
- {},
- },
- },
}
}
}, {
@@ -570,11 +475,6 @@ static struct fbtft_device_display displays[] = {
.backlight = FBTFT_ONBOARD_BACKLIGHT,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 24 },
- { "dc", 25 },
- {},
- },
}
}
}, {
@@ -588,12 +488,6 @@ static struct fbtft_device_display displays[] = {
.buswidth = 8,
.backlight = 1,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 23 },
- {},
- },
}
}
}, {
@@ -609,11 +503,6 @@ static struct fbtft_device_display displays[] = {
},
.startbyte = 0x70,
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -631,11 +520,6 @@ static struct fbtft_device_display displays[] = {
.startbyte = 0x70,
.bgr = true,
.fps = 50,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "led", 18 },
- {},
- },
.gamma = HY28B_GAMMA,
}
}
@@ -652,12 +536,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 22 },
- {},
- },
}
}
}, {
@@ -673,22 +551,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = false,
- .gpios = (const struct fbtft_gpio []) {
- /* Wiring for LCD adapter kit */
- { "reset", 7 },
- { "dc", 0 }, /* rev 2: 2 */
- { "wr", 1 }, /* rev 2: 3 */
- { "cs", 8 },
- { "db00", 17 },
- { "db01", 18 },
- { "db02", 21 }, /* rev 2: 27 */
- { "db03", 22 },
- { "db04", 23 },
- { "db05", 24 },
- { "db06", 25 },
- { "db07", 4 },
- {}
- },
},
}
}
@@ -705,9 +567,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
}
}
@@ -723,11 +582,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -743,12 +597,6 @@ static struct fbtft_device_display displays[] = {
},
.startbyte = 0x70,
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -763,11 +611,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -777,10 +620,6 @@ static struct fbtft_device_display displays[] = {
.max_speed_hz = 4000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- {},
- },
}
}
}, {
@@ -793,12 +632,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 23 },
- {},
- },
}
}
}, {
@@ -811,12 +644,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 23 },
- {},
- },
}
}
}, {
@@ -831,9 +658,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
}
}
}, {
@@ -849,12 +673,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 22 },
- {},
- },
}
}
}, {
@@ -871,10 +689,6 @@ static struct fbtft_device_display displays[] = {
.init_sequence = pitft_init_sequence,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "dc", 25 },
- {},
- },
}
}
}, {
@@ -888,11 +702,6 @@ static struct fbtft_device_display displays[] = {
.buswidth = 8,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 24 },
- { "dc", 25 },
- {},
- },
.gamma = PIOLED_GAMMA
}
}
@@ -908,12 +717,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 23 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -928,12 +731,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 23 },
- {},
- },
}
}
}, {
@@ -946,11 +743,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -968,9 +760,6 @@ static struct fbtft_device_display displays[] = {
.fbtftops.write = write_gpio16_wr_slow,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
},
}
@@ -988,9 +777,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
},
}
@@ -1010,9 +796,6 @@ static struct fbtft_device_display displays[] = {
fbtft_write_gpio16_wr_latched,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
},
}
@@ -1028,11 +811,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- {},
- },
}
}
}, {
@@ -1044,9 +822,6 @@ static struct fbtft_device_display displays[] = {
.chip_select = 0,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
}
}
}, {
@@ -1059,11 +834,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 24 },
- { "dc", 25 },
- {},
- },
}
}
}, {
@@ -1078,12 +848,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -1098,12 +862,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 25 },
- { "dc", 24 },
- { "led", 18 },
- {},
- },
}
}
}, {
@@ -1118,12 +876,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 15 },
- { "dc", 25 },
- { "led_", 18 },
- {},
- },
}
}
}, {
@@ -1138,12 +890,6 @@ static struct fbtft_device_display displays[] = {
.backlight = 1,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 15 },
- { "dc", 25 },
- { "led_", 18 },
- {},
- },
}
}
}, {
@@ -1156,11 +902,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 24 },
- { "dc", 25 },
- {},
- },
}
}
}, {
@@ -1177,11 +918,6 @@ static struct fbtft_device_display displays[] = {
waveshare32b_init_sequence,
},
.bgr = true,
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 27 },
- { "dc", 22 },
- {},
- },
}
}
}, {
@@ -1194,11 +930,6 @@ static struct fbtft_device_display displays[] = {
.display = {
.buswidth = 8,
},
- .gpios = (const struct fbtft_gpio []) {
- { "reset", 24 },
- { "dc", 25 },
- {},
- },
}
}
}, {
@@ -1211,9 +942,6 @@ static struct fbtft_device_display displays[] = {
.max_speed_hz = 0,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
}
},
.pdev = &(struct platform_device) {
@@ -1222,9 +950,6 @@ static struct fbtft_device_display displays[] = {
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
- .gpios = (const struct fbtft_gpio []) {
- {},
- },
},
},
},
@@ -1246,30 +971,30 @@ static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
data = *(u16 *)buf;
/* Start writing by pulling down /WR */
- gpio_set_value(par->gpio.wr, 0);
+ gpiod_set_value(par->gpio.wr, 0);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
- gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ gpiod_set_value(par->gpio.wr, 0); /* used as delay */
} else {
for (i = 0; i < 16; i++) {
if ((data & 1) != (prev_data & 1))
- gpio_set_value(par->gpio.db[i],
- data & 1);
+ gpiod_set_value(par->gpio.db[i],
+ data & 1);
data >>= 1;
prev_data >>= 1;
}
}
#else
for (i = 0; i < 16; i++) {
- gpio_set_value(par->gpio.db[i], data & 1);
+ gpiod_set_value(par->gpio.db[i], data & 1);
data >>= 1;
}
#endif
/* Pullup /WR */
- gpio_set_value(par->gpio.wr, 1);
+ gpiod_set_value(par->gpio.wr, 1);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u16 *)buf;
@@ -1289,9 +1014,6 @@ static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
write_reg(par, 0x2C);
}
-/* used if gpios parameter is present */
-static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS + 1] = { };
-
static void fbtft_device_pdev_release(struct device *dev)
{
/* Needed to silence this message:
@@ -1382,11 +1104,8 @@ static int __init fbtft_device_init(void)
{
struct spi_board_info *spi = NULL;
struct fbtft_platform_data *pdata;
- const struct fbtft_gpio *gpio = NULL;
- char *p_gpio, *p_name, *p_num;
bool found = false;
int i = 0;
- long val;
int ret = 0;
if (!name) {
@@ -1404,38 +1123,6 @@ static int __init fbtft_device_init(void)
return -EINVAL;
}
- /* parse module parameter: gpios */
- while ((p_gpio = strsep(&gpios, ","))) {
- if (!strchr(p_gpio, ':')) {
- pr_err("error: missing ':' in gpios parameter: %s\n",
- p_gpio);
- return -EINVAL;
- }
- p_num = p_gpio;
- p_name = strsep(&p_num, ":");
- if (!p_name || !p_num) {
- pr_err("something bad happened parsing gpios parameter: %s\n",
- p_gpio);
- return -EINVAL;
- }
- ret = kstrtol(p_num, 10, &val);
- if (ret) {
- pr_err("could not parse number in gpios parameter: %s:%s\n",
- p_name, p_num);
- return -EINVAL;
- }
- strncpy(fbtft_device_param_gpios[i].name, p_name,
- FBTFT_GPIO_NAME_SIZE - 1);
- fbtft_device_param_gpios[i++].gpio = (int)val;
- if (i == MAX_GPIOS) {
- pr_err("gpios parameter: exceeded max array size: %d\n",
- MAX_GPIOS);
- return -EINVAL;
- }
- }
- if (fbtft_device_param_gpios[0].name[0])
- gpio = fbtft_device_param_gpios;
-
if (verbose > 2) {
pr_spi_devices(); /* print list of registered SPI devices */
pr_p_devices(); /* print list of 'fb' platform devices */
@@ -1516,8 +1203,6 @@ static int __init fbtft_device_init(void)
pdata->txbuflen = txbuflen;
if (init_num)
pdata->display.init_sequence = init;
- if (gpio)
- pdata->gpios = gpio;
if (custom) {
pdata->display.width = width;
pdata->display.height = height;
@@ -1549,19 +1234,6 @@ static int __init fbtft_device_init(void)
return -EINVAL;
}
- if (verbose && pdata && pdata->gpios) {
- gpio = pdata->gpios;
- pr_info("GPIOS used by '%s':\n", name);
- found = false;
- while (verbose && gpio->name[0]) {
- pr_info("'%s' = GPIO%d\n", gpio->name, gpio->gpio);
- gpio++;
- found = true;
- }
- if (!found)
- pr_info("(none)\n");
- }
-
if (spi_device && (verbose > 1))
pr_spi_devices();
if (p_device && (verbose > 1))
diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c
index 2af474469e7d..c5fa59105a43 100644
--- a/drivers/staging/fbtft/flexfb.c
+++ b/drivers/staging/fbtft/flexfb.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -521,7 +521,7 @@ static int flexfb_verify_gpios_dc(struct fbtft_par *par)
{
fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
- if (par->gpio.dc < 0) {
+ if (!par->gpio.dc) {
dev_err(par->info->device,
"Missing info about 'dc' gpio. Aborting.\n");
return -EINVAL;
@@ -537,22 +537,22 @@ static int flexfb_verify_gpios_db(struct fbtft_par *par)
fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
- if (par->gpio.dc < 0) {
+ if (!par->gpio.dc) {
dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
return -EINVAL;
}
- if (par->gpio.wr < 0) {
+ if (!par->gpio.wr) {
dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n");
return -EINVAL;
}
- if (latched && (par->gpio.latch < 0)) {
+ if (latched && !par->gpio.latch) {
dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n");
return -EINVAL;
}
if (latched)
num_db = buswidth / 2;
for (i = 0; i < num_db; i++) {
- if (par->gpio.db[i] < 0) {
+ if (!par->gpio.db[i]) {
dev_err(par->info->device,
"Missing info about 'db%02d' gpio. Aborting.\n",
i);
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index da744f2b0ee6..14b974defa3a 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2014-2016 Freescale Semiconductor Inc.
* Copyright 2017-2018 NXP
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index db43fa3782b8..25635259ce44 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2014-2016 Freescale Semiconductor Inc.
* Copyright 2017-2018 NXP
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index 069c99bfba74..c48783680a05 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* DPAA2 Ethernet Switch declarations
*
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index 3e416f5bbcba..a1b90ea7fcb8 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -1213,6 +1213,7 @@ static int get_serial_info(struct tty_struct *tty,
struct serial_struct *ss)
{
struct fwtty_port *port = tty->driver_data;
+
mutex_lock(&port->port.mutex);
ss->type = PORT_UNKNOWN;
ss->line = port->port.tty->index;
diff --git a/drivers/staging/gasket/gasket_interrupt.c b/drivers/staging/gasket/gasket_interrupt.c
index ad5657d213f0..ff61b782df30 100644
--- a/drivers/staging/gasket/gasket_interrupt.c
+++ b/drivers/staging/gasket/gasket_interrupt.c
@@ -9,7 +9,6 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/printk.h>
-#include <linux/version.h>
#ifdef GASKET_KERNEL_TRACE_SUPPORT
#define CREATE_TRACE_POINTS
#include <trace/events/gasket_interrupt.h>
diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c
index d4520490cf6d..24a738238f9f 100644
--- a/drivers/staging/goldfish/goldfish_audio.c
+++ b/drivers/staging/goldfish/goldfish_audio.c
@@ -4,16 +4,6 @@
*
* Copyright (C) 2007 Google, Inc.
* Copyright (C) 2012 Intel, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/module.h>
diff --git a/drivers/staging/greybus/Kconfig b/drivers/staging/greybus/Kconfig
index ab096bcef98c..b571e4e8060b 100644
--- a/drivers/staging/greybus/Kconfig
+++ b/drivers/staging/greybus/Kconfig
@@ -148,6 +148,7 @@ if GREYBUS_BRIDGED_PHY
config GREYBUS_GPIO
tristate "Greybus GPIO Bridged PHY driver"
depends on GPIOLIB
+ select GPIOLIB_IRQCHIP
---help---
Select this option if you have a device that follows the
Greybus GPIO Bridged PHY Class specification.
diff --git a/drivers/staging/greybus/TODO b/drivers/staging/greybus/TODO
index 3b90a5711998..31f1f2cb401c 100644
--- a/drivers/staging/greybus/TODO
+++ b/drivers/staging/greybus/TODO
@@ -1,5 +1,3 @@
* Convert all uses of the old GPIO API from <linux/gpio.h> to the
GPIO descriptor API in <linux/gpio/consumer.h> and look up GPIO
lines from device tree or ACPI.
-* Convert the GPIO driver to use the GPIO irqchip library
- GPIOLIB_IRQCHIP instead of reimplementing the same.
diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c
index be5ffed90bcf..bbf3ba744fc4 100644
--- a/drivers/staging/greybus/arche-apb-ctrl.c
+++ b/drivers/staging/greybus/arche-apb-ctrl.c
@@ -8,9 +8,8 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
@@ -24,12 +23,12 @@ static void apb_bootret_deassert(struct device *dev);
struct arche_apb_ctrl_drvdata {
/* Control GPIO signals to and from AP <=> AP Bridges */
- int resetn_gpio;
- int boot_ret_gpio;
- int pwroff_gpio;
- int wake_in_gpio;
- int wake_out_gpio;
- int pwrdn_gpio;
+ struct gpio_desc *resetn;
+ struct gpio_desc *boot_ret;
+ struct gpio_desc *pwroff;
+ struct gpio_desc *wake_in;
+ struct gpio_desc *wake_out;
+ struct gpio_desc *pwrdn;
enum arche_platform_state state;
bool init_disabled;
@@ -37,28 +36,28 @@ struct arche_apb_ctrl_drvdata {
struct regulator *vcore;
struct regulator *vio;
- int clk_en_gpio;
+ struct gpio_desc *clk_en;
struct clk *clk;
struct pinctrl *pinctrl;
struct pinctrl_state *pin_default;
/* V2: SPI Bus control */
- int spi_en_gpio;
+ struct gpio_desc *spi_en;
bool spi_en_polarity_high;
};
/*
* Note that these low level api's are active high
*/
-static inline void deassert_reset(unsigned int gpio)
+static inline void deassert_reset(struct gpio_desc *gpio)
{
- gpio_set_value(gpio, 1);
+ gpiod_set_raw_value(gpio, 1);
}
-static inline void assert_reset(unsigned int gpio)
+static inline void assert_reset(struct gpio_desc *gpio)
{
- gpio_set_value(gpio, 0);
+ gpiod_set_raw_value(gpio, 0);
}
/*
@@ -75,11 +74,10 @@ static int coldboot_seq(struct platform_device *pdev)
return 0;
/* Hold APB in reset state */
- assert_reset(apb->resetn_gpio);
+ assert_reset(apb->resetn);
- if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
- gpio_is_valid(apb->spi_en_gpio))
- devm_gpio_free(dev, apb->spi_en_gpio);
+ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en)
+ devm_gpiod_put(dev, apb->spi_en);
/* Enable power to APB */
if (!IS_ERR(apb->vcore)) {
@@ -101,13 +99,13 @@ static int coldboot_seq(struct platform_device *pdev)
apb_bootret_deassert(dev);
/* On DB3 clock was not mandatory */
- if (gpio_is_valid(apb->clk_en_gpio))
- gpio_set_value(apb->clk_en_gpio, 1);
+ if (apb->clk_en)
+ gpiod_set_value(apb->clk_en, 1);
usleep_range(100, 200);
/* deassert reset to APB : Active-low signal */
- deassert_reset(apb->resetn_gpio);
+ deassert_reset(apb->resetn);
apb->state = ARCHE_PLATFORM_STATE_ACTIVE;
@@ -136,25 +134,25 @@ static int fw_flashing_seq(struct platform_device *pdev)
return ret;
}
- if (gpio_is_valid(apb->spi_en_gpio)) {
+ if (apb->spi_en) {
unsigned long flags;
if (apb->spi_en_polarity_high)
- flags = GPIOF_OUT_INIT_HIGH;
+ flags = GPIOD_OUT_HIGH;
else
- flags = GPIOF_OUT_INIT_LOW;
+ flags = GPIOD_OUT_LOW;
- ret = devm_gpio_request_one(dev, apb->spi_en_gpio,
- flags, "apb_spi_en");
- if (ret) {
- dev_err(dev, "Failed requesting SPI bus en gpio %d\n",
- apb->spi_en_gpio);
+ apb->spi_en = devm_gpiod_get(dev, "spi-en", flags);
+ if (IS_ERR(apb->spi_en)) {
+ ret = PTR_ERR(apb->spi_en);
+ dev_err(dev, "Failed requesting SPI bus en GPIO: %d\n",
+ ret);
return ret;
}
}
/* for flashing device should be in reset state */
- assert_reset(apb->resetn_gpio);
+ assert_reset(apb->resetn);
apb->state = ARCHE_PLATFORM_STATE_FW_FLASHING;
return 0;
@@ -176,9 +174,8 @@ static int standby_boot_seq(struct platform_device *pdev)
apb->state == ARCHE_PLATFORM_STATE_OFF)
return 0;
- if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
- gpio_is_valid(apb->spi_en_gpio))
- devm_gpio_free(dev, apb->spi_en_gpio);
+ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en)
+ devm_gpiod_put(dev, apb->spi_en);
/*
* As per WDM spec, do nothing
@@ -201,13 +198,12 @@ static void poweroff_seq(struct platform_device *pdev)
if (apb->init_disabled || apb->state == ARCHE_PLATFORM_STATE_OFF)
return;
- if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING &&
- gpio_is_valid(apb->spi_en_gpio))
- devm_gpio_free(dev, apb->spi_en_gpio);
+ if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING && apb->spi_en)
+ devm_gpiod_put(dev, apb->spi_en);
/* disable the clock */
- if (gpio_is_valid(apb->clk_en_gpio))
- gpio_set_value(apb->clk_en_gpio, 0);
+ if (apb->clk_en)
+ gpiod_set_value(apb->clk_en, 0);
if (!IS_ERR(apb->vcore) && regulator_is_enabled(apb->vcore) > 0)
regulator_disable(apb->vcore);
@@ -216,7 +212,7 @@ static void poweroff_seq(struct platform_device *pdev)
regulator_disable(apb->vio);
/* As part of exit, put APB back in reset state */
- assert_reset(apb->resetn_gpio);
+ assert_reset(apb->resetn);
apb->state = ARCHE_PLATFORM_STATE_OFF;
/* TODO: May have to send an event to SVC about this exit */
@@ -226,7 +222,7 @@ static void apb_bootret_deassert(struct device *dev)
{
struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev);
- gpio_set_value(apb->boot_ret_gpio, 0);
+ gpiod_set_value(apb->boot_ret, 0);
}
int apb_ctrl_coldboot(struct device *dev)
@@ -322,66 +318,44 @@ static int apb_ctrl_get_devtree_data(struct platform_device *pdev,
struct arche_apb_ctrl_drvdata *apb)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
int ret;
- apb->resetn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
- if (apb->resetn_gpio < 0) {
- dev_err(dev, "failed to get reset gpio\n");
- return apb->resetn_gpio;
- }
- ret = devm_gpio_request_one(dev, apb->resetn_gpio,
- GPIOF_OUT_INIT_LOW, "apb-reset");
- if (ret) {
- dev_err(dev, "Failed requesting reset gpio %d\n",
- apb->resetn_gpio);
+ apb->resetn = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(apb->resetn)) {
+ ret = PTR_ERR(apb->resetn);
+ dev_err(dev, "Failed requesting reset GPIO: %d\n", ret);
return ret;
}
- apb->boot_ret_gpio = of_get_named_gpio(np, "boot-ret-gpios", 0);
- if (apb->boot_ret_gpio < 0) {
- dev_err(dev, "failed to get boot retention gpio\n");
- return apb->boot_ret_gpio;
- }
- ret = devm_gpio_request_one(dev, apb->boot_ret_gpio,
- GPIOF_OUT_INIT_LOW, "boot retention");
- if (ret) {
- dev_err(dev, "Failed requesting bootret gpio %d\n",
- apb->boot_ret_gpio);
+ apb->boot_ret = devm_gpiod_get(dev, "boot-ret", GPIOD_OUT_LOW);
+ if (IS_ERR(apb->boot_ret)) {
+ ret = PTR_ERR(apb->boot_ret);
+ dev_err(dev, "Failed requesting bootret GPIO: %d\n", ret);
return ret;
}
/* It's not mandatory to support power management interface */
- apb->pwroff_gpio = of_get_named_gpio(np, "pwr-off-gpios", 0);
- if (apb->pwroff_gpio < 0) {
- dev_err(dev, "failed to get power off gpio\n");
- return apb->pwroff_gpio;
- }
- ret = devm_gpio_request_one(dev, apb->pwroff_gpio,
- GPIOF_IN, "pwroff_n");
- if (ret) {
- dev_err(dev, "Failed requesting pwroff_n gpio %d\n",
- apb->pwroff_gpio);
+ apb->pwroff = devm_gpiod_get_optional(dev, "pwr-off", GPIOD_IN);
+ if (IS_ERR(apb->pwroff)) {
+ ret = PTR_ERR(apb->pwroff);
+ dev_err(dev, "Failed requesting pwroff_n GPIO: %d\n", ret);
return ret;
}
/* Do not make clock mandatory as of now (for DB3) */
- apb->clk_en_gpio = of_get_named_gpio(np, "clock-en-gpio", 0);
- if (apb->clk_en_gpio < 0) {
- dev_warn(dev, "failed to get clock en gpio\n");
- } else if (gpio_is_valid(apb->clk_en_gpio)) {
- ret = devm_gpio_request_one(dev, apb->clk_en_gpio,
- GPIOF_OUT_INIT_LOW, "apb_clk_en");
- if (ret) {
- dev_warn(dev, "Failed requesting APB clock en gpio %d\n",
- apb->clk_en_gpio);
- return ret;
- }
+ apb->clk_en = devm_gpiod_get_optional(dev, "clock-en", GPIOD_OUT_LOW);
+ if (IS_ERR(apb->clk_en)) {
+ ret = PTR_ERR(apb->clk_en);
+ dev_err(dev, "Failed requesting APB clock en GPIO: %d\n", ret);
+ return ret;
}
- apb->pwrdn_gpio = of_get_named_gpio(np, "pwr-down-gpios", 0);
- if (apb->pwrdn_gpio < 0)
- dev_warn(dev, "failed to get power down gpio\n");
+ apb->pwrdn = devm_gpiod_get(dev, "pwr-down", GPIOD_OUT_LOW);
+ if (IS_ERR(apb->pwrdn)) {
+ ret = PTR_ERR(apb->pwrdn);
+ dev_warn(dev, "Failed requesting power down GPIO: %d\n", ret);
+ return ret;
+ }
/* Regulators are optional, as we may have fixed supply coming in */
apb->vcore = devm_regulator_get(dev, "vcore");
@@ -404,12 +378,8 @@ static int apb_ctrl_get_devtree_data(struct platform_device *pdev,
}
/* Only applicable for platform >= V2 */
- apb->spi_en_gpio = of_get_named_gpio(np, "spi-en-gpio", 0);
- if (apb->spi_en_gpio >= 0) {
- if (of_property_read_bool(pdev->dev.of_node,
- "spi-en-active-high"))
- apb->spi_en_polarity_high = true;
- }
+ if (of_property_read_bool(pdev->dev.of_node, "gb,spi-en-active-high"))
+ apb->spi_en_polarity_high = true;
return 0;
}
diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c
index 4c36e88766e7..6eb842040c22 100644
--- a/drivers/staging/greybus/arche-platform.c
+++ b/drivers/staging/greybus/arche-platform.c
@@ -8,10 +8,9 @@
#include <linux/clk.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -45,14 +44,14 @@ enum svc_wakedetect_state {
struct arche_platform_drvdata {
/* Control GPIO signals to and from AP <=> SVC */
- int svc_reset_gpio;
+ struct gpio_desc *svc_reset;
bool is_reset_act_hi;
- int svc_sysboot_gpio;
- int wake_detect_gpio; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */
+ struct gpio_desc *svc_sysboot;
+ struct gpio_desc *wake_detect; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */
enum arche_platform_state state;
- int svc_refclk_req;
+ struct gpio_desc *svc_refclk_req;
struct clk *svc_ref_clk;
struct pinctrl *pinctrl;
@@ -85,9 +84,9 @@ static void arche_platform_set_wake_detect_state(
arche_pdata->wake_detect_state = state;
}
-static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
+static inline void svc_reset_onoff(struct gpio_desc *gpio, bool onoff)
{
- gpio_set_value(gpio, onoff);
+ gpiod_set_raw_value(gpio, onoff);
}
static int apb_cold_boot(struct device *dev, void *data)
@@ -116,7 +115,6 @@ static int apb_poweroff(struct device *dev, void *data)
static void arche_platform_wd_irq_en(struct arche_platform_drvdata *arche_pdata)
{
/* Enable interrupt here, to read event back from SVC */
- gpio_direction_input(arche_pdata->wake_detect_gpio);
enable_irq(arche_pdata->wake_detect_irq);
}
@@ -160,7 +158,7 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid)
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
- if (gpio_get_value(arche_pdata->wake_detect_gpio)) {
+ if (gpiod_get_value(arche_pdata->wake_detect)) {
/* wake/detect rising */
/*
@@ -224,10 +222,9 @@ arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
dev_info(arche_pdata->dev, "Booting from cold boot state\n");
- svc_reset_onoff(arche_pdata->svc_reset_gpio,
- arche_pdata->is_reset_act_hi);
+ svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
- gpio_set_value(arche_pdata->svc_sysboot_gpio, 0);
+ gpiod_set_value(arche_pdata->svc_sysboot, 0);
usleep_range(100, 200);
ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
@@ -238,8 +235,7 @@ arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
}
/* bring SVC out of reset */
- svc_reset_onoff(arche_pdata->svc_reset_gpio,
- !arche_pdata->is_reset_act_hi);
+ svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_ACTIVE);
@@ -259,10 +255,9 @@ arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
dev_info(arche_pdata->dev, "Switching to FW flashing state\n");
- svc_reset_onoff(arche_pdata->svc_reset_gpio,
- arche_pdata->is_reset_act_hi);
+ svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
- gpio_set_value(arche_pdata->svc_sysboot_gpio, 1);
+ gpiod_set_value(arche_pdata->svc_sysboot, 1);
usleep_range(100, 200);
@@ -273,8 +268,7 @@ arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
return ret;
}
- svc_reset_onoff(arche_pdata->svc_reset_gpio,
- !arche_pdata->is_reset_act_hi);
+ svc_reset_onoff(arche_pdata->svc_reset, !arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_FW_FLASHING);
@@ -305,8 +299,7 @@ arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata)
clk_disable_unprepare(arche_pdata->svc_ref_clk);
/* As part of exit, put APB back in reset state */
- svc_reset_onoff(arche_pdata->svc_reset_gpio,
- arche_pdata->is_reset_act_hi);
+ svc_reset_onoff(arche_pdata->svc_reset, arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
}
@@ -435,6 +428,7 @@ static int arche_platform_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
+ unsigned int flags;
arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata),
GFP_KERNEL);
@@ -444,61 +438,33 @@ static int arche_platform_probe(struct platform_device *pdev)
/* setup svc reset gpio */
arche_pdata->is_reset_act_hi = of_property_read_bool(np,
"svc,reset-active-high");
- arche_pdata->svc_reset_gpio = of_get_named_gpio(np,
- "svc,reset-gpio",
- 0);
- if (!gpio_is_valid(arche_pdata->svc_reset_gpio)) {
- dev_err(dev, "failed to get reset-gpio\n");
- return arche_pdata->svc_reset_gpio;
- }
- ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset");
- if (ret) {
- dev_err(dev, "failed to request svc-reset gpio:%d\n", ret);
- return ret;
- }
- ret = gpio_direction_output(arche_pdata->svc_reset_gpio,
- arche_pdata->is_reset_act_hi);
- if (ret) {
- dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
+ if (arche_pdata->is_reset_act_hi)
+ flags = GPIOD_OUT_HIGH;
+ else
+ flags = GPIOD_OUT_LOW;
+
+ arche_pdata->svc_reset = devm_gpiod_get(dev, "svc,reset", flags);
+ if (IS_ERR(arche_pdata->svc_reset)) {
+ ret = PTR_ERR(arche_pdata->svc_reset);
+ dev_err(dev, "failed to request svc-reset GPIO: %d\n", ret);
return ret;
}
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
- arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np,
- "svc,sysboot-gpio",
- 0);
- if (!gpio_is_valid(arche_pdata->svc_sysboot_gpio)) {
- dev_err(dev, "failed to get sysboot gpio\n");
- return arche_pdata->svc_sysboot_gpio;
- }
- ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0");
- if (ret) {
- dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret);
- return ret;
- }
- ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0);
- if (ret) {
- dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
+ arche_pdata->svc_sysboot = devm_gpiod_get(dev, "svc,sysboot",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(arche_pdata->svc_sysboot)) {
+ ret = PTR_ERR(arche_pdata->svc_sysboot);
+ dev_err(dev, "failed to request sysboot0 GPIO: %d\n", ret);
return ret;
}
/* setup the clock request gpio first */
- arche_pdata->svc_refclk_req = of_get_named_gpio(np,
- "svc,refclk-req-gpio",
- 0);
- if (!gpio_is_valid(arche_pdata->svc_refclk_req)) {
- dev_err(dev, "failed to get svc clock-req gpio\n");
- return arche_pdata->svc_refclk_req;
- }
- ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req,
- "svc-clk-req");
- if (ret) {
- dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret);
- return ret;
- }
- ret = gpio_direction_input(arche_pdata->svc_refclk_req);
- if (ret) {
- dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret);
+ arche_pdata->svc_refclk_req = devm_gpiod_get(dev, "svc,refclk-req",
+ GPIOD_IN);
+ if (IS_ERR(arche_pdata->svc_refclk_req)) {
+ ret = PTR_ERR(arche_pdata->svc_refclk_req);
+ dev_err(dev, "failed to request svc-clk-req GPIO: %d\n", ret);
return ret;
}
@@ -515,19 +481,11 @@ static int arche_platform_probe(struct platform_device *pdev)
arche_pdata->num_apbs = of_get_child_count(np);
dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
- arche_pdata->wake_detect_gpio = of_get_named_gpio(np,
- "svc,wake-detect-gpio",
- 0);
- if (arche_pdata->wake_detect_gpio < 0) {
- dev_err(dev, "failed to get wake detect gpio\n");
- return arche_pdata->wake_detect_gpio;
- }
-
- ret = devm_gpio_request(dev, arche_pdata->wake_detect_gpio,
- "wake detect");
- if (ret) {
- dev_err(dev, "Failed requesting wake_detect gpio %d\n",
- arche_pdata->wake_detect_gpio);
+ arche_pdata->wake_detect = devm_gpiod_get(dev, "svc,wake-detect",
+ GPIOD_IN);
+ if (IS_ERR(arche_pdata->wake_detect)) {
+ ret = PTR_ERR(arche_pdata->wake_detect);
+ dev_err(dev, "Failed requesting wake_detect GPIO: %d\n", ret);
return ret;
}
@@ -538,7 +496,7 @@ static int arche_platform_probe(struct platform_device *pdev)
spin_lock_init(&arche_pdata->wake_lock);
mutex_init(&arche_pdata->platform_state_mutex);
arche_pdata->wake_detect_irq =
- gpio_to_irq(arche_pdata->wake_detect_gpio);
+ gpiod_to_irq(arche_pdata->wake_detect);
ret = devm_request_threaded_irq(dev, arche_pdata->wake_detect_irq,
arche_platform_wd_irq,
diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c
index 8bcbc3c4588c..4ac30accf226 100644
--- a/drivers/staging/greybus/audio_topology.c
+++ b/drivers/staging/greybus/audio_topology.c
@@ -923,7 +923,6 @@ static int gbaudio_tplg_create_wcontrol(struct gbaudio_module_info *gb,
break;
default:
return -EINVAL;
-
}
dev_dbg(gb->dev, "%s:%d DAPM control created, ret:%d\n", ctl->name,
diff --git a/drivers/staging/greybus/bundle.c b/drivers/staging/greybus/bundle.c
index 81c018da1248..e97b2b87ba47 100644
--- a/drivers/staging/greybus/bundle.c
+++ b/drivers/staging/greybus/bundle.c
@@ -65,7 +65,7 @@ static struct attribute *bundle_attrs[] = {
ATTRIBUTE_GROUPS(bundle);
static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
- u8 bundle_id)
+ u8 bundle_id)
{
struct gb_bundle *bundle;
diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h
index 8deeb1d5f008..5ca3befc0636 100644
--- a/drivers/staging/greybus/connection.h
+++ b/drivers/staging/greybus/connection.h
@@ -88,7 +88,7 @@ void gb_connection_mode_switch_prepare(struct gb_connection *connection);
void gb_connection_mode_switch_complete(struct gb_connection *connection);
void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
- u8 *data, size_t length);
+ u8 *data, size_t length);
void gb_connection_latency_tag_enable(struct gb_connection *connection);
void gb_connection_latency_tag_disable(struct gb_connection *connection);
diff --git a/drivers/staging/greybus/control.c b/drivers/staging/greybus/control.c
index ffa41d31896d..a9e8b6036cac 100644
--- a/drivers/staging/greybus/control.c
+++ b/drivers/staging/greybus/control.c
@@ -15,7 +15,6 @@
#define GB_CONTROL_VERSION_MAJOR 0
#define GB_CONTROL_VERSION_MINOR 1
-
static int gb_control_get_version(struct gb_control *control)
{
struct gb_interface *intf = control->connection->intf;
diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
index 412337daf45c..d6b0d49130c0 100644
--- a/drivers/staging/greybus/core.c
+++ b/drivers/staging/greybus/core.c
@@ -266,7 +266,7 @@ static int greybus_remove(struct device *dev)
}
int greybus_register_driver(struct greybus_driver *driver, struct module *owner,
- const char *mod_name)
+ const char *mod_name)
{
int retval;
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index e110681e6f86..3151004d26fb 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -9,9 +9,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/gpio/driver.h>
#include <linux/mutex.h>
#include "greybus.h"
@@ -39,11 +39,6 @@ struct gb_gpio_controller {
struct gpio_chip chip;
struct irq_chip irqc;
- struct irq_chip *irqchip;
- struct irq_domain *irqdomain;
- unsigned int irq_base;
- irq_flow_handler_t irq_handler;
- unsigned int irq_default_type;
struct mutex irq_lock;
};
#define gpio_chip_to_gb_gpio_controller(chip) \
@@ -391,7 +386,7 @@ static int gb_gpio_request_handler(struct gb_operation *op)
return -EINVAL;
}
- irq = irq_find_mapping(ggc->irqdomain, event->which);
+ irq = irq_find_mapping(ggc->chip.irq.domain, event->which);
if (!irq) {
dev_err(dev, "failed to find IRQ\n");
return -EINVAL;
@@ -506,135 +501,6 @@ static int gb_gpio_controller_setup(struct gb_gpio_controller *ggc)
return ret;
}
-/**
- * gb_gpio_irq_map() - maps an IRQ into a GB gpio irqchip
- * @d: the irqdomain used by this irqchip
- * @irq: the global irq number used by this GB gpio irqchip irq
- * @hwirq: the local IRQ/GPIO line offset on this GB gpio
- *
- * This function will set up the mapping for a certain IRQ line on a
- * GB gpio by assigning the GB gpio as chip data, and using the irqchip
- * stored inside the GB gpio.
- */
-static int gb_gpio_irq_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct gpio_chip *chip = domain->host_data;
- struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
-
- irq_set_chip_data(irq, ggc);
- irq_set_chip_and_handler(irq, ggc->irqchip, ggc->irq_handler);
- irq_set_noprobe(irq);
- /*
- * No set-up of the hardware will happen if IRQ_TYPE_NONE
- * is passed as default type.
- */
- if (ggc->irq_default_type != IRQ_TYPE_NONE)
- irq_set_irq_type(irq, ggc->irq_default_type);
-
- return 0;
-}
-
-static void gb_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
-{
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
-}
-
-static const struct irq_domain_ops gb_gpio_domain_ops = {
- .map = gb_gpio_irq_map,
- .unmap = gb_gpio_irq_unmap,
-};
-
-/**
- * gb_gpio_irqchip_remove() - removes an irqchip added to a gb_gpio_controller
- * @ggc: the gb_gpio_controller to remove the irqchip from
- *
- * This is called only from gb_gpio_remove()
- */
-static void gb_gpio_irqchip_remove(struct gb_gpio_controller *ggc)
-{
- unsigned int offset;
-
- /* Remove all IRQ mappings and delete the domain */
- if (ggc->irqdomain) {
- for (offset = 0; offset < (ggc->line_max + 1); offset++)
- irq_dispose_mapping(irq_find_mapping(ggc->irqdomain,
- offset));
- irq_domain_remove(ggc->irqdomain);
- }
-
- if (ggc->irqchip)
- ggc->irqchip = NULL;
-}
-
-/**
- * gb_gpio_irqchip_add() - adds an irqchip to a gpio chip
- * @chip: the gpio chip to add the irqchip to
- * @irqchip: the irqchip to add to the adapter
- * @first_irq: if not dynamically assigned, the base (first) IRQ to
- * allocate gpio irqs from
- * @handler: the irq handler to use (often a predefined irq core function)
- * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
- * to have the core avoid setting up any default type in the hardware.
- *
- * This function closely associates a certain irqchip with a certain
- * gpio chip, providing an irq domain to translate the local IRQs to
- * global irqs, and making sure that the gpio chip
- * is passed as chip data to all related functions. Driver callbacks
- * need to use container_of() to get their local state containers back
- * from the gpio chip passed as chip data. An irqdomain will be stored
- * in the gpio chip that shall be used by the driver to handle IRQ number
- * translation. The gpio chip will need to be initialized and registered
- * before calling this function.
- */
-static int gb_gpio_irqchip_add(struct gpio_chip *chip,
- struct irq_chip *irqchip,
- unsigned int first_irq,
- irq_flow_handler_t handler,
- unsigned int type)
-{
- struct gb_gpio_controller *ggc;
- unsigned int offset;
- unsigned int irq_base;
-
- if (!chip || !irqchip)
- return -EINVAL;
-
- ggc = gpio_chip_to_gb_gpio_controller(chip);
-
- ggc->irqchip = irqchip;
- ggc->irq_handler = handler;
- ggc->irq_default_type = type;
- ggc->irqdomain = irq_domain_add_simple(NULL,
- ggc->line_max + 1, first_irq,
- &gb_gpio_domain_ops, chip);
- if (!ggc->irqdomain) {
- ggc->irqchip = NULL;
- return -EINVAL;
- }
-
- /*
- * Prepare the mapping since the irqchip shall be orthogonal to
- * any gpio calls. If the first_irq was zero, this is
- * necessary to allocate descriptors for all IRQs.
- */
- for (offset = 0; offset < (ggc->line_max + 1); offset++) {
- irq_base = irq_create_mapping(ggc->irqdomain, offset);
- if (offset == 0)
- ggc->irq_base = irq_base;
- }
-
- return 0;
-}
-
-static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
- struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
-
- return irq_find_mapping(ggc->irqdomain, offset);
-}
-
static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
const struct gbphy_device_id *id)
{
@@ -694,7 +560,6 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
gpio->get = gb_gpio_get;
gpio->set = gb_gpio_set;
gpio->set_config = gb_gpio_set_config;
- gpio->to_irq = gb_gpio_to_irq;
gpio->base = -1; /* Allocate base dynamically */
gpio->ngpio = ggc->line_max + 1;
gpio->can_sleep = true;
@@ -703,24 +568,24 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
if (ret)
goto exit_line_free;
- ret = gb_gpio_irqchip_add(gpio, irqc, 0,
- handle_level_irq, IRQ_TYPE_NONE);
+ ret = gpiochip_add(gpio);
if (ret) {
- dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret);
+ dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret);
goto exit_line_free;
}
- ret = gpiochip_add(gpio);
+ ret = gpiochip_irqchip_add(gpio, irqc, 0, handle_level_irq,
+ IRQ_TYPE_NONE);
if (ret) {
- dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret);
- goto exit_gpio_irqchip_remove;
+ dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret);
+ goto exit_gpiochip_remove;
}
gbphy_runtime_put_autosuspend(gbphy_dev);
return 0;
-exit_gpio_irqchip_remove:
- gb_gpio_irqchip_remove(ggc);
+exit_gpiochip_remove:
+ gpiochip_remove(gpio);
exit_line_free:
kfree(ggc->lines);
exit_connection_disable:
@@ -744,7 +609,6 @@ static void gb_gpio_remove(struct gbphy_device *gbphy_dev)
gb_connection_disable_rx(connection);
gpiochip_remove(&ggc->chip);
- gb_gpio_irqchip_remove(ggc);
gb_connection_disable(connection);
gb_connection_destroy(connection);
kfree(ggc->lines);
diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
index fa8b27e091a2..3e154562c64d 100644
--- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
+++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
@@ -1,14 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h
index 986e841f6b5e..5cf12c14cca4 100644
--- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.h
+++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.h
@@ -1,14 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+/* SPDX-License-Identifier: GPL-2.0+ */
#include <linux/firmware.h>
diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c
index 83a13ca7259a..80903ec36b76 100644
--- a/drivers/staging/gs_fpgaboot/io.c
+++ b/drivers/staging/gs_fpgaboot/io.c
@@ -1,15 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- */
+// SPDX-License-Identifier: GPL-2.0+
#include <linux/kernel.h>
#include <linux/init.h>
@@ -50,8 +39,7 @@ int xl_supported_prog_bus_width(enum wbus bus_bytes)
case bus_2byte:
break;
default:
- pr_err("unsupported program bus width %d\n",
- bus_bytes);
+ pr_err("unsupported program bus width %d\n", bus_bytes);
return 0;
}
diff --git a/drivers/staging/gs_fpgaboot/io.h b/drivers/staging/gs_fpgaboot/io.h
index bc5d99cbda8f..9bd86a92e90f 100644
--- a/drivers/staging/gs_fpgaboot/io.h
+++ b/drivers/staging/gs_fpgaboot/io.h
@@ -1,14 +1,4 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+/* SPDX-License-Identifier: GPL-2.0+ */
#define GPDIR 0
#define GPCFG 4 /* open drain or not */
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index fc23059f1673..7a93d3a5c113 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -3,40 +3,6 @@
#
menu "Analog to digital converters"
-config AD7606
- tristate "Analog Devices AD7606 ADC driver"
- depends on GPIOLIB || COMPILE_TEST
- depends on HAS_IOMEM
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- Say yes here to build support for Analog Devices:
- ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
-
- To compile this driver as a module, choose M here: the
- module will be called ad7606.
-
-config AD7606_IFACE_PARALLEL
- tristate "parallel interface support"
- depends on AD7606
- help
- Say yes here to include parallel interface support on the AD7606
- ADC driver.
-
- To compile this driver as a module, choose M here: the
- module will be called ad7606_parallel.
-
-config AD7606_IFACE_SPI
- tristate "spi interface support"
- depends on AD7606
- depends on SPI
- help
- Say yes here to include parallel interface support on the AD7606
- ADC driver.
-
- To compile this driver as a module, choose M here: the
- module will be called ad7606_spi.
-
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
depends on SPI
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index ebe83c1ad362..7a421088ff82 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -3,10 +3,6 @@
# Makefile for industrial I/O ADC drivers
#
-obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
-obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
-obj-$(CONFIG_AD7606) += ad7606.o
-
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7816) += ad7816.o
obj-$(CONFIG_AD7192) += ad7192.o
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 14f6a3ced060..d9df12665176 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -97,6 +97,10 @@
#define AD7280A_NUM_CH (AD7280A_AUX_ADC_6 - \
AD7280A_CELL_VOLTAGE_1 + 1)
+#define AD7280A_CALC_VOLTAGE_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + c)
+#define AD7280A_CALC_TEMP_CHAN_NUM(d, c) ((d * AD7280A_CELLS_PER_DEV) + \
+ c - AD7280A_CELLS_PER_DEV)
+
#define AD7280A_DEVADDR_MASTER 0
#define AD7280A_DEVADDR_ALL 0x1F
/* 5-bit device address is sent LSB first */
@@ -496,72 +500,171 @@ static const struct attribute_group ad7280_attrs_group = {
.attrs = ad7280_attributes,
};
+static void ad7280_voltage_channel_init(struct iio_chan_spec *chan, int i)
+{
+ chan->type = IIO_VOLTAGE;
+ chan->differential = 1;
+ chan->channel = i;
+ chan->channel2 = chan->channel + 1;
+}
+
+static void ad7280_temp_channel_init(struct iio_chan_spec *chan, int i)
+{
+ chan->type = IIO_TEMP;
+ chan->channel = i;
+}
+
+static void ad7280_common_fields_init(struct iio_chan_spec *chan, int addr,
+ int cnt)
+{
+ chan->indexed = 1;
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+ chan->address = addr;
+ chan->scan_index = cnt;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 12;
+ chan->scan_type.storagebits = 32;
+}
+
+static void ad7280_total_voltage_channel_init(struct iio_chan_spec *chan,
+ int cnt, int dev)
+{
+ chan->type = IIO_VOLTAGE;
+ chan->differential = 1;
+ chan->channel = 0;
+ chan->channel2 = dev * AD7280A_CELLS_PER_DEV;
+ chan->address = AD7280A_ALL_CELLS;
+ chan->indexed = 1;
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+ chan->scan_index = cnt;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 32;
+ chan->scan_type.storagebits = 32;
+}
+
+static void ad7280_timestamp_channel_init(struct iio_chan_spec *chan, int cnt)
+{
+ chan->type = IIO_TIMESTAMP;
+ chan->channel = -1;
+ chan->scan_index = cnt;
+ chan->scan_type.sign = 's';
+ chan->scan_type.realbits = 64;
+ chan->scan_type.storagebits = 64;
+}
+
+static void ad7280_init_dev_channels(struct ad7280_state *st, int dev, int *cnt)
+{
+ int addr, ch, i;
+ struct iio_chan_spec *chan;
+
+ for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6; ch++) {
+ chan = &st->channels[*cnt];
+
+ if (ch < AD7280A_AUX_ADC_1) {
+ i = AD7280A_CALC_VOLTAGE_CHAN_NUM(dev, ch);
+ ad7280_voltage_channel_init(chan, i);
+ } else {
+ i = AD7280A_CALC_TEMP_CHAN_NUM(dev, ch);
+ ad7280_temp_channel_init(chan, i);
+ }
+
+ addr = ad7280a_devaddr(dev) << 8 | ch;
+ ad7280_common_fields_init(chan, addr, *cnt);
+
+ (*cnt)++;
+ }
+}
+
static int ad7280_channel_init(struct ad7280_state *st)
{
- int dev, ch, cnt;
+ int dev, cnt = 0;
st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2,
sizeof(*st->channels), GFP_KERNEL);
if (!st->channels)
return -ENOMEM;
- for (dev = 0, cnt = 0; dev <= st->slave_num; dev++)
- for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_AUX_ADC_6;
- ch++, cnt++) {
- if (ch < AD7280A_AUX_ADC_1) {
- st->channels[cnt].type = IIO_VOLTAGE;
- st->channels[cnt].differential = 1;
- st->channels[cnt].channel = (dev * 6) + ch;
- st->channels[cnt].channel2 =
- st->channels[cnt].channel + 1;
- } else {
- st->channels[cnt].type = IIO_TEMP;
- st->channels[cnt].channel = (dev * 6) + ch - 6;
- }
- st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask_separate =
- BIT(IIO_CHAN_INFO_RAW);
- st->channels[cnt].info_mask_shared_by_type =
- BIT(IIO_CHAN_INFO_SCALE);
- st->channels[cnt].address =
- ad7280a_devaddr(dev) << 8 | ch;
- st->channels[cnt].scan_index = cnt;
- st->channels[cnt].scan_type.sign = 'u';
- st->channels[cnt].scan_type.realbits = 12;
- st->channels[cnt].scan_type.storagebits = 32;
- st->channels[cnt].scan_type.shift = 0;
- }
+ for (dev = 0; dev <= st->slave_num; dev++)
+ ad7280_init_dev_channels(st, dev, &cnt);
- st->channels[cnt].type = IIO_VOLTAGE;
- st->channels[cnt].differential = 1;
- st->channels[cnt].channel = 0;
- st->channels[cnt].channel2 = dev * 6;
- st->channels[cnt].address = AD7280A_ALL_CELLS;
- st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
- st->channels[cnt].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
- st->channels[cnt].scan_index = cnt;
- st->channels[cnt].scan_type.sign = 'u';
- st->channels[cnt].scan_type.realbits = 32;
- st->channels[cnt].scan_type.storagebits = 32;
- st->channels[cnt].scan_type.shift = 0;
+ ad7280_total_voltage_channel_init(&st->channels[cnt], cnt, dev);
cnt++;
- st->channels[cnt].type = IIO_TIMESTAMP;
- st->channels[cnt].channel = -1;
- st->channels[cnt].scan_index = cnt;
- st->channels[cnt].scan_type.sign = 's';
- st->channels[cnt].scan_type.realbits = 64;
- st->channels[cnt].scan_type.storagebits = 64;
- st->channels[cnt].scan_type.shift = 0;
+ ad7280_timestamp_channel_init(&st->channels[cnt], cnt);
return cnt + 1;
}
-static int ad7280_attr_init(struct ad7280_state *st)
+static int ad7280_balance_switch_attr_init(struct iio_dev_attr *attr,
+ struct device *dev, int addr, int i)
{
- int dev, ch, cnt;
- unsigned int index;
+ attr->address = addr;
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = ad7280_show_balance_sw;
+ attr->dev_attr.store = ad7280_store_balance_sw;
+ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+ "in%d-in%d_balance_switch_en",
+ i, i + 1);
+ if (!attr->dev_attr.attr.name)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int ad7280_balance_timer_attr_init(struct iio_dev_attr *attr,
+ struct device *dev, int addr, int i)
+{
+ attr->address = addr;
+ attr->dev_attr.attr.mode = 0644;
+ attr->dev_attr.show = ad7280_show_balance_timer;
+ attr->dev_attr.store = ad7280_store_balance_timer;
+ attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
+ "in%d-in%d_balance_timer",
+ i, i + 1);
+ if (!attr->dev_attr.attr.name)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int ad7280_init_dev_attrs(struct ad7280_state *st, int dev, int *cnt)
+{
+ int addr, ch, i, ret;
struct iio_dev_attr *iio_attr;
+ struct device *sdev = &st->spi->dev;
+
+ for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++) {
+ iio_attr = &st->iio_attr[*cnt];
+ addr = ad7280a_devaddr(dev) << 8 | ch;
+ i = dev * AD7280A_CELLS_PER_DEV + ch;
+
+ ret = ad7280_balance_switch_attr_init(iio_attr, sdev, addr, i);
+ if (ret < 0)
+ return ret;
+
+ ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr;
+
+ (*cnt)++;
+ iio_attr = &st->iio_attr[*cnt];
+ addr = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch);
+
+ ret = ad7280_balance_timer_attr_init(iio_attr, sdev, addr, i);
+ if (ret < 0)
+ return ret;
+
+ ad7280_attributes[*cnt] = &iio_attr->dev_attr.attr;
+ (*cnt)++;
+ }
+
+ ad7280_attributes[*cnt] = NULL;
+
+ return 0;
+}
+
+static int ad7280_attr_init(struct ad7280_state *st)
+{
+ int dev, cnt = 0, ret;
st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) *
(st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
@@ -569,41 +672,11 @@ static int ad7280_attr_init(struct ad7280_state *st)
if (!st->iio_attr)
return -ENOMEM;
- for (dev = 0, cnt = 0; dev <= st->slave_num; dev++)
- for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6;
- ch++, cnt++) {
- iio_attr = &st->iio_attr[cnt];
- index = dev * AD7280A_CELLS_PER_DEV + ch;
- iio_attr->address = ad7280a_devaddr(dev) << 8 | ch;
- iio_attr->dev_attr.attr.mode = 0644;
- iio_attr->dev_attr.show = ad7280_show_balance_sw;
- iio_attr->dev_attr.store = ad7280_store_balance_sw;
- iio_attr->dev_attr.attr.name =
- devm_kasprintf(&st->spi->dev, GFP_KERNEL,
- "in%d-in%d_balance_switch_en",
- index, index + 1);
- if (!iio_attr->dev_attr.attr.name)
- return -ENOMEM;
-
- ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
- cnt++;
- iio_attr = &st->iio_attr[cnt];
- iio_attr->address = ad7280a_devaddr(dev) << 8 |
- (AD7280A_CB1_TIMER + ch);
- iio_attr->dev_attr.attr.mode = 0644;
- iio_attr->dev_attr.show = ad7280_show_balance_timer;
- iio_attr->dev_attr.store = ad7280_store_balance_timer;
- iio_attr->dev_attr.attr.name =
- devm_kasprintf(&st->spi->dev, GFP_KERNEL,
- "in%d-in%d_balance_timer",
- index, index + 1);
- if (!iio_attr->dev_attr.attr.name)
- return -ENOMEM;
-
- ad7280_attributes[cnt] = &iio_attr->dev_attr.attr;
- }
-
- ad7280_attributes[cnt] = NULL;
+ for (dev = 0; dev <= st->slave_num; dev++) {
+ ret = ad7280_init_dev_attrs(st, dev, &cnt);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 5209651a1b25..ee50e7296795 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -65,7 +65,7 @@ enum ad7816_type {
static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
{
struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
+ int ret;
__be16 buf;
gpiod_set_value(chip->rdwr_pin, 1);
@@ -106,7 +106,7 @@ static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
{
struct spi_device *spi_dev = chip->spi_dev;
- int ret = 0;
+ int ret;
gpiod_set_value(chip->rdwr_pin, 1);
gpiod_set_value(chip->rdwr_pin, 0);
@@ -354,8 +354,7 @@ static int ad7816_probe(struct spi_device *spi_dev)
{
struct ad7816_chip_info *chip;
struct iio_dev *indio_dev;
- int ret = 0;
- int i;
+ int i, ret;
indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip));
if (!indio_dev)
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
index 2d51bd425662..0f26bc38edc6 100644
--- a/drivers/staging/iio/addac/adt7316-i2c.c
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -43,7 +43,7 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
static int adt7316_i2c_write(void *client, u8 reg, u8 data)
{
struct i2c_client *cl = client;
- int ret = 0;
+ int ret;
ret = i2c_smbus_write_byte_data(cl, reg, data);
if (ret < 0)
@@ -55,7 +55,7 @@ static int adt7316_i2c_write(void *client, u8 reg, u8 data)
static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data)
{
struct i2c_client *cl = client;
- int i, ret = 0;
+ int i, ret;
if (count > ADT7316_REG_MAX_ADDR)
count = ADT7316_REG_MAX_ADDR;
@@ -74,7 +74,7 @@ static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data)
static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data)
{
struct i2c_client *cl = client;
- int i, ret = 0;
+ int i, ret;
if (count > ADT7316_REG_MAX_ADDR)
count = ADT7316_REG_MAX_ADDR;
diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
index e75827e326a6..8294b9c1e3c2 100644
--- a/drivers/staging/iio/addac/adt7316-spi.c
+++ b/drivers/staging/iio/addac/adt7316-spi.c
@@ -27,7 +27,7 @@ static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data)
{
struct spi_device *spi_dev = client;
u8 cmd[2];
- int ret = 0;
+ int ret;
if (count > ADT7316_REG_MAX_ADDR)
count = ADT7316_REG_MAX_ADDR;
@@ -56,7 +56,7 @@ static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data)
{
struct spi_device *spi_dev = client;
u8 buf[ADT7316_REG_MAX_ADDR + 2];
- int i, ret = 0;
+ int i, ret;
if (count > ADT7316_REG_MAX_ADDR)
count = ADT7316_REG_MAX_ADDR;
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index dc93e85808e0..6f7891b567b9 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -47,6 +47,8 @@
#define ADT7516_MSB_AIN3 0xA
#define ADT7516_MSB_AIN4 0xB
#define ADT7316_DA_DATA_BASE 0x10
+#define ADT7316_DA_10_BIT_LSB_SHIFT 6
+#define ADT7316_DA_12_BIT_LSB_SHIFT 4
#define ADT7316_DA_MSB_DATA_REGS 4
#define ADT7316_LSB_DAC_A 0x10
#define ADT7316_MSB_DAC_A 0x11
@@ -59,8 +61,8 @@
#define ADT7316_CONFIG1 0x18
#define ADT7316_CONFIG2 0x19
#define ADT7316_CONFIG3 0x1A
-#define ADT7316_LDAC_CONFIG 0x1B
-#define ADT7316_DAC_CONFIG 0x1C
+#define ADT7316_DAC_CONFIG 0x1B
+#define ADT7316_LDAC_CONFIG 0x1C
#define ADT7316_INT_MASK1 0x1D
#define ADT7316_INT_MASK2 0x1E
#define ADT7316_IN_TEMP_OFFSET 0x1F
@@ -117,7 +119,7 @@
*/
#define ADT7316_ADCLK_22_5 0x1
#define ADT7316_DA_HIGH_RESOLUTION 0x2
-#define ADT7316_DA_EN_VIA_DAC_LDCA 0x4
+#define ADT7316_DA_EN_VIA_DAC_LDAC 0x8
#define ADT7516_AIN_IN_VREF 0x10
#define ADT7316_EN_IN_TEMP_PROP_DACA 0x20
#define ADT7316_EN_EX_TEMP_PROP_DACB 0x40
@@ -127,6 +129,7 @@
*/
#define ADT7316_DA_2VREF_CH_MASK 0xF
#define ADT7316_DA_EN_MODE_MASK 0x30
+#define ADT7316_DA_EN_MODE_SHIFT 4
#define ADT7316_DA_EN_MODE_SINGLE 0x00
#define ADT7316_DA_EN_MODE_AB_CD 0x10
#define ADT7316_DA_EN_MODE_ABCD 0x20
@@ -632,9 +635,7 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev,
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
- if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
- return sprintf(buf, "1 (12 bits)\n");
- if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+ if (chip->id != ID_ADT7318 && chip->id != ID_ADT7519)
return sprintf(buf, "1 (10 bits)\n");
}
@@ -651,17 +652,12 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev,
u8 config3;
int ret;
- chip->dac_bits = 8;
+ if (chip->id == ID_ADT7318 || chip->id == ID_ADT7519)
+ return -EPERM;
- if (buf[0] == '1') {
- config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION;
- if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
- chip->dac_bits = 12;
- else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
- chip->dac_bits = 10;
- } else {
- config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
- }
+ config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
+ if (buf[0] == '1')
+ config3 |= ADT7316_DA_HIGH_RESOLUTION;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
if (ret)
@@ -851,7 +847,7 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+ if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC))
return sprintf(buf, "manual\n");
switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
@@ -880,15 +876,15 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
u8 data;
int ret;
- if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+ if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC))
return -EPERM;
ret = kstrtou8(buf, 10, &data);
- if (ret || data > ADT7316_DA_EN_MODE_MASK)
+ if (ret || data > (ADT7316_DA_EN_MODE_MASK >> ADT7316_DA_EN_MODE_SHIFT))
return -EINVAL;
dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK);
- dac_config |= data;
+ dac_config |= data << ADT7316_DA_EN_MODE_SHIFT;
ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
if (ret)
@@ -911,7 +907,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
+ if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC)
return sprintf(buf, "0 - auto at any MSB DAC writing\n"
"1 - auto at MSB DAC AB and CD writing\n"
"2 - auto at MSB DAC ABCD writing\n"
@@ -933,7 +929,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
u8 data;
int ret;
- if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) {
+ if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDAC) {
if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) !=
ADT7316_DA_EN_MODE_LDAC)
return -EPERM;
@@ -969,9 +965,6 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
- return -EPERM;
-
return sprintf(buf, "%d\n",
!!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB));
}
@@ -986,9 +979,6 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
u8 dac_config;
int ret;
- if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
- return -EPERM;
-
dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
if (buf[0] == '1')
dac_config |= ADT7316_VREF_BYPASS_DAC_AB;
@@ -1014,9 +1004,6 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
- if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
- return -EPERM;
-
return sprintf(buf, "%d\n",
!!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD));
}
@@ -1031,9 +1018,6 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
u8 dac_config;
int ret;
- if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
- return -EPERM;
-
dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
if (buf[0] == '1')
dac_config |= ADT7316_VREF_BYPASS_DAC_CD;
@@ -1061,10 +1045,10 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
return sprintf(buf, "0x%x\n",
- (chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >>
+ (chip->ldac_config & ADT7516_DAC_IN_VREF_MASK) >>
ADT7516_DAC_IN_VREF_OFFSET);
return sprintf(buf, "%d\n",
- !!(chip->dac_config & ADT7316_DAC_IN_VREF));
+ !!(chip->ldac_config & ADT7316_DAC_IN_VREF));
}
static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
@@ -1086,7 +1070,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK);
if (data & 0x1)
ldac_config |= ADT7516_DAC_AB_IN_VREF;
- else if (data & 0x2)
+ if (data & 0x2)
ldac_config |= ADT7516_DAC_CD_IN_VREF;
} else {
ret = kstrtou8(buf, 16, &data);
@@ -1410,7 +1394,7 @@ static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644,
static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
int channel, char *buf)
{
- u16 data;
+ u16 data = 0;
u8 msb, lsb, offset;
int ret;
@@ -1435,7 +1419,11 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
if (ret)
return -EIO;
- data = (msb << offset) + (lsb & ((1 << offset) - 1));
+ if (chip->dac_bits == 12)
+ data = lsb >> ADT7316_DA_12_BIT_LSB_SHIFT;
+ else if (chip->dac_bits == 10)
+ data = lsb >> ADT7316_DA_10_BIT_LSB_SHIFT;
+ data |= msb << offset;
return sprintf(buf, "%d\n", data);
}
@@ -1443,7 +1431,7 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
int channel, const char *buf, size_t len)
{
- u8 msb, lsb, offset;
+ u8 msb, lsb, lsb_reg, offset;
u16 data;
int ret;
@@ -1461,9 +1449,13 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
return -EINVAL;
if (chip->dac_bits > 8) {
- lsb = data & (1 << offset);
+ lsb = data & ((1 << offset) - 1);
+ if (chip->dac_bits == 12)
+ lsb_reg = lsb << ADT7316_DA_12_BIT_LSB_SHIFT;
+ else
+ lsb_reg = lsb << ADT7316_DA_10_BIT_LSB_SHIFT;
ret = chip->bus.write(chip->bus.client,
- ADT7316_DA_DATA_BASE + channel * 2, lsb);
+ ADT7316_DA_DATA_BASE + channel * 2, lsb_reg);
if (ret)
return -EIO;
}
@@ -1710,8 +1702,6 @@ static struct attribute *adt7516_attributes[] = {
&iio_dev_attr_DAC_update_mode.dev_attr.attr,
&iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
&iio_dev_attr_update_DAC.dev_attr.attr,
- &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
- &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
&iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
&iio_dev_attr_VDD.dev_attr.attr,
&iio_dev_attr_in_temp.dev_attr.attr,
@@ -1809,6 +1799,43 @@ static irqreturn_t adt7316_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
+static int adt7316_setup_irq(struct iio_dev *indio_dev)
+{
+ struct adt7316_chip_info *chip = iio_priv(indio_dev);
+ int irq_type, ret;
+
+ irq_type = irqd_get_trigger_type(irq_get_irq_data(chip->bus.irq));
+
+ switch (irq_type) {
+ case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
+ break;
+ case IRQF_TRIGGER_LOW:
+ case IRQF_TRIGGER_FALLING:
+ break;
+ default:
+ dev_info(&indio_dev->dev, "mode %d unsupported, using IRQF_TRIGGER_LOW\n",
+ irq_type);
+ irq_type = IRQF_TRIGGER_LOW;
+ break;
+ }
+
+ ret = devm_request_threaded_irq(&indio_dev->dev, chip->bus.irq,
+ NULL, adt7316_event_handler,
+ irq_type | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret) {
+ dev_err(&indio_dev->dev, "failed to request irq %d\n",
+ chip->bus.irq);
+ return ret;
+ }
+
+ if (irq_type & IRQF_TRIGGER_HIGH)
+ chip->config1 |= ADT7316_INT_POLARITY;
+
+ return 0;
+}
+
/*
* Show mask of enabled interrupts in Hex.
*/
@@ -2103,9 +2130,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
{
struct adt7316_chip_info *chip;
struct iio_dev *indio_dev;
- unsigned short *adt7316_platform_data = dev->platform_data;
- int irq_type = IRQF_TRIGGER_LOW;
- int ret = 0;
+ int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
if (!indio_dev)
@@ -2123,6 +2148,13 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
else
return -ENODEV;
+ if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
+ chip->dac_bits = 12;
+ else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+ chip->dac_bits = 10;
+ else
+ chip->dac_bits = 8;
+
chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac", GPIOD_OUT_LOW);
if (IS_ERR(chip->ldac_pin)) {
ret = PTR_ERR(chip->ldac_pin);
@@ -2130,8 +2162,8 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
return ret;
}
- if (chip->ldac_pin) {
- chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
+ if (!chip->ldac_pin) {
+ chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDAC;
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
chip->config1 |= ADT7516_SEL_AIN3;
}
@@ -2148,20 +2180,9 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
indio_dev->modes = INDIO_DIRECT_MODE;
if (chip->bus.irq > 0) {
- if (adt7316_platform_data[0])
- irq_type = adt7316_platform_data[0];
-
- ret = devm_request_threaded_irq(dev, chip->bus.irq,
- NULL,
- adt7316_event_handler,
- irq_type | IRQF_ONESHOT,
- indio_dev->name,
- indio_dev);
+ ret = adt7316_setup_irq(indio_dev);
if (ret)
return ret;
-
- if (irq_type & IRQF_TRIGGER_HIGH)
- chip->config1 |= ADT7316_INT_POLARITY;
}
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1);
diff --git a/drivers/staging/iio/cdc/Kconfig b/drivers/staging/iio/cdc/Kconfig
index 80211df8c577..b97478e7cbd0 100644
--- a/drivers/staging/iio/cdc/Kconfig
+++ b/drivers/staging/iio/cdc/Kconfig
@@ -13,16 +13,6 @@ config AD7150
To compile this driver as a module, choose M here: the
module will be called ad7150.
-config AD7152
- tristate "Analog Devices ad7152/3 capacitive sensor driver"
- depends on I2C
- help
- Say yes here to build support for Analog Devices capacitive sensors.
- (ad7152, ad7153) Provides direct access via sysfs.
-
- To compile this driver as a module, choose M here: the
- module will be called ad7152.
-
config AD7746
tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver"
depends on I2C
diff --git a/drivers/staging/iio/cdc/Makefile b/drivers/staging/iio/cdc/Makefile
index a5fbabf5c8bf..1466bc31f244 100644
--- a/drivers/staging/iio/cdc/Makefile
+++ b/drivers/staging/iio/cdc/Makefile
@@ -3,5 +3,4 @@
#
obj-$(CONFIG_AD7150) += ad7150.o
-obj-$(CONFIG_AD7152) += ad7152.o
obj-$(CONFIG_AD7746) += ad7746.o
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
deleted file mode 100644
index 25f51db05d2d..000000000000
--- a/drivers/staging/iio/cdc/ad7152.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * AD7152 capacitive sensor driver supporting AD7152/3
- *
- * Copyright 2010-2011a Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-
-/*
- * TODO: Check compliance of calibbias with abi (units)
- */
-/*
- * AD7152 registers definition
- */
-
-#define AD7152_REG_STATUS 0
-#define AD7152_REG_CH1_DATA_HIGH 1
-#define AD7152_REG_CH2_DATA_HIGH 3
-#define AD7152_REG_CH1_OFFS_HIGH 5
-#define AD7152_REG_CH2_OFFS_HIGH 7
-#define AD7152_REG_CH1_GAIN_HIGH 9
-#define AD7152_REG_CH1_SETUP 11
-#define AD7152_REG_CH2_GAIN_HIGH 12
-#define AD7152_REG_CH2_SETUP 14
-#define AD7152_REG_CFG 15
-#define AD7152_REG_RESEVERD 16
-#define AD7152_REG_CAPDAC_POS 17
-#define AD7152_REG_CAPDAC_NEG 18
-#define AD7152_REG_CFG2 26
-
-/* Status Register Bit Designations (AD7152_REG_STATUS) */
-#define AD7152_STATUS_RDY1 BIT(0)
-#define AD7152_STATUS_RDY2 BIT(1)
-#define AD7152_STATUS_C1C2 BIT(2)
-#define AD7152_STATUS_PWDN BIT(7)
-
-/* Setup Register Bit Designations (AD7152_REG_CHx_SETUP) */
-#define AD7152_SETUP_CAPDIFF BIT(5)
-#define AD7152_SETUP_RANGE_2pF (0 << 6)
-#define AD7152_SETUP_RANGE_0_5pF (1 << 6)
-#define AD7152_SETUP_RANGE_1pF (2 << 6)
-#define AD7152_SETUP_RANGE_4pF (3 << 6)
-#define AD7152_SETUP_RANGE(x) ((x) << 6)
-
-/* Config Register Bit Designations (AD7152_REG_CFG) */
-#define AD7152_CONF_CH2EN BIT(3)
-#define AD7152_CONF_CH1EN BIT(4)
-#define AD7152_CONF_MODE_IDLE (0 << 0)
-#define AD7152_CONF_MODE_CONT_CONV (1 << 0)
-#define AD7152_CONF_MODE_SINGLE_CONV (2 << 0)
-#define AD7152_CONF_MODE_OFFS_CAL (5 << 0)
-#define AD7152_CONF_MODE_GAIN_CAL (6 << 0)
-
-/* Capdac Register Bit Designations (AD7152_REG_CAPDAC_XXX) */
-#define AD7152_CAPDAC_DACEN BIT(7)
-#define AD7152_CAPDAC_DACP(x) ((x) & 0x1F)
-
-/* CFG2 Register Bit Designations (AD7152_REG_CFG2) */
-#define AD7152_CFG2_OSR(x) (((x) & 0x3) << 4)
-
-enum {
- AD7152_DATA,
- AD7152_OFFS,
- AD7152_GAIN,
- AD7152_SETUP
-};
-
-/*
- * struct ad7152_chip_info - chip specific information
- */
-
-struct ad7152_chip_info {
- struct i2c_client *client;
- /*
- * Capacitive channel digital filter setup;
- * conversion time/update rate setup per channel
- */
- u8 filter_rate_setup;
- u8 setup[2];
- struct mutex state_lock; /* protect hardware state */
-};
-
-static inline ssize_t ad7152_start_calib(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len,
- u8 regval)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7152_chip_info *chip = iio_priv(indio_dev);
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- bool doit;
- int ret, timeout = 10;
-
- ret = strtobool(buf, &doit);
- if (ret < 0)
- return ret;
-
- if (!doit)
- return 0;
-
- if (this_attr->address == 0)
- regval |= AD7152_CONF_CH1EN;
- else
- regval |= AD7152_CONF_CH2EN;
-
- mutex_lock(&chip->state_lock);
- ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG, regval);
- if (ret < 0)
- goto unlock;
-
- do {
- mdelay(20);
- ret = i2c_smbus_read_byte_data(chip->client, AD7152_REG_CFG);
- if (ret < 0)
- goto unlock;
-
- } while ((ret == regval) && timeout--);
-
- mutex_unlock(&chip->state_lock);
- return len;
-
-unlock:
- mutex_unlock(&chip->state_lock);
- return ret;
-}
-
-static ssize_t ad7152_start_offset_calib(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return ad7152_start_calib(dev, attr, buf, len,
- AD7152_CONF_MODE_OFFS_CAL);
-}
-
-static ssize_t ad7152_start_gain_calib(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return ad7152_start_calib(dev, attr, buf, len,
- AD7152_CONF_MODE_GAIN_CAL);
-}
-
-static IIO_DEVICE_ATTR(in_capacitance0_calibbias_calibration,
- 0200, NULL, ad7152_start_offset_calib, 0);
-static IIO_DEVICE_ATTR(in_capacitance1_calibbias_calibration,
- 0200, NULL, ad7152_start_offset_calib, 1);
-static IIO_DEVICE_ATTR(in_capacitance0_calibscale_calibration,
- 0200, NULL, ad7152_start_gain_calib, 0);
-static IIO_DEVICE_ATTR(in_capacitance1_calibscale_calibration,
- 0200, NULL, ad7152_start_gain_calib, 1);
-
-/* Values are Update Rate (Hz), Conversion Time (ms) + 1*/
-static const unsigned char ad7152_filter_rate_table[][2] = {
- {200, 5 + 1}, {50, 20 + 1}, {20, 50 + 1}, {17, 60 + 1},
-};
-
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("200 50 20 17");
-
-static IIO_CONST_ATTR(in_capacitance_scale_available,
- "0.000061050 0.000030525 0.000015263 0.000007631");
-
-static struct attribute *ad7152_attributes[] = {
- &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr,
- &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr,
- &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr,
- &iio_dev_attr_in_capacitance1_calibscale_calibration.dev_attr.attr,
- &iio_const_attr_in_capacitance_scale_available.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad7152_attribute_group = {
- .attrs = ad7152_attributes,
-};
-
-static const u8 ad7152_addresses[][4] = {
- { AD7152_REG_CH1_DATA_HIGH, AD7152_REG_CH1_OFFS_HIGH,
- AD7152_REG_CH1_GAIN_HIGH, AD7152_REG_CH1_SETUP },
- { AD7152_REG_CH2_DATA_HIGH, AD7152_REG_CH2_OFFS_HIGH,
- AD7152_REG_CH2_GAIN_HIGH, AD7152_REG_CH2_SETUP },
-};
-
-/* Values are nano relative to pf base. */
-static const int ad7152_scale_table[] = {
- 30525, 7631, 15263, 61050
-};
-
-/**
- * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ
- *
- * lock must be held
- **/
-static int ad7152_read_raw_samp_freq(struct device *dev, int *val)
-{
- struct ad7152_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
-
- *val = ad7152_filter_rate_table[chip->filter_rate_setup][0];
-
- return 0;
-}
-
-/**
- * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ
- *
- * lock must be held
- **/
-static int ad7152_write_raw_samp_freq(struct device *dev, int val)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7152_chip_info *chip = iio_priv(indio_dev);
- int ret, i;
-
- for (i = 0; i < ARRAY_SIZE(ad7152_filter_rate_table); i++)
- if (val >= ad7152_filter_rate_table[i][0])
- break;
-
- if (i >= ARRAY_SIZE(ad7152_filter_rate_table))
- i = ARRAY_SIZE(ad7152_filter_rate_table) - 1;
-
- ret = i2c_smbus_write_byte_data(chip->client,
- AD7152_REG_CFG2, AD7152_CFG2_OSR(i));
- if (ret < 0)
- return ret;
-
- chip->filter_rate_setup = i;
-
- return ret;
-}
-
-static int ad7152_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val,
- int val2,
- long mask)
-{
- struct ad7152_chip_info *chip = iio_priv(indio_dev);
- int ret, i;
-
- mutex_lock(&chip->state_lock);
-
- switch (mask) {
- case IIO_CHAN_INFO_CALIBSCALE:
- if (val != 1) {
- ret = -EINVAL;
- goto out;
- }
-
- val = (val2 * 1024) / 15625;
-
- ret = i2c_smbus_write_word_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_GAIN],
- swab16(val));
- if (ret < 0)
- goto out;
-
- ret = 0;
- break;
-
- case IIO_CHAN_INFO_CALIBBIAS:
- if ((val < 0) | (val > 0xFFFF)) {
- ret = -EINVAL;
- goto out;
- }
- ret = i2c_smbus_write_word_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_OFFS],
- swab16(val));
- if (ret < 0)
- goto out;
-
- ret = 0;
- break;
- case IIO_CHAN_INFO_SCALE:
- if (val) {
- ret = -EINVAL;
- goto out;
- }
- for (i = 0; i < ARRAY_SIZE(ad7152_scale_table); i++)
- if (val2 == ad7152_scale_table[i])
- break;
-
- chip->setup[chan->channel] &= ~AD7152_SETUP_RANGE_4pF;
- chip->setup[chan->channel] |= AD7152_SETUP_RANGE(i);
-
- ret = i2c_smbus_write_byte_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_SETUP],
- chip->setup[chan->channel]);
- if (ret < 0)
- goto out;
-
- ret = 0;
- break;
- case IIO_CHAN_INFO_SAMP_FREQ:
- if (val2) {
- ret = -EINVAL;
- goto out;
- }
- ret = ad7152_write_raw_samp_freq(&indio_dev->dev, val);
- if (ret < 0)
- goto out;
-
- ret = 0;
- break;
- default:
- ret = -EINVAL;
- }
-
-out:
- mutex_unlock(&chip->state_lock);
- return ret;
-}
-
-static int ad7152_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
-{
- struct ad7152_chip_info *chip = iio_priv(indio_dev);
- int ret;
- u8 regval = 0;
-
- mutex_lock(&chip->state_lock);
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- /* First set whether in differential mode */
-
- regval = chip->setup[chan->channel];
-
- if (chan->differential)
- chip->setup[chan->channel] |= AD7152_SETUP_CAPDIFF;
- else
- chip->setup[chan->channel] &= ~AD7152_SETUP_CAPDIFF;
-
- if (regval != chip->setup[chan->channel]) {
- ret = i2c_smbus_write_byte_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_SETUP],
- chip->setup[chan->channel]);
- if (ret < 0)
- goto out;
- }
- /* Make sure the channel is enabled */
- if (chan->channel == 0)
- regval = AD7152_CONF_CH1EN;
- else
- regval = AD7152_CONF_CH2EN;
-
- /* Trigger a single read */
- regval |= AD7152_CONF_MODE_SINGLE_CONV;
- ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG,
- regval);
- if (ret < 0)
- goto out;
-
- msleep(ad7152_filter_rate_table[chip->filter_rate_setup][1]);
- /* Now read the actual register */
- ret = i2c_smbus_read_word_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_DATA]);
- if (ret < 0)
- goto out;
- *val = swab16(ret);
-
- if (chan->differential)
- *val -= 0x8000;
-
- ret = IIO_VAL_INT;
- break;
- case IIO_CHAN_INFO_CALIBSCALE:
-
- ret = i2c_smbus_read_word_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_GAIN]);
- if (ret < 0)
- goto out;
- /* 1 + gain_val / 2^16 */
- *val = 1;
- *val2 = (15625 * swab16(ret)) / 1024;
-
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
- case IIO_CHAN_INFO_CALIBBIAS:
- ret = i2c_smbus_read_word_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_OFFS]);
- if (ret < 0)
- goto out;
- *val = swab16(ret);
-
- ret = IIO_VAL_INT;
- break;
- case IIO_CHAN_INFO_SCALE:
- ret = i2c_smbus_read_byte_data(chip->client,
- ad7152_addresses[chan->channel][AD7152_SETUP]);
- if (ret < 0)
- goto out;
- *val = 0;
- *val2 = ad7152_scale_table[ret >> 6];
-
- ret = IIO_VAL_INT_PLUS_NANO;
- break;
- case IIO_CHAN_INFO_SAMP_FREQ:
- ret = ad7152_read_raw_samp_freq(&indio_dev->dev, val);
- if (ret < 0)
- goto out;
-
- ret = IIO_VAL_INT;
- break;
- default:
- ret = -EINVAL;
- }
-out:
- mutex_unlock(&chip->state_lock);
- return ret;
-}
-
-static int ad7152_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
-{
- switch (mask) {
- case IIO_CHAN_INFO_SCALE:
- return IIO_VAL_INT_PLUS_NANO;
- default:
- return IIO_VAL_INT_PLUS_MICRO;
- }
-}
-
-static const struct iio_info ad7152_info = {
- .attrs = &ad7152_attribute_group,
- .read_raw = ad7152_read_raw,
- .write_raw = ad7152_write_raw,
- .write_raw_get_fmt = ad7152_write_raw_get_fmt,
-};
-
-static const struct iio_chan_spec ad7152_channels[] = {
- {
- .type = IIO_CAPACITANCE,
- .indexed = 1,
- .channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBSCALE) |
- BIT(IIO_CHAN_INFO_CALIBBIAS) |
- BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
- }, {
- .type = IIO_CAPACITANCE,
- .differential = 1,
- .indexed = 1,
- .channel = 0,
- .channel2 = 2,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBSCALE) |
- BIT(IIO_CHAN_INFO_CALIBBIAS) |
- BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
- }, {
- .type = IIO_CAPACITANCE,
- .indexed = 1,
- .channel = 1,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBSCALE) |
- BIT(IIO_CHAN_INFO_CALIBBIAS) |
- BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
- }, {
- .type = IIO_CAPACITANCE,
- .differential = 1,
- .indexed = 1,
- .channel = 1,
- .channel2 = 3,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBSCALE) |
- BIT(IIO_CHAN_INFO_CALIBBIAS) |
- BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
- }
-};
-
-/*
- * device probe and remove
- */
-
-static int ad7152_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int ret = 0;
- struct ad7152_chip_info *chip;
- struct iio_dev *indio_dev;
-
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
- if (!indio_dev)
- return -ENOMEM;
- chip = iio_priv(indio_dev);
- /* this is only used for device removal purposes */
- i2c_set_clientdata(client, indio_dev);
-
- chip->client = client;
- mutex_init(&chip->state_lock);
-
- /* Establish that the iio_dev is a child of the i2c device */
- indio_dev->name = id->name;
- indio_dev->dev.parent = &client->dev;
- indio_dev->info = &ad7152_info;
- indio_dev->channels = ad7152_channels;
- if (id->driver_data == 0)
- indio_dev->num_channels = ARRAY_SIZE(ad7152_channels);
- else
- indio_dev->num_channels = 2;
- indio_dev->num_channels = ARRAY_SIZE(ad7152_channels);
- indio_dev->modes = INDIO_DIRECT_MODE;
-
- ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
- if (ret)
- return ret;
-
- dev_err(&client->dev, "%s capacitive sensor registered\n", id->name);
-
- return 0;
-}
-
-static const struct i2c_device_id ad7152_id[] = {
- { "ad7152", 0 },
- { "ad7153", 1 },
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, ad7152_id);
-
-static struct i2c_driver ad7152_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- },
- .probe = ad7152_probe,
- .id_table = ad7152_id,
-};
-module_i2c_driver(ad7152_driver);
-
-MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices AD7152/3 capacitive sensor driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 1e977014fe5f..0b0287503fb4 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -6,6 +6,7 @@
* Licensed under the GPL-2.
*/
+#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/device.h>
@@ -71,7 +72,7 @@
struct ad9834_state {
struct spi_device *spi;
struct regulator *reg;
- unsigned int mclk;
+ struct clk *mclk;
unsigned short control;
unsigned short devid;
struct spi_transfer xfer;
@@ -110,12 +111,15 @@ static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout)
static int ad9834_write_frequency(struct ad9834_state *st,
unsigned long addr, unsigned long fout)
{
+ unsigned long clk_freq;
unsigned long regval;
- if (fout > (st->mclk / 2))
+ clk_freq = clk_get_rate(st->mclk);
+
+ if (fout > (clk_freq / 2))
return -EINVAL;
- regval = ad9834_calc_freqreg(st->mclk, fout);
+ regval = ad9834_calc_freqreg(clk_freq, fout);
st->freq_data[0] = cpu_to_be16(addr | (regval &
RES_MASK(AD9834_FREQ_BITS / 2)));
@@ -389,16 +393,11 @@ static const struct iio_info ad9833_info = {
static int ad9834_probe(struct spi_device *spi)
{
- struct ad9834_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad9834_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
int ret;
- if (!pdata) {
- dev_dbg(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
reg = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(reg))
@@ -418,7 +417,14 @@ static int ad9834_probe(struct spi_device *spi)
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
mutex_init(&st->lock);
- st->mclk = pdata->mclk;
+ st->mclk = devm_clk_get(&spi->dev, NULL);
+
+ ret = clk_prepare_enable(st->mclk);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable master clock\n");
+ goto error_disable_reg;
+ }
+
st->spi = spi;
st->devid = spi_get_device_id(spi)->driver_data;
st->reg = reg;
@@ -454,42 +460,41 @@ static int ad9834_probe(struct spi_device *spi)
spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg);
st->control = AD9834_B28 | AD9834_RESET;
+ st->control |= AD9834_DIV2;
- if (!pdata->en_div2)
- st->control |= AD9834_DIV2;
-
- if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834))
+ if (st->devid == ID_AD9834)
st->control |= AD9834_SIGN_PIB;
st->data = cpu_to_be16(AD9834_REG_CMD | st->control);
ret = spi_sync(st->spi, &st->msg);
if (ret) {
dev_err(&spi->dev, "device init failed\n");
- goto error_disable_reg;
+ goto error_clock_unprepare;
}
- ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0);
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, 1000000);
if (ret)
- goto error_disable_reg;
+ goto error_clock_unprepare;
- ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1);
+ ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, 5000000);
if (ret)
- goto error_disable_reg;
+ goto error_clock_unprepare;
- ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0);
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE0, 512);
if (ret)
- goto error_disable_reg;
+ goto error_clock_unprepare;
- ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1);
+ ret = ad9834_write_phase(st, AD9834_REG_PHASE1, 1024);
if (ret)
- goto error_disable_reg;
+ goto error_clock_unprepare;
ret = iio_device_register(indio_dev);
if (ret)
- goto error_disable_reg;
+ goto error_clock_unprepare;
return 0;
-
+error_clock_unprepare:
+ clk_disable_unprepare(st->mclk);
error_disable_reg:
regulator_disable(reg);
@@ -502,6 +507,7 @@ static int ad9834_remove(struct spi_device *spi)
struct ad9834_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
+ clk_disable_unprepare(st->mclk);
regulator_disable(st->reg);
return 0;
diff --git a/drivers/staging/iio/frequency/ad9834.h b/drivers/staging/iio/frequency/ad9834.h
index ae620f38eb49..da7e83ceedad 100644
--- a/drivers/staging/iio/frequency/ad9834.h
+++ b/drivers/staging/iio/frequency/ad9834.h
@@ -8,32 +8,4 @@
#ifndef IIO_DDS_AD9834_H_
#define IIO_DDS_AD9834_H_
-/*
- * TODO: struct ad7887_platform_data needs to go into include/linux/iio
- */
-
-/**
- * struct ad9834_platform_data - platform specific information
- * @mclk: master clock in Hz
- * @freq0: power up freq0 tuning word in Hz
- * @freq1: power up freq1 tuning word in Hz
- * @phase0: power up phase0 value [0..4095] correlates with 0..2PI
- * @phase1: power up phase1 value [0..4095] correlates with 0..2PI
- * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin
- * @en_signbit_msb_out: the MSB (or MSB/2) of the DAC data is connected to the
- * SIGN BIT OUT pin. en_div2 controls whether it is the MSB
- * or MSB/2 that is output. if en_signbit_msb_out=false,
- * the on-board comparator is connected to SIGN BIT OUT
- */
-
-struct ad9834_platform_data {
- unsigned int mclk;
- unsigned int freq0;
- unsigned int freq1;
- unsigned short phase0;
- unsigned short phase1;
- bool en_div2;
- bool en_signbit_msb_out;
-};
-
#endif /* IIO_DDS_AD9834_H_ */
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 9e52384f5370..3134295f014f 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -82,21 +83,10 @@
#define AD5933_POLL_TIME_ms 10
#define AD5933_INIT_EXCITATION_TIME_ms 100
-/**
- * struct ad5933_platform_data - platform specific data
- * @ext_clk_hz: the external clock frequency in Hz, if not set
- * the driver uses the internal clock (16.776 MHz)
- * @vref_mv: the external reference voltage in millivolt
- */
-
-struct ad5933_platform_data {
- unsigned long ext_clk_hz;
- unsigned short vref_mv;
-};
-
struct ad5933_state {
struct i2c_client *client;
struct regulator *reg;
+ struct clk *mclk;
struct delayed_work work;
struct mutex lock; /* Protect sensor state */
unsigned long mclk_hz;
@@ -112,10 +102,6 @@ struct ad5933_state {
unsigned int poll_time_jiffies;
};
-static struct ad5933_platform_data ad5933_default_pdata = {
- .vref_mv = 3300,
-};
-
#define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \
_scan_index, _realbits) { \
.type = (_type), \
@@ -691,10 +677,10 @@ static void ad5933_work(struct work_struct *work)
static int ad5933_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int ret, voltage_uv = 0;
- struct ad5933_platform_data *pdata = dev_get_platdata(&client->dev);
+ int ret;
struct ad5933_state *st;
struct iio_dev *indio_dev;
+ unsigned long ext_clk_hz = 0;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (!indio_dev)
@@ -706,9 +692,6 @@ static int ad5933_probe(struct i2c_client *client,
mutex_init(&st->lock);
- if (!pdata)
- pdata = &ad5933_default_pdata;
-
st->reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
@@ -718,15 +701,28 @@ static int ad5933_probe(struct i2c_client *client,
dev_err(&client->dev, "Failed to enable specified VDD supply\n");
return ret;
}
- voltage_uv = regulator_get_voltage(st->reg);
+ ret = regulator_get_voltage(st->reg);
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- st->vref_mv = pdata->vref_mv;
+ if (ret < 0)
+ goto error_disable_reg;
+
+ st->vref_mv = ret / 1000;
+
+ st->mclk = devm_clk_get(&client->dev, "mclk");
+ if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) {
+ ret = PTR_ERR(st->mclk);
+ goto error_disable_reg;
+ }
- if (pdata->ext_clk_hz) {
- st->mclk_hz = pdata->ext_clk_hz;
+ if (!IS_ERR(st->mclk)) {
+ ret = clk_prepare_enable(st->mclk);
+ if (ret < 0)
+ goto error_disable_reg;
+ ext_clk_hz = clk_get_rate(st->mclk);
+ }
+
+ if (ext_clk_hz) {
+ st->mclk_hz = ext_clk_hz;
st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK;
} else {
st->mclk_hz = AD5933_INT_OSC_FREQ_Hz;
@@ -746,7 +742,7 @@ static int ad5933_probe(struct i2c_client *client,
ret = ad5933_register_ring_funcs_and_init(indio_dev);
if (ret)
- goto error_disable_reg;
+ goto error_disable_mclk;
ret = ad5933_setup(st);
if (ret)
@@ -760,6 +756,8 @@ static int ad5933_probe(struct i2c_client *client,
error_unreg_ring:
iio_kfifo_free(indio_dev->buffer);
+error_disable_mclk:
+ clk_disable_unprepare(st->mclk);
error_disable_reg:
regulator_disable(st->reg);
@@ -774,6 +772,7 @@ static int ad5933_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_kfifo_free(indio_dev->buffer);
regulator_disable(st->reg);
+ clk_disable_unprepare(st->mclk);
return 0;
}
diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile
index 07dc16cc86f5..412e2105a3a5 100644
--- a/drivers/staging/ks7010/Makefile
+++ b/drivers/staging/ks7010/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_KS7010) += ks7010.o
-ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o
+ks7010-y := ks_hostif.o ks_wlan_net.o ks7010_sdio.o
diff --git a/drivers/staging/ks7010/TODO b/drivers/staging/ks7010/TODO
index d393ca58e231..87a6dac4890d 100644
--- a/drivers/staging/ks7010/TODO
+++ b/drivers/staging/ks7010/TODO
@@ -27,8 +27,6 @@ Now the TODOs:
- fix the 'card removal' event when card is inserted when booting
- check what other upstream wireless mechanisms can be used instead of the
custom ones here
-- replace custom Michael MIC implementation with the kernel
- implementation. This task is only required for a *clean* WEXT interface.
Please send any patches to:
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c
index 065bce193fac..06ebea0be118 100644
--- a/drivers/staging/ks7010/ks_hostif.c
+++ b/drivers/staging/ks7010/ks_hostif.c
@@ -6,15 +6,18 @@
* Copyright (C) 2009 Renesas Technology Corp.
*/
+#include <crypto/hash.h>
#include <linux/circ_buf.h>
#include <linux/if_arp.h>
#include <net/iw_handler.h>
#include <uapi/linux/llc.h>
#include "eap_packet.h"
#include "ks_wlan.h"
-#include "michael_mic.h"
#include "ks_hostif.h"
+#define MICHAEL_MIC_KEY_LEN 8
+#define MICHAEL_MIC_LEN 8
+
static inline void inc_smeqhead(struct ks_wlan_private *priv)
{
priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE;
@@ -35,7 +38,7 @@ static inline u8 get_byte(struct ks_wlan_private *priv)
{
u8 data;
- data = *(priv->rxp)++;
+ data = *priv->rxp++;
/* length check in advance ! */
--(priv->rx_size);
return data;
@@ -171,7 +174,7 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info *ap_info)
"- rate_set_size=%d\n",
ap->bssid[0], ap->bssid[1], ap->bssid[2],
ap->bssid[3], ap->bssid[4], ap->bssid[5],
- &(ap->ssid.body[0]),
+ &ap->ssid.body[0],
ap->rate_set.body[0], ap->rate_set.body[1],
ap->rate_set.body[2], ap->rate_set.body[3],
ap->rate_set.body[4], ap->rate_set.body[5],
@@ -191,6 +194,68 @@ static u8 read_ie(unsigned char *bp, u8 max, u8 *body)
return size;
}
+static int
+michael_mic(u8 *key, u8 *data, unsigned int len, u8 priority, u8 *result)
+{
+ u8 pad_data[4] = { priority, 0, 0, 0 };
+ struct crypto_shash *tfm = NULL;
+ struct shash_desc *desc = NULL;
+ int ret;
+
+ tfm = crypto_alloc_shash("michael_mic", 0, 0);
+ if (IS_ERR(tfm)) {
+ ret = PTR_ERR(tfm);
+ goto err;
+ }
+
+ ret = crypto_shash_setkey(tfm, key, MICHAEL_MIC_KEY_LEN);
+ if (ret < 0)
+ goto err_free_tfm;
+
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!desc) {
+ ret = -ENOMEM;
+ goto err_free_tfm;
+ }
+
+ desc->tfm = tfm;
+ desc->flags = 0;
+
+ ret = crypto_shash_init(desc);
+ if (ret < 0)
+ goto err_free_desc;
+
+ // Compute the MIC value
+ /*
+ * IEEE802.11i page 47
+ * Figure 43g TKIP MIC processing format
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7|
+ * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
+ */
+
+ ret = crypto_shash_update(desc, data, 12);
+ if (ret < 0)
+ goto err_free_desc;
+
+ ret = crypto_shash_update(desc, pad_data, 4);
+ if (ret < 0)
+ goto err_free_desc;
+
+ ret = crypto_shash_finup(desc, data + 12, len - 12, result);
+
+err_free_desc:
+ kzfree(desc);
+
+err_free_tfm:
+ crypto_free_shash(tfm);
+
+err:
+ return ret;
+}
+
static
int get_ap_information(struct ks_wlan_private *priv, struct ap_info *ap_info,
struct local_ap *ap)
@@ -273,11 +338,11 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
{
struct ether_hdr *eth_hdr;
unsigned short eth_proto;
- unsigned char recv_mic[8];
+ unsigned char recv_mic[MICHAEL_MIC_LEN];
char buf[128];
unsigned long now;
struct mic_failure *mic_failure;
- struct michael_mic michael_mic;
+ u8 mic[MICHAEL_MIC_LEN];
union iwreq_data wrqu;
unsigned int key_index = auth_type - 1;
struct wpa_key *key = &priv->wpa.key[key_index];
@@ -300,14 +365,20 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv,
netdev_dbg(priv->net_dev, "TKIP: protocol=%04X: size=%u\n",
eth_proto, priv->rx_size);
/* MIC save */
- memcpy(&recv_mic[0], (priv->rxp) + ((priv->rx_size) - 8), 8);
- priv->rx_size = priv->rx_size - 8;
+ memcpy(&recv_mic[0],
+ (priv->rxp) + ((priv->rx_size) - sizeof(recv_mic)),
+ sizeof(recv_mic));
+ priv->rx_size = priv->rx_size - sizeof(recv_mic);
if (auth_type > 0 && auth_type < 4) { /* auth_type check */
- michael_mic_function(&michael_mic, key->rx_mic_key,
- priv->rxp, priv->rx_size,
- 0, michael_mic.result);
+ int ret;
+
+ ret = michael_mic(key->rx_mic_key,
+ priv->rxp, priv->rx_size,
+ 0, mic);
+ if (ret < 0)
+ return ret;
}
- if (memcmp(michael_mic.result, recv_mic, 8) != 0) {
+ if (memcmp(mic, recv_mic, sizeof(mic)) != 0) {
now = jiffies;
mic_failure = &priv->wpa.mic_failure;
/* MIC FAILURE */
@@ -730,9 +801,9 @@ void hostif_scan_indication(struct ks_wlan_private *priv)
priv->scan_ind_count++;
if (priv->scan_ind_count < LOCAL_APLIST_MAX + 1) {
netdev_dbg(priv->net_dev, " scan_ind_count=%d :: aplist.size=%d\n",
- priv->scan_ind_count, priv->aplist.size);
+ priv->scan_ind_count, priv->aplist.size);
get_ap_information(priv, (struct ap_info *)(priv->rxp),
- &(priv->aplist.ap[priv->scan_ind_count - 1]));
+ &priv->aplist.ap[priv->scan_ind_count - 1]);
priv->aplist.size = priv->scan_ind_count;
} else {
netdev_dbg(priv->net_dev, " count over :: scan_ind_count=%d\n",
@@ -1002,7 +1073,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
int result = 0;
unsigned short eth_proto;
struct ether_hdr *eth_hdr;
- struct michael_mic michael_mic;
unsigned short keyinfo = 0;
struct ieee802_1x_hdr *aa1x_hdr;
struct wpa_eapol_key *eap_key;
@@ -1109,17 +1179,20 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb)
pp->auth_type = cpu_to_le16(TYPE_AUTH);
} else {
if (priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP) {
- michael_mic_function(&michael_mic,
- priv->wpa.key[0].tx_mic_key,
- &pp->data[0], skb_len,
- 0, michael_mic.result);
- memcpy(p, michael_mic.result, 8);
- length += 8;
- skb_len += 8;
- p += 8;
+ u8 mic[MICHAEL_MIC_LEN];
+
+ ret = michael_mic(priv->wpa.key[0].tx_mic_key,
+ &pp->data[0], skb_len,
+ 0, mic);
+ if (ret < 0)
+ goto err_kfree;
+
+ memcpy(p, mic, sizeof(mic));
+ length += sizeof(mic);
+ skb_len += sizeof(mic);
+ p += sizeof(mic);
pp->auth_type =
cpu_to_le16(TYPE_DATA);
-
} else if (priv->wpa.pairwise_suite ==
IW_AUTH_CIPHER_CCMP) {
pp->auth_type =
diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c
index dc5459ae0b51..3cffc8be6656 100644
--- a/drivers/staging/ks7010/ks_wlan_net.c
+++ b/drivers/staging/ks7010/ks_wlan_net.c
@@ -182,7 +182,7 @@ static int ks_wlan_set_freq(struct net_device *dev,
/* for SLEEP MODE */
/* If setting by frequency, convert to a channel */