aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-04 21:40:53 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-04 21:40:53 -0800
commit118c216e16c5ccb028cd03a0dcd56d17a07ff8d7 (patch)
tree94769cd9af230aec964d95f380b1119bb8d8edf0 /drivers
parentfd0d351de7bbd718bc2b34d5846854831aa2b88c (diff)
parente3cc3136df33de1aa26d606f2a42cac3fd30cf54 (diff)
Merge tag 'staging-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver updates from Greg KH: "Here's the big staging driver update for 4.4-rc1. If you were disappointed for 4.3-rc1 that we didn't contribute enough changesets, you should be happy with this pull request of over 2400 patches. But overall we removed more lines of code than we added, which is nice to see. Full details in the shortlog. All of these have been in linux-next for a while" Greg, I've never been disappointed in how few commits Staging contributes to the kernel.. Never. * tag 'staging-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (2431 commits) Staging: rtl8192u: ieee80211: added missing blank lines Staging: rtl8192u: ieee80211: removed unnecessary braces Staging: rtl8192u: ieee80211: corrected block comments Staging: rtl8192u: ieee80211: corrected indent Staging: rtl8192u: ieee80211: added missing spaces after if Staging: rtl8192u: ieee80211: added missing space around '=' Staging: rtl8192u: ieee80211: fixed position of else statements Staging: rtl8192u: ieee80211: fixed open brace positions staging: rdma: ipath: Remove unneeded vairable. staging: rtl8188eu: pwrGrpCnt variable removed in store_pwrindex_offset function staging: rtl8188eu: new variable for hal_data->MCSTxPowerLevelOriginalOffset[pwrGrpCnt] in store_pwrindex_offset function staging: rtl8188eu: checkpatch fixes: 'Avoid CamelCase' in hal/bb_cfg.c staging: rtl8188eu: checkpatch fixes: line over 80 characters splited into two parts staging: rtl8188eu: checkpatch fixes: alignment should match open parenthesis staging: rtl8188eu: checkpatch fixes: unnecessary parentheses removed in hal/bb_cfg.c staging: rtl8188eu: checkpatch fixes: spaces preferred around that '|' in hal/bb_cfg.c staging: rtl8188eu: operator = replaced by += in loop increment staging: rtl8188eu: occurrence of the 5 GHz code marked staging: rtl8188eu: increment placed into for loop header staging: rtl8188eu: while loop replaced by for loop in rtw_restruct_wmm_ie ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iio/Kconfig30
-rw-r--r--drivers/iio/Makefile7
-rw-r--r--drivers/iio/accel/Kconfig33
-rw-r--r--drivers/iio/accel/Makefile6
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c (renamed from drivers/iio/accel/bmc150-accel.c)407
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c102
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c91
-rw-r--r--drivers/iio/accel/bmc150-accel.h20
-rw-r--r--drivers/iio/accel/kxcjk-1013.c34
-rw-r--r--drivers/iio/accel/mma8452.c356
-rw-r--r--drivers/iio/accel/mma9553.c29
-rw-r--r--drivers/iio/accel/mxc4005.c567
-rw-r--r--drivers/iio/accel/st_accel_core.c1
-rw-r--r--drivers/iio/accel/stk8312.c30
-rw-r--r--drivers/iio/accel/stk8ba50.c30
-rw-r--r--drivers/iio/adc/Kconfig35
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad799x.c1
-rw-r--r--drivers/iio/adc/berlin2-adc.c91
-rw-r--r--drivers/iio/adc/hi8435.c534
-rw-r--r--drivers/iio/adc/max1027.c1
-rw-r--r--drivers/iio/adc/max1363.c1
-rw-r--r--drivers/iio/adc/mcp320x.c1
-rw-r--r--drivers/iio/adc/ti-adc128s052.c8
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c1
-rw-r--r--drivers/iio/adc/vf610_adc.c101
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c37
-rw-r--r--drivers/iio/adc/xilinx-xadc.h2
-rw-r--r--drivers/iio/amplifiers/ad8366.c1
-rw-r--r--drivers/iio/buffer/Kconfig24
-rw-r--r--drivers/iio/buffer/Makefile8
-rw-r--r--drivers/iio/buffer/industrialio-buffer-cb.c (renamed from drivers/iio/buffer_cb.c)12
-rw-r--r--drivers/iio/buffer/industrialio-triggered-buffer.c (renamed from drivers/iio/industrialio-triggered-buffer.c)0
-rw-r--r--drivers/iio/buffer/kfifo_buf.c (renamed from drivers/iio/kfifo_buf.c)0
-rw-r--r--drivers/iio/chemical/Kconfig15
-rw-r--r--drivers/iio/chemical/Makefile6
-rw-r--r--drivers/iio/chemical/vz89x.c256
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/ms_sensors/Kconfig6
-rw-r--r--drivers/iio/common/ms_sensors/Makefile5
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.c652
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.h66
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c22
-rw-r--r--drivers/iio/dac/ad5504.c1
-rw-r--r--drivers/iio/dac/ad7303.c7
-rw-r--r--drivers/iio/dac/m62332.c63
-rw-r--r--drivers/iio/dac/max5821.c1
-rw-r--r--drivers/iio/frequency/adf4350.c9
-rw-r--r--drivers/iio/gyro/Kconfig19
-rw-r--r--drivers/iio/gyro/Makefile4
-rw-r--r--drivers/iio/gyro/bmg160.h10
-rw-r--r--drivers/iio/gyro/bmg160_core.c (renamed from drivers/iio/gyro/bmg160.c)361
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c71
-rw-r--r--drivers/iio/gyro/bmg160_spi.c57
-rw-r--r--drivers/iio/gyro/st_gyro_core.c1
-rw-r--r--drivers/iio/humidity/Kconfig23
-rw-r--r--drivers/iio/humidity/Makefile2
-rw-r--r--drivers/iio/humidity/hdc100x.c320
-rw-r--r--drivers/iio/humidity/htu21.c253
-rw-r--r--drivers/iio/humidity/si7020.c6
-rw-r--r--drivers/iio/imu/kmx61.c28
-rw-r--r--drivers/iio/industrialio-core.c10
-rw-r--r--drivers/iio/industrialio-trigger.c12
-rw-r--r--drivers/iio/industrialio-triggered-event.c68
-rw-r--r--drivers/iio/light/Kconfig23
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/apds9960.c1130
-rw-r--r--drivers/iio/light/opt3001.c1
-rw-r--r--drivers/iio/light/stk3310.c98
-rw-r--r--drivers/iio/light/tsl4531.c9
-rw-r--r--drivers/iio/light/us5182d.c507
-rw-r--r--drivers/iio/magnetometer/Kconfig33
-rw-r--r--drivers/iio/magnetometer/Makefile3
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c29
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c1
-rw-r--r--drivers/iio/potentiometer/Kconfig20
-rw-r--r--drivers/iio/potentiometer/Makefile6
-rw-r--r--drivers/iio/potentiometer/mcp4531.c231
-rw-r--r--drivers/iio/pressure/Kconfig13
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/ms5637.c190
-rw-r--r--drivers/iio/pressure/st_pressure_core.c1
-rw-r--r--drivers/iio/proximity/Kconfig12
-rw-r--r--drivers/iio/proximity/Makefile1
-rw-r--r--drivers/iio/proximity/as3935.c7
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c289
-rw-r--r--drivers/iio/proximity/sx9500.c9
-rw-r--r--drivers/iio/temperature/Kconfig22
-rw-r--r--drivers/iio/temperature/Makefile2
-rw-r--r--drivers/iio/temperature/mlx90614.c92
-rw-r--r--drivers/iio/temperature/tsys01.c230
-rw-r--r--drivers/iio/temperature/tsys02d.c191
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/android/Kconfig2
-rw-r--r--drivers/staging/android/ashmem.c44
-rw-r--r--drivers/staging/android/ion/compat_ion.h1
-rw-r--r--drivers/staging/android/ion/ion.c49
-rw-r--r--drivers/staging/android/ion/ion.h10
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c6
-rw-r--r--drivers/staging/android/ion/ion_heap.c4
-rw-r--r--drivers/staging/android/ion/ion_page_pool.c10
-rw-r--r--drivers/staging/android/ion/ion_priv.h3
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c7
-rw-r--r--drivers/staging/android/ion/tegra/Makefile2
-rw-r--r--drivers/staging/android/lowmemorykiller.c30
-rw-r--r--drivers/staging/android/sw_sync.c17
-rw-r--r--drivers/staging/android/timed_output.c16
-rw-r--r--drivers/staging/android/uapi/ion.h25
-rw-r--r--drivers/staging/board/board.c6
-rw-r--r--drivers/staging/comedi/Kconfig10
-rw-r--r--drivers/staging/comedi/comedi_buf.c125
-rw-r--r--drivers/staging/comedi/comedi_fops.c180
-rw-r--r--drivers/staging/comedi/comedi_internal.h1
-rw-r--r--drivers/staging/comedi/comedi_pci.c108
-rw-r--r--drivers/staging/comedi/comedi_pcmcia.c104
-rw-r--r--drivers/staging/comedi/comedi_usb.c75
-rw-r--r--drivers/staging/comedi/comedidev.h635
-rw-r--r--drivers/staging/comedi/drivers.c407
-rw-r--r--drivers/staging/comedi/drivers/8255.h12
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c4
-rw-r--r--drivers/staging/comedi/drivers/Makefile1
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c7
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c16
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c59
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c6
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c171
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c289
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c136
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c304
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c33
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c15
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c201
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c284
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c1175
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c565
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c8
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c466
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c66
-rw-r--r--drivers/staging/comedi/drivers/fl512.c2
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c28
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c517
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c84
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c7
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c315
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c137
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c411
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c358
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_usb6501.c16
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c19
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c186
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c109
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c40
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c112
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c684
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c369
-rw-r--r--drivers/staging/comedi/drivers/rti800.c28
-rw-r--r--drivers/staging/comedi/drivers/s526.c560
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c51
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c57
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c506
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c164
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c310
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c142
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c127
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c32
-rw-r--r--drivers/staging/dgap/dgap.c532
-rw-r--r--drivers/staging/dgap/dgap.h4
-rw-r--r--drivers/staging/dgnc/dgnc_cls.c50
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c52
-rw-r--r--drivers/staging/dgnc/dgnc_driver.h59
-rw-r--r--drivers/staging/dgnc/dgnc_mgmt.c15
-rw-r--r--drivers/staging/dgnc/dgnc_neo.c65
-rw-r--r--drivers/staging/dgnc/dgnc_sysfs.c95
-rw-r--r--drivers/staging/dgnc/dgnc_tty.c324
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c183
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.h30
-rw-r--r--drivers/staging/fbtft/Kconfig10
-rw-r--r--drivers/staging/fbtft/Makefile1
-rw-r--r--drivers/staging/fbtft/fb_agm1264k-fl.c17
-rw-r--r--drivers/staging/fbtft/fb_bd663474.c11
-rw-r--r--drivers/staging/fbtft/fb_hx8340bn.c16
-rw-r--r--drivers/staging/fbtft/fb_hx8347d.c16
-rw-r--r--drivers/staging/fbtft/fb_hx8353d.c21
-rw-r--r--drivers/staging/fbtft/fb_hx8357d.c12
-rw-r--r--drivers/staging/fbtft/fb_ili9163.c13
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c21
-rw-r--r--drivers/staging/fbtft/fb_ili9325.c20
-rw-r--r--drivers/staging/fbtft/fb_ili9340.c14
-rw-r--r--drivers/staging/fbtft/fb_ili9341.c20
-rw-r--r--drivers/staging/fbtft/fb_ili9481.c10
-rw-r--r--drivers/staging/fbtft/fb_ili9486.c12
-rw-r--r--drivers/staging/fbtft/fb_pcd8544.c25
-rw-r--r--drivers/staging/fbtft/fb_ra8875.c40
-rw-r--r--drivers/staging/fbtft/fb_s6d02a1.c16
-rw-r--r--drivers/staging/fbtft/fb_s6d1121.c18
-rw-r--r--drivers/staging/fbtft/fb_ssd1289.c20
-rw-r--r--drivers/staging/fbtft/fb_ssd1306.c25
-rw-r--r--drivers/staging/fbtft/fb_ssd1331.c11
-rw-r--r--drivers/staging/fbtft/fb_ssd1351.c67
-rw-r--r--drivers/staging/fbtft/fb_st7735r.c22
-rw-r--r--drivers/staging/fbtft/fb_st7789v.c265
-rw-r--r--drivers/staging/fbtft/fb_tinylcd.c14
-rw-r--r--drivers/staging/fbtft/fb_tls8204.c24
-rw-r--r--drivers/staging/fbtft/fb_uc1611.c12
-rw-r--r--drivers/staging/fbtft/fb_uc1701.c25
-rw-r--r--drivers/staging/fbtft/fb_upd161704.c11
-rw-r--r--drivers/staging/fbtft/fb_watterott.c38
-rw-r--r--drivers/staging/fbtft/fbtft-bus.c27
-rw-r--r--drivers/staging/fbtft/fbtft-core.c135
-rw-r--r--drivers/staging/fbtft/fbtft-sysfs.c6
-rw-r--r--drivers/staging/fbtft/fbtft.h11
-rw-r--r--drivers/staging/fbtft/fbtft_device.c171
-rw-r--r--drivers/staging/fbtft/flexfb.c10
-rw-r--r--drivers/staging/fsl-mc/bus/dpbp.c356
-rw-r--r--drivers/staging/fsl-mc/bus/dpmcp-cmd.h81
-rw-r--r--drivers/staging/fsl-mc/bus/dpmcp.c316
-rw-r--r--drivers/staging/fsl-mc/bus/dpmcp.h220
-rw-r--r--drivers/staging/fsl-mc/bus/dpmng.c31
-rw-r--r--drivers/staging/fsl-mc/bus/dprc-cmd.h7
-rw-r--r--drivers/staging/fsl-mc/bus/dprc-driver.c12
-rw-r--r--drivers/staging/fsl-mc/bus/dprc.c955
-rw-r--r--drivers/staging/fsl-mc/bus/mc-allocator.c98
-rw-r--r--drivers/staging/fsl-mc/bus/mc-bus.c136
-rw-r--r--drivers/staging/fsl-mc/bus/mc-sys.c208
-rw-r--r--drivers/staging/fsl-mc/include/dpbp-cmd.h2
-rw-r--r--drivers/staging/fsl-mc/include/dpbp.h303
-rw-r--r--drivers/staging/fsl-mc/include/dpcon-cmd.h62
-rw-r--r--drivers/staging/fsl-mc/include/dpmng.h33
-rw-r--r--drivers/staging/fsl-mc/include/dprc.h638
-rw-r--r--drivers/staging/fsl-mc/include/mc-cmd.h52
-rw-r--r--drivers/staging/fsl-mc/include/mc-private.h19
-rw-r--r--drivers/staging/fsl-mc/include/mc-sys.h55
-rw-r--r--drivers/staging/fsl-mc/include/mc.h18
-rw-r--r--drivers/staging/ft1000/Kconfig22
-rw-r--r--drivers/staging/ft1000/Makefile3
-rw-r--r--drivers/staging/ft1000/TODO9
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/Makefile2
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/boot.h158
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000.h70
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000.imgbin305770 -> 0 bytes
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_cs.c158
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c769
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c2068
-rw-r--r--drivers/staging/ft1000/ft1000-usb/Makefile3
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_debug.c789
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_download.c1058
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c1586
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h123
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.c252
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.h150
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft3000.imgbin280414 -> 0 bytes
-rw-r--r--drivers/staging/ft1000/ft1000.h366
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c54
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c28
-rw-r--r--drivers/staging/gdm724x/gdm_tty.c8
-rw-r--r--drivers/staging/gdm724x/gdm_usb.c56
-rw-r--r--drivers/staging/gdm724x/netlink_k.c10
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c4
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c20
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.c16
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c22
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.c4
-rw-r--r--drivers/staging/gdm72xx/usb_boot.c8
-rw-r--r--drivers/staging/goldfish/goldfish_nand.c4
-rw-r--r--drivers/staging/goldfish/goldfish_nand_reg.h10
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c10
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c30
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c65
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c19
-rw-r--r--drivers/staging/iio/adc/ad7192.c64
-rw-r--r--drivers/staging/iio/adc/ad7192.h2
-rw-r--r--drivers/staging/iio/adc/ad7280a.c180
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c23
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c15
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c5
-rw-r--r--drivers/staging/iio/adc/ad7780.c13
-rw-r--r--drivers/staging/iio/adc/ad7816.c58
-rw-r--r--drivers/staging/iio/adc/lpc32xx_adc.c18
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c185
-rw-r--r--drivers/staging/iio/adc/spear_adc.c4
-rw-r--r--drivers/staging/iio/addac/adt7316.c16
-rw-r--r--drivers/staging/iio/cdc/ad7150.c19
-rw-r--r--drivers/staging/iio/cdc/ad7152.c14
-rw-r--r--drivers/staging/iio/cdc/ad7746.c49
-rw-r--r--drivers/staging/iio/frequency/ad9834.c2
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c16
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.c26
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c11
-rw-r--r--drivers/staging/iio/iio_simple_dummy.h17
-rw-r--r--drivers/staging/iio/iio_simple_dummy_buffer.c8
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c19
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c11
-rw-r--r--drivers/staging/iio/light/isl29018.c6
-rw-r--r--drivers/staging/iio/light/isl29028.c11
-rw-r--r--drivers/staging/iio/light/tsl2583.c16
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c14
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.h2
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843_core.c6
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843_i2c.c2
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843_spi.c4
-rw-r--r--drivers/staging/iio/meter/ade7753.c10
-rw-r--r--drivers/staging/iio/meter/ade7754.c8
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c6
-rw-r--r--drivers/staging/iio/meter/ade7759.c10
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c2
-rw-r--r--drivers/staging/iio/meter/ade7854.c6
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c2
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c10
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c4
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h13
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h1
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h189
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h13
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_string.h5
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_time.h49
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h3
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h35
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h6
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h2
-rw-r--r--drivers/staging/lustre/include/linux/lnet/nidstr.h47
-rw-r--r--drivers/staging/lustre/include/linux/lnet/types.h2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c44
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h289
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c65
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c1
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c61
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h6
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c21
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c6
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c1
-rw-r--r--drivers/staging/lustre/lnet/lnet/Makefile2
-rw-r--r--drivers/staging/lustre/lnet/lnet/acceptor.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/api-ni.c18
-rw-r--r--drivers/staging/lustre/lnet/lnet/config.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-eq.c12
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-move.c7
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/nidstrings.c1260
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c15
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c45
-rw-r--r--drivers/staging/lustre/lnet/selftest/brw_test.c6
-rw-r--r--drivers/staging/lustre/lnet/selftest/conctl.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c18
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.h5
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c20
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.h3
-rw-r--r--drivers/staging/lustre/lnet/selftest/framework.c12
-rw-r--r--drivers/staging/lustre/lnet/selftest/module.c1
-rw-r--r--drivers/staging/lustre/lnet/selftest/ping_test.c16
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c11
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.h1
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h27
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.c17
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.h2
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c132
-rw-r--r--drivers/staging/lustre/lustre/fid/lproc_fid.c3
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c3
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h3
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c1
-rw-r--r--drivers/staging/lustre/lustre/fld/lproc_fld.c1
-rw-r--r--drivers/staging/lustre/lustre/include/cl_object.h59
-rw-r--r--drivers/staging/lustre/lustre/include/dt_object.h1496
-rw-r--r--drivers/staging/lustre/lustre/include/interval_tree.h36
-rw-r--r--drivers/staging/lustre/lustre/include/lclient.h28
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_compat25.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_lite.h4
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h1
-rw-r--r--drivers/staging/lustre/lustre/include/linux/obd.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h61
-rw-r--r--drivers/staging/lustre/lustre/include/lu_object.h61
-rw-r--r--drivers/staging/lustre/lustre/include/lu_ref.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/libiam.h145
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/ll_fiemap.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h98
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_lfsck_user.h95
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_user.h40
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_capa.h305
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_cfg.h10
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_debug.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_disk.h159
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm.h117
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_dlm_flags.h228
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_eacl.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_export.h37
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h96
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fld.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_ha.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_handles.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_import.h22
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lib.h19
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_lite.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_log.h167
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mdc.h1
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_mds.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_net.h152
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_param.h12
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_req_layout.h11
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_sec.h48
-rw-r--r--drivers/staging/lustre/lustre/include/obd.h188
-rw-r--r--drivers/staging/lustre/lustre/include/obd_cache.h39
-rw-r--r--drivers/staging/lustre/lustre/include/obd_cksum.h1
-rw-r--r--drivers/staging/lustre/lustre/include/obd_class.h236
-rw-r--r--drivers/staging/lustre/lustre/include/obd_support.h284
-rw-r--r--drivers/staging/lustre/lustre/lclient/glimpse.c6
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c102
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_misc.c1
-rw-r--r--drivers/staging/lustre/lustre/ldlm/interval_tree.c274
-rw-r--r--drivers/staging/lustre/lustre/ldlm/l_lock.c7
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_extent.c27
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_flock.c278
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_inodebits.c1
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_internal.h36
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lib.c38
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lock.c391
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c132
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_plain.c1
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c441
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_request.c380
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c209
-rw-r--r--drivers/staging/lustre/lustre/libcfs/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c5
-rw-r--r--drivers/staging/lustre/lustre/libcfs/fail.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c131
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_lock.c8
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_mem.c10
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c144
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-crypto-adler.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c9
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-module.c1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c70
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c32
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c185
-rw-r--r--drivers/staging/lustre/lustre/libcfs/nidstrings.c842
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c6
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.h3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/workitem.c16
-rw-r--r--drivers/staging/lustre/lustre/llite/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c15
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c81
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_capa.c661
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_close.c9
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h49
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c179
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c9
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_rmtacl.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c5
-rw-r--r--drivers/staging/lustre/lustre/llite/lproc_llite.c38
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c58
-rw-r--r--drivers/staging/lustre/lustre/llite/remote_perm.c16
-rw-r--r--drivers/staging/lustre/lustre/llite/rw.c42
-rw-r--r--drivers/staging/lustre/lustre/llite/rw26.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c40
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c42
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_dev.c11
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_internal.h1
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c10
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_lock.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_object.c13
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_page.c1
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c19
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr_cache.c24
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c78
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_cl_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_dev.c15
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_ea.c7
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_io.c9
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_lock.c21
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_obd.c52
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_object.c18
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pack.c22
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_page.c2
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_pool.c32
-rw-r--r--drivers/staging/lustre/lustre/lov/lov_request.c17
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_dev.c5
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_lock.c4
-rw-r--r--drivers/staging/lustre/lustre/lov/lovsub_object.c6
-rw-r--r--drivers/staging/lustre/lustre/lov/lproc_lov.c5
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_internal.h18
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c50
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c47
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_reint.c24
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c258
-rw-r--r--drivers/staging/lustre/lustre/mgc/lproc_mgc.c1
-rw-r--r--drivers/staging/lustre/lustre/mgc/mgc_request.c63
-rw-r--r--drivers/staging/lustre/lustre/obdclass/Makefile2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/acl.c120
-rw-r--r--drivers/staging/lustre/lustre/obdclass/capa.c421
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_io.c106
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_lock.c49
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c68
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_page.c5
-rw-r--r--drivers/staging/lustre/lustre/obdclass/class_obd.c119
-rw-r--r--drivers/staging/lustre/lustre/obdclass/debug.c10
-rw-r--r--drivers/staging/lustre/lustre/obdclass/dt_object.c1054
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c600
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c3
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c137
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog.c549
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_cat.c590
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_internal.h21
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_obd.c31
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_swab.c7
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_counters.c9
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c440
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lu_object.c383
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lustre_handles.c22
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_config.c468
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c162
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obdo.c173
-rw-r--r--drivers/staging/lustre/lustre/obdclass/statfs_pack.c14
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c45
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_internal.h1
-rw-r--r--drivers/staging/lustre/lustre/osc/lproc_osc.c46
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c44
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cl_internal.h3
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_dev.c8
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_internal.h7
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_io.c14
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_lock.c4
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_object.c6
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_page.c9
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_quota.c11
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c238
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c512
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/connection.c10
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/events.c12
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/import.c70
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c144
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/llog_client.c37
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c134
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/niobuf.c22
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/nrs.c129
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pack_generic.c362
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pers.c1
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/pinger.c170
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h19
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c740
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec.c165
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c358
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_config.c78
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_gc.c25
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_lproc.c6
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_null.c4
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_plain.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/service.c526
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/wiretest.c6
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c60
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c2
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c12
-rw-r--r--drivers/staging/media/omap4iss/iss.c40
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c6
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.h4
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c26
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.h4
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c24
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.h8
-rw-r--r--drivers/staging/media/omap4iss/iss_regs.h316
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c28
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.h6
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c19
-rw-r--r--drivers/staging/most/Documentation/ABI/sysfs-class-most.txt2
-rw-r--r--drivers/staging/most/aim-cdev/cdev.c68
-rw-r--r--drivers/staging/most/aim-network/networking.c53
-rw-r--r--drivers/staging/most/aim-sound/sound.c114
-rw-r--r--drivers/staging/most/aim-v4l2/Makefile1
-rw-r--r--drivers/staging/most/aim-v4l2/video.c50
-rw-r--r--drivers/staging/most/hdm-dim2/Kconfig2
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hal.c62
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hal.h5
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hdm.c79
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_hdm.h3
-rw-r--r--drivers/staging/most/hdm-dim2/dim2_sysfs.c3
-rw-r--r--drivers/staging/most/hdm-i2c/hdm_i2c.c45
-rw-r--r--drivers/staging/most/hdm-usb/hdm_usb.c162
-rw-r--r--drivers/staging/most/mostcore/core.c230
-rw-r--r--drivers/staging/most/mostcore/mostcore.h13
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.c66
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.h18
-rw-r--r--drivers/staging/netlogic/platform_net.c1
-rw-r--r--drivers/staging/netlogic/xlr_net.h3
-rw-r--r--drivers/staging/nvec/nvec.c1
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c7
-rw-r--r--drivers/staging/octeon/Makefile2
-rw-r--r--drivers/staging/octeon/ethernet-defines.h5
-rw-r--r--drivers/staging/octeon/ethernet-rgmii.c2
-rw-r--r--drivers/staging/octeon/ethernet-rx.c10
-rw-r--r--drivers/staging/octeon/ethernet-sgmii.c2
-rw-r--r--drivers/staging/octeon/ethernet-tx.c8
-rw-r--r--drivers/staging/octeon/ethernet-xaui.c42
-rw-r--r--drivers/staging/octeon/ethernet.c42
-rw-r--r--drivers/staging/octeon/octeon-ethernet.h6
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c36
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.h4
-rw-r--r--drivers/staging/panel/panel.c138
-rw-r--r--drivers/staging/rdma/Kconfig2
-rw-r--r--drivers/staging/rdma/amso1100/c2.c6
-rw-r--r--drivers/staging/rdma/amso1100/c2_ae.c6
-rw-r--r--drivers/staging/rdma/amso1100/c2_alloc.c2
-rw-r--r--drivers/staging/rdma/amso1100/c2_cm.c3
-rw-r--r--drivers/staging/rdma/amso1100/c2_cq.c12
-rw-r--r--drivers/staging/rdma/amso1100/c2_intr.c2
-rw-r--r--drivers/staging/rdma/amso1100/c2_mm.c10
-rw-r--r--drivers/staging/rdma/amso1100/c2_mq.c1
-rw-r--r--drivers/staging/rdma/amso1100/c2_provider.c10
-rw-r--r--drivers/staging/rdma/amso1100/c2_qp.c20
-rw-r--r--drivers/staging/rdma/amso1100/c2_rnic.c28
-rw-r--r--drivers/staging/rdma/ehca/ehca_cq.c13
-rw-r--r--drivers/staging/rdma/hfi1/chip.c196
-rw-r--r--drivers/staging/rdma/hfi1/chip.h2
-rw-r--r--drivers/staging/rdma/hfi1/common.h4
-rw-r--r--drivers/staging/rdma/hfi1/device.c2
-rw-r--r--drivers/staging/rdma/hfi1/diag.c9
-rw-r--r--drivers/staging/rdma/hfi1/driver.c83
-rw-r--r--drivers/staging/rdma/hfi1/file_ops.c18
-rw-r--r--drivers/staging/rdma/hfi1/firmware.c37
-rw-r--r--drivers/staging/rdma/hfi1/hfi.h22
-rw-r--r--drivers/staging/rdma/hfi1/init.c30
-rw-r--r--drivers/staging/rdma/hfi1/mad.c20
-rw-r--r--drivers/staging/rdma/hfi1/mr.c28
-rw-r--r--drivers/staging/rdma/hfi1/pcie.c15
-rw-r--r--drivers/staging/rdma/hfi1/pio.c21
-rw-r--r--drivers/staging/rdma/hfi1/qp.h15
-rw-r--r--drivers/staging/rdma/hfi1/qsfp.c13
-rw-r--r--drivers/staging/rdma/hfi1/rc.c25
-rw-r--r--drivers/staging/rdma/hfi1/ruc.c25
-rw-r--r--drivers/staging/rdma/hfi1/sdma.c168
-rw-r--r--drivers/staging/rdma/hfi1/sdma.h74
-rw-r--r--drivers/staging/rdma/hfi1/sysfs.c2
-rw-r--r--drivers/staging/rdma/hfi1/trace.c4
-rw-r--r--drivers/staging/rdma/hfi1/trace.h48
-rw-r--r--drivers/staging/rdma/hfi1/user_sdma.c124
-rw-r--r--drivers/staging/rdma/hfi1/verbs.c19
-rw-r--r--drivers/staging/rdma/hfi1/verbs.h3
-rw-r--r--drivers/staging/rdma/ipath/ipath_driver.c27
-rw-r--r--drivers/staging/rdma/ipath/ipath_eeprom.c2
-rw-r--r--drivers/staging/rdma/ipath/ipath_file_ops.c15
-rw-r--r--drivers/staging/rdma/ipath/ipath_fs.c13
-rw-r--r--drivers/staging/rdma/ipath/ipath_iba6110.c7
-rw-r--r--drivers/staging/rdma/ipath/ipath_init_chip.c32
-rw-r--r--drivers/staging/rdma/ipath/ipath_intr.c8
-rw-r--r--drivers/staging/rdma/ipath/ipath_kernel.h3
-rw-r--r--drivers/staging/rdma/ipath/ipath_qp.c3
-rw-r--r--drivers/staging/rdma/ipath/ipath_ruc.c1
-rw-r--r--drivers/staging/rdma/ipath/ipath_sdma.c6
-rw-r--r--drivers/staging/rdma/ipath/ipath_sysfs.c7
-rw-r--r--drivers/staging/rdma/ipath/ipath_ud.c1
-rw-r--r--drivers/staging/rdma/ipath/ipath_user_pages.c1
-rw-r--r--drivers/staging/rdma/ipath/ipath_user_sdma.c5
-rw-r--r--drivers/staging/rdma/ipath/ipath_verbs.c15
-rw-r--r--drivers/staging/rdma/ipath/ipath_verbs_mcast.c1
-rw-r--r--drivers/staging/rtl8188eu/Kconfig2
-rw-r--r--drivers/staging/rtl8188eu/Makefile1
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_cmd.c8
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_debug.c3
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_efuse.c50
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ieee80211.c14
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme.c5
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c96
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c20
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_rf.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_sta_mgt.c15
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c10
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_xmit.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c14
-rw-r--r--drivers/staging/rtl8188eu/hal/bb_cfg.c93
-rw-r--r--drivers/staging/rtl8188eu/hal/fw.c5
-rw-r--r--drivers/staging/rtl8188eu/hal/mac_cfg.c4
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c33
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_HWConfig.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/odm_RTL8188E.c122
-rw-r--r--drivers/staging/rtl8188eu/hal/phy.c32
-rw-r--r--drivers/staging/rtl8188eu/hal/rf_cfg.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c26
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c27
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_led.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c2
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c6
-rw-r--r--drivers/staging/rtl8188eu/hal/usb_halinit.c56
-rw-r--r--drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h14
-rw-r--r--drivers/staging/rtl8188eu/include/basic_types.h6
-rw-r--r--drivers/staging/rtl8188eu/include/drv_types.h2
-rw-r--r--drivers/staging/rtl8188eu/include/hal_intf.h16
-rw-r--r--drivers/staging/rtl8188eu/include/ieee80211.h4
-rw-r--r--drivers/staging/rtl8188eu/include/mon.h36
-rw-r--r--drivers/staging/rtl8188eu/include/odm.h90
-rw-r--r--drivers/staging/rtl8188eu/include/odm_debug.h42
-rw-r--r--drivers/staging/rtl8188eu/include/odm_reg.h2
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h48
-rw-r--r--drivers/staging/rtl8188eu/include/pwrseq.h84
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_spec.h415
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_security.h3
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_sreset.h14
-rw-r--r--drivers/staging/rtl8188eu/include/wifi.h12
-rw-r--r--drivers/staging/rtl8188eu/os_dep/ioctl_linux.c28
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mlme_linux.c9
-rw-r--r--drivers/staging/rtl8188eu/os_dep/mon.c195
-rw-r--r--drivers/staging/rtl8188eu/os_dep/os_intfs.c8
-rw-r--r--drivers/staging/rtl8188eu/os_dep/osdep_service.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/recv_linux.c2
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_intf.c10
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c5
-rw-r--r--drivers/staging/rtl8188eu/os_dep/xmit_linux.c2
-rw-r--r--drivers/staging/rtl8192e/dot11d.c4
-rw-r--r--drivers/staging/rtl8192e/dot11d.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_def.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c62
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c103
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c278
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h23
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_hwimg.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c240
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c358
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h6
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c311
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c14
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.c8
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pci.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.c31
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_ps.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c349
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BA.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c8
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HT.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_Qos.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TS.h4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_debug.h4
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c9
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c14
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c20
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c12
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211.h10
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c47
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c76
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c19
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c19
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c102
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c8
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_Qos.h49
-rw-r--r--drivers/staging/rtl8192u/r8192U.h99
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c1980
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c17
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h145
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c4
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.h6
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c4
-rw-r--r--drivers/staging/rtl8712/drv_types.h11
-rw-r--r--drivers/staging/rtl8712/hal_init.c57
-rw-r--r--drivers/staging/rtl8712/ieee80211.c43
-rw-r--r--drivers/staging/rtl8712/ieee80211.h48
-rw-r--r--drivers/staging/rtl8712/mlme_linux.c5
-rw-r--r--drivers/staging/rtl8712/os_intfs.c11
-rw-r--r--drivers/staging/rtl8712/osdep_service.h4
-rw-r--r--drivers/staging/rtl8712/recv_linux.c3
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c42
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h3
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c138
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_bitdef.h3
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h14
-rw-r--r--drivers/staging/rtl8712/rtl8712_io.c28
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c187
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c55
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c86
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c25
-rw-r--r--drivers/staging/rtl8712/rtl871x_eeprom.c22
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.h8
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c234
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.c53
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c33
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c150
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.c39
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.h1
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c38
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c70
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.c133
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c10
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c95
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c13
-rw-r--r--drivers/staging/rtl8712/usb_intf.c21
-rw-r--r--drivers/staging/rtl8712/usb_ops.c20
-rw-r--r--drivers/staging/rtl8712/usb_ops_linux.c28
-rw-r--r--drivers/staging/rtl8712/wifi.h9
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c4
-rw-r--r--drivers/staging/rtl8723au/core/rtw_ap.c210
-rw-r--r--drivers/staging/rtl8723au/core/rtw_cmd.c16
-rw-r--r--drivers/staging/rtl8723au/core/rtw_efuse.c320
-rw-r--r--drivers/staging/rtl8723au/core/rtw_ieee80211.c9
-rw-r--r--drivers/staging/rtl8723au/core/rtw_mlme_ext.c9
-rw-r--r--drivers/staging/rtl8723au/core/rtw_recv.c6
-rw-r--r--drivers/staging/rtl8723au/core/rtw_security.c17
-rw-r--r--drivers/staging/rtl8723au/core/rtw_wlan_util.c4
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c88
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_cmd.c3
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c46
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c55
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c48
-rw-r--r--drivers/staging/rtl8723au/hal/usb_halinit.c5
-rw-r--r--drivers/staging/rtl8723au/include/rtw_cmd.h2
-rw-r--r--drivers/staging/rts5208/rtsx.c6
-rw-r--r--drivers/staging/rts5208/rtsx_chip.c28
-rw-r--r--drivers/staging/skein/skein_api.c57
-rw-r--r--drivers/staging/skein/skein_api.h48
-rw-r--r--drivers/staging/skein/skein_base.c24
-rw-r--r--drivers/staging/skein/skein_block.c380
-rw-r--r--drivers/staging/skein/skein_generic.c3
-rw-r--r--drivers/staging/slicoss/slic.h23
-rw-r--r--drivers/staging/slicoss/slichw.h38
-rw-r--r--drivers/staging/slicoss/slicoss.c211
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.c323
-rw-r--r--drivers/staging/sm750fb/ddk750_chip.h9
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c50
-rw-r--r--drivers/staging/sm750fb/ddk750_display.h69
-rw-r--r--drivers/staging/sm750fb/ddk750_help.h13
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.c109
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.h9
-rw-r--r--drivers/staging/sm750fb/ddk750_mode.c3
-rw-r--r--drivers/staging/sm750fb/ddk750_power.c71
-rw-r--r--drivers/staging/sm750fb/ddk750_power.h17
-rw-r--r--drivers/staging/sm750fb/ddk750_reg.h244
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.c8
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.c296
-rw-r--r--drivers/staging/sm750fb/ddk750_swi2c.h47
-rw-r--r--drivers/staging/sm750fb/sm750.c439
-rw-r--r--drivers/staging/sm750fb/sm750.h134
-rw-r--r--drivers/staging/sm750fb/sm750_accel.c51
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.c74
-rw-r--r--drivers/staging/sm750fb/sm750_help.h37
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c209
-rw-r--r--drivers/staging/sm750fb/sm750_hw.h101
-rw-r--r--drivers/staging/speakup/buffers.c3
-rw-r--r--drivers/staging/speakup/devsynth.c4
-rw-r--r--drivers/staging/speakup/i18n.c2
-rw-r--r--drivers/staging/speakup/kobjects.c16
-rw-r--r--drivers/staging/speakup/serialio.c4
-rw-r--r--drivers/staging/speakup/speakup_audptr.c2
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c3
-rw-r--r--drivers/staging/speakup/speakup_soft.c3
-rw-r--r--drivers/staging/speakup/spk_priv.h42
-rw-r--r--drivers/staging/speakup/spk_priv_keyinfo.h44
-rw-r--r--drivers/staging/speakup/varhandlers.c20
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c1
-rw-r--r--drivers/staging/unisys/Documentation/ABI/sysfs-platform-visorchipset2
-rw-r--r--drivers/staging/unisys/Documentation/overview.txt458
-rw-r--r--drivers/staging/unisys/Kconfig2
-rw-r--r--drivers/staging/unisys/Makefile2
-rw-r--r--drivers/staging/unisys/TODO25
-rw-r--r--drivers/staging/unisys/include/channel.h19
-rw-r--r--drivers/staging/unisys/include/diagchannel.h5
-rw-r--r--drivers/staging/unisys/include/iochannel.h26
-rw-r--r--drivers/staging/unisys/include/periodic_work.h12
-rw-r--r--drivers/staging/unisys/visorbus/periodic_work.c8
-rw-r--r--drivers/staging/unisys/visorbus/visorchannel.c8
-rw-r--r--drivers/staging/unisys/visorbus/visorchipset.c2
-rw-r--r--drivers/staging/unisys/visorbus/vmcallinterface.h54
-rw-r--r--drivers/staging/unisys/visorhba/Kconfig14
-rw-r--r--drivers/staging/unisys/visorhba/Makefile10
-rw-r--r--drivers/staging/unisys/visorhba/visorhba_main.c1241
-rw-r--r--drivers/staging/unisys/visorinput/Kconfig10
-rw-r--r--drivers/staging/unisys/visorinput/Makefile7
-rw-r--r--drivers/staging/unisys/visorinput/ultrainputreport.h74
-rw-r--r--drivers/staging/unisys/visorinput/visorinput.c715
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c70
-rw-r--r--drivers/staging/vt6655/baseband.c14
-rw-r--r--drivers/staging/vt6655/card.c398
-rw-r--r--drivers/staging/vt6655/desc.h58
-rw-r--r--drivers/staging/vt6655/device.h149
-rw-r--r--drivers/staging/vt6655/device_main.c866
-rw-r--r--drivers/staging/vt6655/dpc.c8
-rw-r--r--drivers/staging/vt6655/dpc.h2
-rw-r--r--drivers/staging/vt6655/mac.c3
-rw-r--r--drivers/staging/vt6655/rf.c12
-rw-r--r--drivers/staging/vt6655/rf.h4
-rw-r--r--drivers/staging/vt6655/rxtx.c6
-rw-r--r--drivers/staging/vt6656/baseband.c2
-rw-r--r--drivers/staging/vt6656/card.c7
-rw-r--r--drivers/staging/vt6656/device.h2
-rw-r--r--drivers/staging/vt6656/int.c14
-rw-r--r--drivers/staging/vt6656/main_usb.c28
-rw-r--r--drivers/staging/vt6656/power.c10
-rw-r--r--drivers/staging/vt6656/rxtx.c5
-rw-r--r--drivers/staging/vt6656/usbpipe.c6
-rw-r--r--drivers/staging/wilc1000/Kconfig24
-rw-r--r--drivers/staging/wilc1000/Makefile14
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c1620
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.h80
-rw-r--r--drivers/staging/wilc1000/host_interface.c8305
-rw-r--r--drivers/staging/wilc1000/host_interface.h594
-rw-r--r--drivers/staging/wilc1000/linux_mon.c218
-rw-r--r--drivers/staging/wilc1000/linux_wlan.c1625
-rw-r--r--drivers/staging/wilc1000/linux_wlan_common.h22
-rw-r--r--drivers/staging/wilc1000/linux_wlan_sdio.c51
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.c116
-rw-r--r--drivers/staging/wilc1000/linux_wlan_spi.h6
-rw-r--r--drivers/staging/wilc1000/wilc_errorsupport.h67
-rw-r--r--drivers/staging/wilc1000/wilc_exported_buf.c71
-rw-r--r--drivers/staging/wilc1000/wilc_memory.c16
-rw-r--r--drivers/staging/wilc1000/wilc_memory.h66
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.c160
-rw-r--r--drivers/staging/wilc1000/wilc_msgqueue.h27
-rw-r--r--drivers/staging/wilc1000/wilc_oswrapper.h29
-rw-r--r--drivers/staging/wilc1000/wilc_platform.h48
-rw-r--r--drivers/staging/wilc1000/wilc_sdio.c154
-rw-r--r--drivers/staging/wilc1000/wilc_spi.c383
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.c1387
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_cfgoperations.h94
-rw-r--r--drivers/staging/wilc1000/wilc_wfi_netdevice.h121
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.c951
-rw-r--r--drivers/staging/wilc1000/wilc_wlan.h99
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.c189
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_cfg.h22
-rw-r--r--drivers/staging/wilc1000/wilc_wlan_if.h1455
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c15
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c2
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c50
-rw-r--r--drivers/staging/wlan-ng/p80211conv.h7
-rw-r--r--drivers/staging/wlan-ng/p80211meta.h90
-rw-r--r--drivers/staging/wlan-ng/prism2fw.c13
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c1027
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c8
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c6
-rw-r--r--drivers/staging/xgifb/vb_init.c103
-rw-r--r--drivers/staging/xgifb/vb_util.h4
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c5
-rw-r--r--drivers/vme/bridges/vme_tsi148.c172
-rw-r--r--drivers/vme/vme.c90
-rw-r--r--drivers/vme/vme_bridge.h21
968 files changed, 38074 insertions, 57679 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 4011effe4c05..66792e707d74 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -19,27 +19,7 @@ config IIO_BUFFER
acquisition methods.
if IIO_BUFFER
-
-config IIO_BUFFER_CB
- bool "IIO callback buffer used for push in-kernel interfaces"
- help
- Should be selected by any drivers that do in-kernel push
- usage. That is, those where the data is pushed to the consumer.
-
-config IIO_KFIFO_BUF
- tristate "Industrial I/O buffering based on kfifo"
- help
- A simple fifo based on kfifo. Note that this currently provides
- no buffer events so it is up to userspace to work out how
- often to read from the buffer.
-
-config IIO_TRIGGERED_BUFFER
- tristate
- select IIO_TRIGGER
- select IIO_KFIFO_BUF
- help
- Provides helper functions for setting up triggered buffers.
-
+ source "drivers/iio/buffer/Kconfig"
endif # IIO_BUFFER
config IIO_TRIGGER
@@ -58,9 +38,16 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
+config IIO_TRIGGERED_EVENT
+ tristate
+ select IIO_TRIGGER
+ help
+ Provides helper functions for setting up triggered events.
+
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig"
+source "drivers/iio/chemical/Kconfig"
source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/frequency/Kconfig"
@@ -73,6 +60,7 @@ source "drivers/iio/orientation/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
+source "drivers/iio/potentiometer/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/temperature/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 698afc2d17ce..aeca7269fe44 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -6,14 +6,14 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
-obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
+obj-y += buffer/
+obj-y += chemical/
obj-y += common/
obj-y += dac/
obj-y += gyro/
@@ -23,6 +23,7 @@ obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += orientation/
+obj-y += potentiometer/
obj-y += pressure/
obj-y += proximity/
obj-y += temperature/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index a59047d7657e..969428dd6329 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -19,19 +19,27 @@ config BMA180
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
- depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+ select REGMAP
+ select BMC150_ACCEL_I2C if I2C
+ select BMC150_ACCEL_SPI if SPI
help
Say yes here to build support for the following Bosch accelerometers:
BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
- Currently this only supports the device via an i2c interface.
-
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing accelerometer part, which has
its own address and register map.
+config BMC150_ACCEL_I2C
+ tristate
+ select REGMAP_I2C
+
+config BMC150_ACCEL_SPI
+ tristate
+ select REGMAP_SPI
+
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -100,13 +108,13 @@ config KXCJK1013
be called kxcjk-1013.
config MMA8452
- tristate "Freescale MMA8452Q Accelerometer Driver"
+ tristate "Freescale MMA8452Q and similar Accelerometers Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- Say yes here to build support for the Freescale MMA8452Q 3-axis
- accelerometer.
+ Say yes here to build support for the following Freescale 3-axis
+ accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
To compile this driver as a module, choose M here: the module
will be called mma8452.
@@ -137,6 +145,19 @@ config MMA9553
To compile this driver as a module, choose M here: the module
will be called mma9553.
+config MXC4005
+ tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_I2C
+ help
+ Say yes here to build support for the Memsic MXC4005XC 3-axis
+ accelerometer.
+
+ To compile this driver as a module, choose M. The module will be
+ called mxc4005.
+
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index ebd2675b2a02..7925f166e6e9 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -4,7 +4,9 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMA180) += bma180.o
-obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o
+obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
+obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
+obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
@@ -14,6 +16,8 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_MMA9553) += mma9553.o
+obj-$(CONFIG_MXC4005) += mxc4005.o
+
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel-core.c
index 0104cdef8709..2d33f1e821db 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -35,10 +35,12 @@
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include <linux/regmap.h>
+
+#include "bmc150-accel.h"
#define BMC150_ACCEL_DRV_NAME "bmc150_accel"
#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event"
-#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int"
#define BMC150_ACCEL_REG_CHIP_ID 0x00
@@ -185,7 +187,9 @@ enum bmc150_accel_trigger_id {
};
struct bmc150_accel_data {
- struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
+ int irq;
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
atomic_t active_intr;
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
@@ -242,6 +246,12 @@ static const struct {
{500000, BMC150_ACCEL_SLEEP_500_MS},
{1000000, BMC150_ACCEL_SLEEP_1_SEC} };
+static const struct regmap_config bmc150_i2c_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f,
+};
+
static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
enum bmc150_power_modes mode,
int dur_us)
@@ -269,12 +279,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT;
lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT);
- dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits);
+ dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits);
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n");
+ dev_err(data->dev, "Error writing reg_pmu_lpw\n");
return ret;
}
@@ -290,8 +299,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
if (bmc150_accel_samp_freq_table[i].val == val &&
bmc150_accel_samp_freq_table[i].val2 == val2) {
- ret = i2c_smbus_write_byte_data(
- data->client,
+ ret = regmap_write(data->regmap,
BMC150_ACCEL_REG_PMU_BW,
bmc150_accel_samp_freq_table[i].bw_bits);
if (ret < 0)
@@ -308,30 +316,23 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
{
- int ret, val;
+ int ret;
- ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6,
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6,
data->slope_thres);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_6\n");
- return ret;
- }
-
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_5\n");
+ dev_err(data->dev, "Error writing reg_int_6\n");
return ret;
}
- val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur;
- ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5,
- val);
+ ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5,
+ BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur);
if (ret < 0) {
- dev_err(&data->client->dev, "Error write reg_int_5\n");
+ dev_err(data->dev, "Error updating reg_int_5\n");
return ret;
}
- dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres,
+ dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres,
data->slope_dur);
return ret;
@@ -380,17 +381,17 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_get_sync(data->dev);
} else {
- pm_runtime_mark_last_busy(&data->client->dev);
- ret = pm_runtime_put_autosuspend(&data->client->dev);
+ pm_runtime_mark_last_busy(data->dev);
+ ret = pm_runtime_put_autosuspend(data->dev);
}
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Failed: bmc150_accel_set_power_state for %d\n", on);
if (on)
- pm_runtime_put_noidle(&data->client->dev);
+ pm_runtime_put_noidle(data->dev);
return ret;
}
@@ -470,38 +471,18 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
return ret;
/* map the interrupt to the appropriate pins */
- ret = i2c_smbus_read_byte_data(data->client, info->map_reg);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_map\n");
- goto out_fix_power_state;
- }
- if (state)
- ret |= info->map_bitmask;
- else
- ret &= ~info->map_bitmask;
-
- ret = i2c_smbus_write_byte_data(data->client, info->map_reg,
- ret);
+ ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask,
+ (state ? info->map_bitmask : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_map\n");
+ dev_err(data->dev, "Error updating reg_int_map\n");
goto out_fix_power_state;
}
/* enable/disable the interrupt */
- ret = i2c_smbus_read_byte_data(data->client, info->en_reg);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_en\n");
- goto out_fix_power_state;
- }
-
- if (state)
- ret |= info->en_bitmask;
- else
- ret &= ~info->en_bitmask;
-
- ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret);
+ ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask,
+ (state ? info->en_bitmask : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_en\n");
+ dev_err(data->dev, "Error updating reg_int_en\n");
goto out_fix_power_state;
}
@@ -523,12 +504,11 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
if (data->chip_info->scale_table[i].scale == val) {
- ret = i2c_smbus_write_byte_data(
- data->client,
+ ret = regmap_write(data->regmap,
BMC150_ACCEL_REG_PMU_RANGE,
data->chip_info->scale_table[i].reg_range);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing pmu_range\n");
return ret;
}
@@ -544,16 +524,17 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
{
int ret;
+ unsigned int value;
mutex_lock(&data->mutex);
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_temp\n");
+ dev_err(data->dev, "Error reading reg_temp\n");
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret, 7);
+ *val = sign_extend32(value, 7);
mutex_unlock(&data->mutex);
@@ -566,6 +547,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
{
int ret;
int axis = chan->scan_index;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
ret = bmc150_accel_set_power_state(data, true);
@@ -574,15 +556,15 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
return ret;
}
- ret = i2c_smbus_read_word_data(data->client,
- BMC150_ACCEL_AXIS_TO_REG(axis));
+ ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
+ &raw_val, 2);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading axis %d\n", axis);
+ dev_err(data->dev, "Error reading axis %d\n", axis);
bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret >> chan->scan_type.shift,
+ *val = sign_extend32(raw_val >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
ret = bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
@@ -846,52 +828,34 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
* We must read at least one full frame in one burst, otherwise the rest of the
* frame data is discarded.
*/
-static int bmc150_accel_fifo_transfer(const struct i2c_client *client,
+static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
char *buffer, int samples)
{
int sample_length = 3 * 2;
- u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
- int ret = -EIO;
-
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .buf = &reg_fifo_data,
- .len = sizeof(reg_fifo_data),
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .buf = (u8 *)buffer,
- .len = samples * sample_length,
- }
- };
+ int ret;
+ int total_length = samples * sample_length;
+ int i;
+ size_t step = regmap_get_raw_read_max(data->regmap);
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret != 2)
- ret = -EIO;
- else
- ret = 0;
- } else {
- int i, step = I2C_SMBUS_BLOCK_MAX / sample_length;
-
- for (i = 0; i < samples * sample_length; i += step) {
- ret = i2c_smbus_read_i2c_block_data(client,
- reg_fifo_data, step,
- &buffer[i]);
- if (ret != step) {
- ret = -EIO;
- break;
- }
+ if (!step || step > total_length)
+ step = total_length;
+ else if (step < total_length)
+ step = sample_length;
- ret = 0;
- }
+ /*
+ * Seems we have a bus with size limitation so we have to execute
+ * multiple reads
+ */
+ for (i = 0; i < total_length; i += step) {
+ ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA,
+ &buffer[i], step);
+ if (ret)
+ break;
}
if (ret)
- dev_err(&client->dev, "Error transferring data from fifo\n");
+ dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n",
+ step);
return ret;
}
@@ -905,15 +869,15 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
int64_t tstamp;
uint64_t sample_period;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client,
- BMC150_ACCEL_REG_FIFO_STATUS);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_fifo_status\n");
+ dev_err(data->dev, "Error reading reg_fifo_status\n");
return ret;
}
- count = ret & 0x7F;
+ count = val & 0x7F;
if (!count)
return 0;
@@ -952,7 +916,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
if (samples && count > samples)
count = samples;
- ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count);
+ ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
if (ret)
return ret;
@@ -1052,15 +1016,6 @@ static const struct iio_chan_spec bmc150_accel_channels[] =
static const struct iio_chan_spec bma280_accel_channels[] =
BMC150_ACCEL_CHANNELS(14);
-enum {
- bmc150,
- bmi055,
- bma255,
- bma250e,
- bma222e,
- bma280,
-};
-
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
[bmc150] = {
.name = "BMC150A",
@@ -1155,17 +1110,19 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct bmc150_accel_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
- ret = i2c_smbus_read_word_data(data->client,
- BMC150_ACCEL_AXIS_TO_REG(bit));
+ ret = regmap_bulk_read(data->regmap,
+ BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val,
+ 2);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err_read;
}
- data->buffer[i++] = ret;
+ data->buffer[i++] = raw_val;
}
mutex_unlock(&data->mutex);
@@ -1189,13 +1146,12 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
mutex_lock(&data->mutex);
/* clear any latched interrupt */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
mutex_unlock(&data->mutex);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
@@ -1249,20 +1205,20 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
struct bmc150_accel_data *data = iio_priv(indio_dev);
int dir;
int ret;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client,
- BMC150_ACCEL_REG_INT_STATUS_2);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_status_2\n");
+ dev_err(data->dev, "Error reading reg_int_status_2\n");
return ret;
}
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
dir = IIO_EV_DIR_FALLING;
else
dir = IIO_EV_DIR_RISING;
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_X)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1271,7 +1227,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
dir),
data->timestamp);
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1280,7 +1236,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
dir),
data->timestamp);
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1315,13 +1271,11 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
}
if (ack) {
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret)
- dev_err(&data->client->dev,
- "Error writing reg_int_rst_latch\n");
+ dev_err(data->dev, "Error writing reg_int_rst_latch\n");
ret = IRQ_HANDLED;
} else {
@@ -1360,32 +1314,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
return IRQ_NONE;
}
-static int bmc150_accel_gpio_probe(struct i2c_client *client,
- struct bmc150_accel_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "Failed: gpio get index\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const struct {
int intr;
const char *name;
@@ -1423,7 +1351,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
struct bmc150_accel_trigger *t = &data->triggers[i];
- t->indio_trig = devm_iio_trigger_alloc(&data->client->dev,
+ t->indio_trig = devm_iio_trigger_alloc(data->dev,
bmc150_accel_triggers[i].name,
indio_dev->name,
indio_dev->id);
@@ -1432,7 +1360,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
break;
}
- t->indio_trig->dev.parent = &data->client->dev;
+ t->indio_trig->dev.parent = data->dev;
t->indio_trig->ops = &bmc150_accel_trigger_ops;
t->intr = bmc150_accel_triggers[i].intr;
t->data = data;
@@ -1459,20 +1387,19 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
int ret;
- ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
+ ret = regmap_write(data->regmap, reg, data->fifo_mode);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
+ dev_err(data->dev, "Error writing reg_fifo_config1\n");
return ret;
}
if (!data->fifo_mode)
return 0;
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_FIFO_CONFIG0,
- data->watermark);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0,
+ data->watermark);
if (ret < 0)
- dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
+ dev_err(data->dev, "Error writing reg_fifo_config0\n");
return ret;
}
@@ -1557,23 +1484,25 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
int ret, i;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error: Reading chip id\n");
+ dev_err(data->dev,
+ "Error: Reading chip id\n");
return ret;
}
- dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
+ dev_dbg(data->dev, "Chip Id %x\n", val);
for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
- if (bmc150_accel_chip_info_tbl[i].chip_id == ret) {
+ if (bmc150_accel_chip_info_tbl[i].chip_id == val) {
data->chip_info = &bmc150_accel_chip_info_tbl[i];
break;
}
}
if (!data->chip_info) {
- dev_err(&data->client->dev, "Unsupported chip %x\n", ret);
+ dev_err(data->dev, "Invalid chip %x\n", val);
return -ENODEV;
}
@@ -1587,11 +1516,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return ret;
/* Set Default Range */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_PMU_RANGE,
- BMC150_ACCEL_DEF_RANGE_4G);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE,
+ BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
+ dev_err(data->dev,
+ "Error writing reg_pmu_range\n");
return ret;
}
@@ -1605,12 +1534,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return ret;
/* Set default as latched interrupts */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
@@ -1618,24 +1546,23 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return 0;
}
-static int bmc150_accel_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name, bool block_supported)
{
struct bmc150_accel_data *data;
struct iio_dev *indio_dev;
int ret;
- const char *name = NULL;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
- data->client = client;
+ dev_set_drvdata(dev, indio_dev);
+ data->dev = dev;
+ data->irq = irq;
- if (id)
- name = id->name;
+ data->regmap = regmap;
ret = bmc150_accel_chip_init(data);
if (ret < 0)
@@ -1643,7 +1570,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
mutex_init(&data->mutex);
- indio_dev->dev.parent = &client->dev;
+ indio_dev->dev.parent = dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name ? name : data->chip_info->name;
@@ -1655,16 +1582,13 @@ static int bmc150_accel_probe(struct i2c_client *client,
bmc150_accel_trigger_handler,
&bmc150_accel_buffer_ops);
if (ret < 0) {
- dev_err(&client->dev, "Failed: iio triggered buffer setup\n");
+ dev_err(data->dev, "Failed: iio triggered buffer setup\n");
return ret;
}
- if (client->irq < 0)
- client->irq = bmc150_accel_gpio_probe(client, data);
-
- if (client->irq > 0) {
+ if (data->irq > 0) {
ret = devm_request_threaded_irq(
- &client->dev, client->irq,
+ data->dev, data->irq,
bmc150_accel_irq_handler,
bmc150_accel_irq_thread_handler,
IRQF_TRIGGER_RISING,
@@ -1679,11 +1603,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
* want to use latch mode when we can to prevent interrupt
* flooding.
*/
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
+ dev_err(data->dev, "Error writing reg_int_rst_latch\n");
goto err_buffer_cleanup;
}
@@ -1693,9 +1616,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (ret)
goto err_buffer_cleanup;
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
- i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ if (block_supported) {
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
indio_dev->info = &bmc150_accel_info_fifo;
indio_dev->buffer->attrs = bmc150_accel_fifo_attributes;
@@ -1704,18 +1625,17 @@ static int bmc150_accel_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret < 0) {
- dev_err(&client->dev, "Unable to register iio device\n");
+ dev_err(dev, "Unable to register iio device\n");
goto err_trigger_unregister;
}
- ret = pm_runtime_set_active(&client->dev);
+ ret = pm_runtime_set_active(dev);
if (ret)
goto err_iio_unregister;
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev,
- BMC150_AUTO_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
return 0;
@@ -1728,15 +1648,16 @@ err_buffer_cleanup:
return ret;
}
+EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
-static int bmc150_accel_remove(struct i2c_client *client)
+int bmc150_accel_core_remove(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
+ pm_runtime_disable(data->dev);
+ pm_runtime_set_suspended(data->dev);
+ pm_runtime_put_noidle(data->dev);
iio_device_unregister(indio_dev);
@@ -1750,11 +1671,12 @@ static int bmc150_accel_remove(struct i2c_client *client)
return 0;
}
+EXPORT_SYMBOL_GPL(bmc150_accel_core_remove);
#ifdef CONFIG_PM_SLEEP
static int bmc150_accel_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1766,7 +1688,7 @@ static int bmc150_accel_suspend(struct device *dev)
static int bmc150_accel_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1782,11 +1704,11 @@ static int bmc150_accel_resume(struct device *dev)
#ifdef CONFIG_PM
static int bmc150_accel_runtime_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
- dev_dbg(&data->client->dev, __func__);
+ dev_dbg(data->dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
if (ret < 0)
return -EAGAIN;
@@ -1796,12 +1718,12 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
static int bmc150_accel_runtime_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
int sleep_val;
- dev_dbg(&data->client->dev, __func__);
+ dev_dbg(data->dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)
@@ -1820,47 +1742,12 @@ static int bmc150_accel_runtime_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bmc150_accel_pm_ops = {
+const struct dev_pm_ops bmc150_accel_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume)
SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend,
bmc150_accel_runtime_resume, NULL)
};
-
-static const struct acpi_device_id bmc150_accel_acpi_match[] = {
- {"BSBA0150", bmc150},
- {"BMC150A", bmc150},
- {"BMI055A", bmi055},
- {"BMA0255", bma255},
- {"BMA250E", bma250e},
- {"BMA222E", bma222e},
- {"BMA0280", bma280},
- { },
-};
-MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
-
-static const struct i2c_device_id bmc150_accel_id[] = {
- {"bmc150_accel", bmc150},
- {"bmi055_accel", bmi055},
- {"bma255", bma255},
- {"bma250e", bma250e},
- {"bma222e", bma222e},
- {"bma280", bma280},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
-
-static struct i2c_driver bmc150_accel_driver = {
- .driver = {
- .name = BMC150_ACCEL_DRV_NAME,
- .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
- .pm = &bmc150_accel_pm_ops,
- },
- .probe = bmc150_accel_probe,
- .remove = bmc150_accel_remove,
- .id_table = bmc150_accel_id,
-};
-module_i2c_driver(bmc150_accel_driver);
+EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
new file mode 100644
index 000000000000..b41404ba32fc
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -0,0 +1,102 @@
+/*
+ * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
+ * - BMC150
+ * - BMI055
+ * - BMA255
+ * - BMA250E
+ * - BMA222E
+ * - BMA280
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+
+#include "bmc150-accel.h"
+
+static const struct regmap_config bmc150_i2c_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int bmc150_accel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ const char *name = NULL;
+ bool block_supported =
+ i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
+ i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK);
+
+ regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to initialize i2c regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ if (id)
+ name = id->name;
+
+ return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name,
+ block_supported);
+}
+
+static int bmc150_accel_remove(struct i2c_client *client)
+{
+ return bmc150_accel_core_remove(&client->dev);
+}
+
+static const struct acpi_device_id bmc150_accel_acpi_match[] = {
+ {"BSBA0150", bmc150},
+ {"BMC150A", bmc150},
+ {"BMI055A", bmi055},
+ {"BMA0255", bma255},
+ {"BMA250E", bma250e},
+ {"BMA222E", bma222e},
+ {"BMA0280", bma280},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
+
+static const struct i2c_device_id bmc150_accel_id[] = {
+ {"bmc150_accel", bmc150},
+ {"bmi055_accel", bmi055},
+ {"bma255", bma255},
+ {"bma250e", bma250e},
+ {"bma222e", bma222e},
+ {"bma280", bma280},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
+
+static struct i2c_driver bmc150_accel_driver = {
+ .driver = {
+ .name = "bmc150_accel_i2c",
+ .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .pm = &bmc150_accel_pm_ops,
+ },
+ .probe = bmc150_accel_probe,
+ .remove = bmc150_accel_remove,
+ .id_table = bmc150_accel_id,
+};
+module_i2c_driver(bmc150_accel_driver);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 I2C accelerometer driver");
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
new file mode 100644
index 000000000000..16b66f2a7204
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -0,0 +1,91 @@
+/*
+ * 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip
+ * Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "bmc150-accel.h"
+
+static const struct regmap_config bmc150_spi_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f,
+};
+
+static int bmc150_accel_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to initialize spi regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
+ true);
+}
+
+static int bmc150_accel_remove(struct spi_device *spi)
+{
+ return bmc150_accel_core_remove(&spi->dev);
+}
+
+static const struct acpi_device_id bmc150_accel_acpi_match[] = {
+ {"BSBA0150", bmc150},
+ {"BMC150A", bmc150},
+ {"BMI055A", bmi055},
+ {"BMA0255", bma255},
+ {"BMA250E", bma250e},
+ {"BMA222E", bma222e},
+ {"BMA0280", bma280},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
+
+static const struct spi_device_id bmc150_accel_id[] = {
+ {"bmc150_accel", bmc150},
+ {"bmi055_accel", bmi055},
+ {"bma255", bma255},
+ {"bma250e", bma250e},
+ {"bma222e", bma222e},
+ {"bma280", bma280},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
+
+static struct spi_driver bmc150_accel_driver = {
+ .driver = {
+ .name = "bmc150_accel_spi",
+ .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .pm = &bmc150_accel_pm_ops,
+ },
+ .probe = bmc150_accel_probe,
+ .remove = bmc150_accel_remove,
+ .id_table = bmc150_accel_id,
+};
+module_spi_driver(bmc150_accel_driver);
+
+MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 SPI accelerometer driver");
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
new file mode 100644
index 000000000000..ba0335987f94
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -0,0 +1,20 @@
+#ifndef _BMC150_ACCEL_H_
+#define _BMC150_ACCEL_H_
+
+struct regmap;
+
+enum {
+ bmc150,
+ bmi055,
+ bma255,
+ bma250e,
+ bma222e,
+ bma280,
+};
+
+int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name, bool block_supported);
+int bmc150_accel_core_remove(struct device *dev);
+extern const struct dev_pm_ops bmc150_accel_pm_ops;
+
+#endif /* _BMC150_ACCEL_H_ */
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 3292bc0c1d0e..18c1b06684c1 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
return dev_name(dev);
}
-static int kxcjk1013_gpio_probe(struct i2c_client *client,
- struct kxcjk1013_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- if (data->is_smo8500_device)
- return -ENOTSUPP;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int kxcjk1013_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &kxcjk1013_info;
- if (client->irq < 0)
- client->irq = kxcjk1013_gpio_probe(client, data);
-
- if (client->irq > 0) {
+ if (client->irq > 0 && !data->is_smo8500_device) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index b921d84c1be6..1eccc2dcf14c 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1,6 +1,12 @@
/*
- * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
+ * mma8452.c - Support for following Freescale 3-axis accelerometers:
*
+ * MMA8452Q (12 bit)
+ * MMA8453Q (10 bit)
+ * MMA8652FC (12 bit)
+ * MMA8653FC (10 bit)
+ *
+ * Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
@@ -22,10 +28,11 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/events.h>
#include <linux/delay.h>
+#include <linux/of_device.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
-#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
+#define MMA8452_OUT_X 0x01 /* MSB first */
#define MMA8452_OUT_Y 0x03
#define MMA8452_OUT_Z 0x05
#define MMA8452_INT_SRC 0x0c
@@ -38,6 +45,16 @@
#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
#define MMA8452_HP_FILTER_CUTOFF 0x0f
#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0)
+#define MMA8452_FF_MT_CFG 0x15
+#define MMA8452_FF_MT_CFG_OAE BIT(6)
+#define MMA8452_FF_MT_CFG_ELE BIT(7)
+#define MMA8452_FF_MT_SRC 0x16
+#define MMA8452_FF_MT_SRC_XHE BIT(1)
+#define MMA8452_FF_MT_SRC_YHE BIT(3)
+#define MMA8452_FF_MT_SRC_ZHE BIT(5)
+#define MMA8452_FF_MT_THS 0x17
+#define MMA8452_FF_MT_THS_MASK 0x7f
+#define MMA8452_FF_MT_COUNT 0x18
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
@@ -65,15 +82,65 @@
#define MMA8452_MAX_REG 0x31
#define MMA8452_INT_DRDY BIT(0)
+#define MMA8452_INT_FF_MT BIT(2)
#define MMA8452_INT_TRANS BIT(5)
#define MMA8452_DEVICE_ID 0x2a
+#define MMA8453_DEVICE_ID 0x3a
+#define MMA8652_DEVICE_ID 0x4a
+#define MMA8653_DEVICE_ID 0x5a
struct mma8452_data {
struct i2c_client *client;
struct mutex lock;
u8 ctrl_reg1;
u8 data_cfg;
+ const struct mma_chip_info *chip_info;
+};
+
+/**
+ * struct mma_chip_info - chip specific data for Freescale's accelerometers
+ * @chip_id: WHO_AM_I register's value
+ * @channels: struct iio_chan_spec matching the device's
+ * capabilities
+ * @num_channels: number of channels
+ * @mma_scales: scale factors for converting register values
+ * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers
+ * per mode: m/s^2 and micro m/s^2
+ * @ev_cfg: event config register address
+ * @ev_cfg_ele: latch bit in event config register
+ * @ev_cfg_chan_shift: number of the bit to enable events in X
+ * direction; in event config register
+ * @ev_src: event source register address
+ * @ev_src_xe: bit in event source register that indicates
+ * an event in X direction
+ * @ev_src_ye: bit in event source register that indicates
+ * an event in Y direction
+ * @ev_src_ze: bit in event source register that indicates
+ * an event in Z direction
+ * @ev_ths: event threshold register address
+ * @ev_ths_mask: mask for the threshold value
+ * @ev_count: event count (period) register address
+ *
+ * Since not all chips supported by the driver support comparing high pass
+ * filtered data for events (interrupts), different interrupt sources are
+ * used for different chips and the relevant registers are included here.
+ */
+struct mma_chip_info {
+ u8 chip_id;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ const int mma_scales[3][2];
+ u8 ev_cfg;
+ u8 ev_cfg_ele;
+ u8 ev_cfg_chan_shift;
+ u8 ev_src;
+ u8 ev_src_xe;
+ u8 ev_src_ye;
+ u8 ev_src_ze;
+ u8 ev_ths;
+ u8 ev_ths_mask;
+ u8 ev_count;
};
static int mma8452_drdy(struct mma8452_data *data)
@@ -143,16 +210,6 @@ static const int mma8452_samp_freq[8][2] = {
{6, 250000}, {1, 560000}
};
-/*
- * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
- * The userspace interface uses m/s^2 and we declare micro units
- * So scale factor is given by:
- * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665
- */
-static const int mma8452_scales[3][2] = {
- {0, 9577}, {0, 19154}, {0, 38307}
-};
-
/* Datasheet table 35 (step time vs sample frequency) */
static const int mma8452_transient_time_step_us[8] = {
1250,
@@ -189,8 +246,11 @@ static ssize_t mma8452_show_scale_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return mma8452_show_int_plus_micros(buf, mma8452_scales,
- ARRAY_SIZE(mma8452_scales));
+ struct mma8452_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+
+ return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
+ ARRAY_SIZE(data->chip_info->mma_scales));
}
static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
@@ -221,9 +281,8 @@ static int mma8452_get_samp_freq_index(struct mma8452_data *data,
static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
{
- return mma8452_get_int_plus_micros_index(mma8452_scales,
- ARRAY_SIZE(mma8452_scales),
- val, val2);
+ return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales,
+ ARRAY_SIZE(data->chip_info->mma_scales), val, val2);
}
static int mma8452_get_hp_filter_index(struct mma8452_data *data,
@@ -270,14 +329,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4,
- 11);
+ *val = sign_extend32(be16_to_cpu(
+ buffer[chan->scan_index]) >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
- *val = mma8452_scales[i][0];
- *val2 = mma8452_scales[i][1];
+ *val = data->chip_info->mma_scales[i][0];
+ *val2 = data->chip_info->mma_scales[i][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
@@ -439,17 +499,17 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
switch (info) {
case IIO_EV_INFO_VALUE:
ret = i2c_smbus_read_byte_data(data->client,
- MMA8452_TRANSIENT_THS);
+ data->chip_info->ev_ths);
if (ret < 0)
return ret;
- *val = ret & MMA8452_TRANSIENT_THS_MASK;
+ *val = ret & data->chip_info->ev_ths_mask;
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
ret = i2c_smbus_read_byte_data(data->client,
- MMA8452_TRANSIENT_COUNT);
+ data->chip_info->ev_count);
if (ret < 0)
return ret;
@@ -497,7 +557,8 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
return -EINVAL;
- return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
+ return mma8452_change_config(data, data->chip_info->ev_ths,
+ val);
case IIO_EV_INFO_PERIOD:
steps = (val * USEC_PER_SEC + val2) /
@@ -507,7 +568,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
if (steps < 0 || steps > 0xff)
return -EINVAL;
- return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
+ return mma8452_change_config(data, data->chip_info->ev_count,
steps);
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
@@ -538,13 +599,15 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct mma8452_data *data = iio_priv(indio_dev);
+ const struct mma_chip_info *chip = data->chip_info;
int ret;
- ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
+ ret = i2c_smbus_read_byte_data(data->client,
+ data->chip_info->ev_cfg);
if (ret < 0)
return ret;
- return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0;
+ return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
}
static int mma8452_write_event_config(struct iio_dev *indio_dev,
@@ -554,20 +617,22 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
int state)
{
struct mma8452_data *data = iio_priv(indio_dev);
+ const struct mma_chip_info *chip = data->chip_info;
int val;
- val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
+ val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
if (val < 0)
return val;
if (state)
- val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
+ val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
else
- val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
+ val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
- val |= MMA8452_TRANSIENT_CFG_ELE;
+ val |= chip->ev_cfg_ele;
+ val |= MMA8452_FF_MT_CFG_OAE;
- return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val);
+ return mma8452_change_config(data, chip->ev_cfg, val);
}
static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
@@ -576,25 +641,25 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
s64 ts = iio_get_time_ns();
int src;
- src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC);
+ src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src);
if (src < 0)
return;
- if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
+ if (src & data->chip_info->ev_src_xe)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_RISING),
ts);
- if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
+ if (src & data->chip_info->ev_src_ye)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
IIO_EV_TYPE_MAG,
IIO_EV_DIR_RISING),
ts);
- if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
+ if (src & data->chip_info->ev_src_ze)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
IIO_EV_TYPE_MAG,
@@ -606,6 +671,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct mma8452_data *data = iio_priv(indio_dev);
+ const struct mma_chip_info *chip = data->chip_info;
int ret = IRQ_NONE;
int src;
@@ -618,7 +684,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
ret = IRQ_HANDLED;
}
- if (src & MMA8452_INT_TRANS) {
+ if ((src & MMA8452_INT_TRANS &&
+ chip->ev_src == MMA8452_TRANSIENT_SRC) ||
+ (src & MMA8452_INT_FF_MT &&
+ chip->ev_src == MMA8452_FF_MT_SRC)) {
mma8452_transient_interrupt(indio_dev);
ret = IRQ_HANDLED;
}
@@ -680,6 +749,16 @@ static const struct iio_event_spec mma8452_transient_event[] = {
},
};
+static const struct iio_event_spec mma8452_motion_event[] = {
+ {
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD)
+ },
+};
+
/*
* Threshold is configured in fixed 8G/127 steps regardless of
* currently selected scale for measurement.
@@ -693,10 +772,9 @@ static struct attribute *mma8452_event_attributes[] = {
static struct attribute_group mma8452_event_attribute_group = {
.attrs = mma8452_event_attributes,
- .name = "events",
};
-#define MMA8452_CHANNEL(axis, idx) { \
+#define MMA8452_CHANNEL(axis, idx, bits) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
@@ -708,22 +786,144 @@ static struct attribute_group mma8452_event_attribute_group = {
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
- .realbits = 12, \
+ .realbits = (bits), \
.storagebits = 16, \
- .shift = 4, \
+ .shift = 16 - (bits), \
.endianness = IIO_BE, \
}, \
.event_spec = mma8452_transient_event, \
.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
}
+#define MMA8652_CHANNEL(axis, idx, bits) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = idx, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = 16 - (bits), \
+ .endianness = IIO_BE, \
+ }, \
+ .event_spec = mma8452_motion_event, \
+ .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
+}
+
static const struct iio_chan_spec mma8452_channels[] = {
- MMA8452_CHANNEL(X, 0),
- MMA8452_CHANNEL(Y, 1),
- MMA8452_CHANNEL(Z, 2),
+ MMA8452_CHANNEL(X, 0, 12),
+ MMA8452_CHANNEL(Y, 1, 12),
+ MMA8452_CHANNEL(Z, 2, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
+static const struct iio_chan_spec mma8453_channels[] = {
+ MMA8452_CHANNEL(X, 0, 10),
+ MMA8452_CHANNEL(Y, 1, 10),
+ MMA8452_CHANNEL(Z, 2, 10),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec mma8652_channels[] = {
+ MMA8652_CHANNEL(X, 0, 12),
+ MMA8652_CHANNEL(Y, 1, 12),
+ MMA8652_CHANNEL(Z, 2, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec mma8653_channels[] = {
+ MMA8652_CHANNEL(X, 0, 10),
+ MMA8652_CHANNEL(Y, 1, 10),
+ MMA8652_CHANNEL(Z, 2, 10),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+enum {
+ mma8452,
+ mma8453,
+ mma8652,
+ mma8653,
+};
+
+static const struct mma_chip_info mma_chip_info_table[] = {
+ [mma8452] = {
+ .chip_id = MMA8452_DEVICE_ID,
+ .channels = mma8452_channels,
+ .num_channels = ARRAY_SIZE(mma8452_channels),
+ /*
+ * Hardware has fullscale of -2G, -4G, -8G corresponding to
+ * raw value -2048 for 12 bit or -512 for 10 bit.
+ * The userspace interface uses m/s^2 and we declare micro units
+ * So scale factor for 12 bit here is given by:
+ * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
+ */
+ .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
+ .ev_cfg = MMA8452_TRANSIENT_CFG,
+ .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+ .ev_cfg_chan_shift = 1,
+ .ev_src = MMA8452_TRANSIENT_SRC,
+ .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
+ .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
+ .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
+ .ev_ths = MMA8452_TRANSIENT_THS,
+ .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+ .ev_count = MMA8452_TRANSIENT_COUNT,
+ },
+ [mma8453] = {
+ .chip_id = MMA8453_DEVICE_ID,
+ .channels = mma8453_channels,
+ .num_channels = ARRAY_SIZE(mma8453_channels),
+ .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
+ .ev_cfg = MMA8452_TRANSIENT_CFG,
+ .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+ .ev_cfg_chan_shift = 1,
+ .ev_src = MMA8452_TRANSIENT_SRC,
+ .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
+ .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
+ .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
+ .ev_ths = MMA8452_TRANSIENT_THS,
+ .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+ .ev_count = MMA8452_TRANSIENT_COUNT,
+ },
+ [mma8652] = {
+ .chip_id = MMA8652_DEVICE_ID,
+ .channels = mma8652_channels,
+ .num_channels = ARRAY_SIZE(mma8652_channels),
+ .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
+ .ev_cfg = MMA8452_FF_MT_CFG,
+ .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
+ .ev_cfg_chan_shift = 3,
+ .ev_src = MMA8452_FF_MT_SRC,
+ .ev_src_xe = MMA8452_FF_MT_SRC_XHE,
+ .ev_src_ye = MMA8452_FF_MT_SRC_YHE,
+ .ev_src_ze = MMA8452_FF_MT_SRC_ZHE,
+ .ev_ths = MMA8452_FF_MT_THS,
+ .ev_ths_mask = MMA8452_FF_MT_THS_MASK,
+ .ev_count = MMA8452_FF_MT_COUNT,
+ },
+ [mma8653] = {
+ .chip_id = MMA8653_DEVICE_ID,
+ .channels = mma8653_channels,
+ .num_channels = ARRAY_SIZE(mma8653_channels),
+ .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
+ .ev_cfg = MMA8452_FF_MT_CFG,
+ .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
+ .ev_cfg_chan_shift = 3,
+ .ev_src = MMA8452_FF_MT_SRC,
+ .ev_src_xe = MMA8452_FF_MT_SRC_XHE,
+ .ev_src_ye = MMA8452_FF_MT_SRC_YHE,
+ .ev_src_ze = MMA8452_FF_MT_SRC_ZHE,
+ .ev_ths = MMA8452_FF_MT_THS,
+ .ev_ths_mask = MMA8452_FF_MT_THS_MASK,
+ .ev_count = MMA8452_FF_MT_COUNT,
+ },
+};
+
static struct attribute *mma8452_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
@@ -841,18 +1041,28 @@ static int mma8452_reset(struct i2c_client *client)
return -ETIMEDOUT;
}
+static const struct of_device_id mma8452_dt_ids[] = {
+ { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
+ { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
+ { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
+ { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
+
static int mma8452_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mma8452_data *data;
struct iio_dev *indio_dev;
int ret;
+ const struct of_device_id *match;
- ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
- if (ret < 0)
- return ret;
- if (ret != MMA8452_DEVICE_ID)
+ match = of_match_device(mma8452_dt_ids, &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "unknown device model\n");
return -ENODEV;
+ }
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -861,14 +1071,33 @@ static int mma8452_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->client = client;
mutex_init(&data->lock);
+ data->chip_info = match->data;
+
+ ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
+ if (ret < 0)
+ return ret;
+
+ switch (ret) {
+ case MMA8452_DEVICE_ID:
+ case MMA8453_DEVICE_ID:
+ case MMA8652_DEVICE_ID:
+ case MMA8653_DEVICE_ID:
+ if (ret == data->chip_info->chip_id)
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
+ match->compatible, data->chip_info->chip_id);
i2c_set_clientdata(client, indio_dev);
indio_dev->info = &mma8452_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = mma8452_channels;
- indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
+ indio_dev->channels = data->chip_info->channels;
+ indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->available_scan_masks = mma8452_scan_masks;
ret = mma8452_reset(client);
@@ -892,13 +1121,15 @@ static int mma8452_probe(struct i2c_client *client,
if (client->irq) {
/*
- * Although we enable the transient interrupt source once and
- * for all here the transient event detection itself is not
- * enabled until userspace asks for it by
- * mma8452_write_event_config()
+ * Although we enable the interrupt sources once and for
+ * all here the event detection itself is not enabled until
+ * userspace asks for it by mma8452_write_event_config()
*/
- int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS;
- int enabled_interrupts = MMA8452_INT_TRANS;
+ int supported_interrupts = MMA8452_INT_DRDY |
+ MMA8452_INT_TRANS |
+ MMA8452_INT_FF_MT;
+ int enabled_interrupts = MMA8452_INT_TRANS |
+ MMA8452_INT_FF_MT;
/* Assume wired to INT1 pin */
ret = i2c_smbus_write_byte_data(client,
@@ -987,17 +1218,14 @@ static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
#endif
static const struct i2c_device_id mma8452_id[] = {
- { "mma8452", 0 },
+ { "mma8452", mma8452 },
+ { "mma8453", mma8453 },
+ { "mma8652", mma8652 },
+ { "mma8653", mma8653 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
-static const struct of_device_id mma8452_dt_ids[] = {
- { .compatible = "fsl,mma8452" },
- { }
-};
-MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
-
static struct i2c_driver mma8452_driver = {
.driver = {
.name = "mma8452",
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 771858cb67a1..9408ef3add58 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -26,7 +26,6 @@
#define MMA9553_DRV_NAME "mma9553"
#define MMA9553_IRQ_NAME "mma9553_event"
-#define MMA9553_GPIO_NAME "mma9553_int"
/* Pedometer configuration registers (R/W) */
#define MMA9553_REG_CONF_SLEEPMIN 0x00
@@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
-static int mma9553_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready GPIO interrupt pin */
- gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "ACPI GPIO get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const char *mma9553_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
@@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mma9553_info;
- if (client->irq < 0)
- client->irq = mma9553_gpio_probe(client);
-
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
mma9553_irq_handler,
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
new file mode 100644
index 000000000000..e72e218c2696
--- /dev/null
+++ b/drivers/iio/accel/mxc4005.c
@@ -0,0 +1,567 @@
+/*
+ * 3-axis accelerometer driver for MXC4005XC Memsic sensor
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define MXC4005_DRV_NAME "mxc4005"
+#define MXC4005_IRQ_NAME "mxc4005_event"
+#define MXC4005_REGMAP_NAME "mxc4005_regmap"
+
+#define MXC4005_REG_XOUT_UPPER 0x03
+#define MXC4005_REG_XOUT_LOWER 0x04
+#define MXC4005_REG_YOUT_UPPER 0x05
+#define MXC4005_REG_YOUT_LOWER 0x06
+#define MXC4005_REG_ZOUT_UPPER 0x07
+#define MXC4005_REG_ZOUT_LOWER 0x08
+
+#define MXC4005_REG_INT_MASK1 0x0B
+#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01
+
+#define MXC4005_REG_INT_CLR1 0x01
+#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01
+
+#define MXC4005_REG_CONTROL 0x0D
+#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5)
+#define MXC4005_CONTROL_FSR_SHIFT 5
+
+#define MXC4005_REG_DEVICE_ID 0x0E
+
+enum mxc4005_axis {
+ AXIS_X,
+ AXIS_Y,
+ AXIS_Z,
+};
+
+enum mxc4005_range {
+ MXC4005_RANGE_2G,
+ MXC4005_RANGE_4G,
+ MXC4005_RANGE_8G,
+};
+
+struct mxc4005_data {
+ struct device *dev;
+ struct mutex mutex;
+ struct regmap *regmap;
+ struct iio_trigger *dready_trig;
+ __be16 buffer[8];
+ bool trigger_enabled;
+};
+
+/*
+ * MXC4005 can operate in the following ranges:
+ * +/- 2G, 4G, 8G (the default +/-2G)
+ *
+ * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582
+ * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164
+ * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329
+ */
+static const struct {
+ u8 range;
+ int scale;
+} mxc4005_scale_table[] = {
+ {MXC4005_RANGE_2G, 9582},
+ {MXC4005_RANGE_4G, 19164},
+ {MXC4005_RANGE_8G, 38329},
+};
+
+
+static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329");
+
+static struct attribute *mxc4005_attributes[] = {
+ &iio_const_attr_in_accel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group mxc4005_attrs_group = {
+ .attrs = mxc4005_attributes,
+};
+
+static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MXC4005_REG_XOUT_UPPER:
+ case MXC4005_REG_XOUT_LOWER:
+ case MXC4005_REG_YOUT_UPPER:
+ case MXC4005_REG_YOUT_LOWER:
+ case MXC4005_REG_ZOUT_UPPER:
+ case MXC4005_REG_ZOUT_LOWER:
+ case MXC4005_REG_DEVICE_ID:
+ case MXC4005_REG_CONTROL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MXC4005_REG_INT_CLR1:
+ case MXC4005_REG_INT_MASK1:
+ case MXC4005_REG_CONTROL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config mxc4005_regmap_config = {
+ .name = MXC4005_REGMAP_NAME,
+
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = MXC4005_REG_DEVICE_ID,
+
+ .readable_reg = mxc4005_is_readable_reg,
+ .writeable_reg = mxc4005_is_writeable_reg,
+};
+
+static int mxc4005_read_xyz(struct mxc4005_data *data)
+{
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
+ (u8 *) data->buffer, sizeof(data->buffer));
+ if (ret < 0) {
+ dev_err(data->dev, "failed to read axes\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxc4005_read_axis(struct mxc4005_data *data,
+ unsigned int addr)
+{
+ __be16 reg;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, addr, (u8 *) &reg, sizeof(reg));
+ if (ret < 0) {
+ dev_err(data->dev, "failed to read reg %02x\n", addr);
+ return ret;
+ }
+
+ return be16_to_cpu(reg);
+}
+
+static int mxc4005_read_scale(struct mxc4005_data *data)
+{
+ unsigned int reg;
+ int ret;
+ int i;
+
+ ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &reg);
+ if (ret < 0) {
+ dev_err(data->dev, "failed to read reg_control\n");
+ return ret;
+ }
+
+ i = reg >> MXC4005_CONTROL_FSR_SHIFT;
+
+ if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table))
+ return -EINVAL;
+
+ return mxc4005_scale_table[i].scale;
+}
+
+static int mxc4005_set_scale(struct mxc4005_data *data, int val)
+{
+ unsigned int reg;
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) {
+ if (mxc4005_scale_table[i].scale == val) {
+ reg = i << MXC4005_CONTROL_FSR_SHIFT;
+ ret = regmap_update_bits(data->regmap,
+ MXC4005_REG_CONTROL,
+ MXC4005_REG_CONTROL_MASK_FSR,
+ reg);
+ if (ret < 0)
+ dev_err(data->dev,
+ "failed to write reg_control\n");
+ return ret;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int mxc4005_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mxc4005_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+
+ ret = mxc4005_read_axis(data, chan->address);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ ret = mxc4005_read_scale(data);
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+ *val2 = ret;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mxc4005_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mxc4005_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val != 0)
+ return -EINVAL;
+
+ return mxc4005_set_scale(data, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mxc4005_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = mxc4005_read_raw,
+ .write_raw = mxc4005_write_raw,
+ .attrs = &mxc4005_attrs_group,
+};
+
+static const unsigned long mxc4005_scan_masks[] = {
+ BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+ 0
+};
+
+#define MXC4005_CHANNEL(_axis, _addr) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .address = _addr, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = AXIS_##_axis, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+static const struct iio_chan_spec mxc4005_channels[] = {
+ MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
+ MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
+ MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct mxc4005_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = mxc4005_read_xyz(data);
+ if (ret < 0)
+ goto err;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ pf->timestamp);
+
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int mxc4005_clr_intr(struct mxc4005_data *data)
+{
+ int ret;
+
+ /* clear interrupt */
+ ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
+ MXC4005_REG_INT_CLR1_BIT_DRDYC);
+ if (ret < 0) {
+ dev_err(data->dev, "failed to write to reg_int_clr1\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxc4005_set_trigger_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct mxc4005_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ if (state) {
+ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
+ MXC4005_REG_INT_MASK1_BIT_DRDYE);
+ } else {
+ ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
+ ~MXC4005_REG_INT_MASK1_BIT_DRDYE);
+ }
+
+ if (ret < 0) {
+ mutex_unlock(&data->mutex);
+ dev_err(data->dev, "failed to update reg_int_mask1");
+ return ret;
+ }
+
+ data->trigger_enabled = state;
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+static int mxc4005_trigger_try_reen(struct iio_trigger *trig)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct mxc4005_data *data = iio_priv(indio_dev);
+
+ if (!data->dready_trig)
+ return 0;
+
+ return mxc4005_clr_intr(data);
+}
+
+static const struct iio_trigger_ops mxc4005_trigger_ops = {
+ .set_trigger_state = mxc4005_set_trigger_state,
+ .try_reenable = mxc4005_trigger_try_reen,
+ .owner = THIS_MODULE,
+};
+
+static int mxc4005_gpio_probe(struct i2c_client *client,
+ struct mxc4005_data *data)
+{
+ struct device *dev;
+ struct gpio_desc *gpio;
+ int ret;
+
+ if (!client)
+ return -EINVAL;
+
+ dev = &client->dev;
+
+ gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN);
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "failed to get acpi gpio index\n");
+ return PTR_ERR(gpio);
+ }
+
+ ret = gpiod_to_irq(gpio);
+
+ dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+ return ret;
+}
+
+static int mxc4005_chip_init(struct mxc4005_data *data)
+{
+ int ret;
+ unsigned int reg;
+
+ ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, &reg);
+ if (ret < 0) {
+ dev_err(data->dev, "failed to read chip id\n");
+ return ret;
+ }
+
+ dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
+
+ return 0;
+}
+
+static int mxc4005_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mxc4005_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "failed to initialize regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->dev = &client->dev;
+ data->regmap = regmap;
+
+ ret = mxc4005_chip_init(data);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to initialize chip\n");
+ return ret;
+ }
+
+ mutex_init(&data->mutex);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = mxc4005_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
+ indio_dev->available_scan_masks = mxc4005_scan_masks;
+ indio_dev->name = MXC4005_DRV_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mxc4005_info;
+
+ ret = iio_triggered_buffer_setup(indio_dev,
+ iio_pollfunc_store_time,
+ mxc4005_trigger_handler,
+ NULL);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "failed to setup iio triggered buffer\n");
+ return ret;
+ }
+
+ if (client->irq < 0)
+ client->irq = mxc4005_gpio_probe(client, data);
+
+ if (client->irq > 0) {
+ data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+ "%s-dev%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (!data->dready_trig)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ iio_trigger_generic_data_rdy_poll,
+ NULL,
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ MXC4005_IRQ_NAME,
+ data->dready_trig);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to init threaded irq\n");
+ goto err_buffer_cleanup;
+ }
+
+ data->dready_trig->dev.parent = &client->dev;
+ data->dready_trig->ops = &mxc4005_trigger_ops;
+ iio_trigger_set_drvdata(data->dready_trig, indio_dev);
+ indio_dev->trig = data->dready_trig;
+ iio_trigger_get(indio_dev->trig);
+ ret = iio_trigger_register(data->dready_trig);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to register trigger\n");
+ goto err_trigger_unregister;
+ }
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "unable to register iio device %d\n", ret);
+ goto err_buffer_cleanup;
+ }
+
+ return 0;
+
+err_trigger_unregister:
+ iio_trigger_unregister(data->dready_trig);
+err_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ return ret;
+}
+
+static int mxc4005_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mxc4005_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (data->dready_trig)
+ iio_trigger_unregister(data->dready_trig);
+
+ return 0;
+}
+
+static const struct acpi_device_id mxc4005_acpi_match[] = {
+ {"MXC4005", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
+
+static const struct i2c_device_id mxc4005_id[] = {
+ {"mxc4005", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, mxc4005_id);
+
+static struct i2c_driver mxc4005_driver = {
+ .driver = {
+ .name = MXC4005_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+ },
+ .probe = mxc4005_probe,
+ .remove = mxc4005_remove,
+ .id_table = mxc4005_id,
+};
+
+module_i2c_driver(mxc4005_driver);
+
+MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver");
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index fb9311110424..197a08b4e2f3 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -612,6 +612,7 @@ static const struct iio_info accel_info = {
.attrs = &st_accel_attribute_group,
.read_raw = &st_accel_read_raw,
.write_raw = &st_accel_write_raw,
+ .debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index c764af284c94..85fe7f7247c1 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -50,7 +50,6 @@
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312"
-#define STK8312_GPIO "stk8312_gpio"
#define STK8312_IRQ_NAME "stk8312_event"
/*
@@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
.postdisable = stk8312_buffer_postdisable,
};
-static int stk8312_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int stk8312_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0)
- client->irq = stk8312_gpio_probe(client);
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8312_data_rdy_trig_poll,
NULL,
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 80f77d8704b5..5709d9eb8f34 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -45,7 +45,6 @@
#define STK8BA50_ALL_CHANNEL_SIZE 6
#define STK8BA50_DRIVER_NAME "stk8ba50"
-#define STK8BA50_GPIO "stk8ba50_gpio"
#define STK8BA50_IRQ_NAME "stk8ba50_event"
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
@@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
.postdisable = stk8ba50_buffer_postdisable,
};
-static int stk8ba50_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int stk8ba50_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client,
goto err_power_off;
}
- if (client->irq < 0)
- client->irq = stk8ba50_gpio_probe(client);
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8ba50_data_rdy_trig_poll,
NULL,
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 50c103d75af9..7868c744fd4b 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -149,6 +149,17 @@ config BERLIN2_ADC
Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
temperature measurement.
+config CC10001_ADC
+ tristate "Cosmic Circuits 10001 ADC driver"
+ depends on HAS_IOMEM && HAVE_CLK && REGULATOR
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Cosmic Circuits 10001 ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called cc10001_adc.
+
config DA9150_GPADC
tristate "Dialog DA9150 GPADC driver support"
depends on MFD_DA9150
@@ -161,17 +172,6 @@ config DA9150_GPADC
To compile this driver as a module, choose M here: the module will be
called berlin2-adc.
-config CC10001_ADC
- tristate "Cosmic Circuits 10001 ADC driver"
- depends on HAS_IOMEM && HAVE_CLK && REGULATOR
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- Say yes here to build support for Cosmic Circuits 10001 ADC.
-
- This driver can also be built as a module. If so, the module will be
- called cc10001_adc.
-
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -183,6 +183,17 @@ config EXYNOS_ADC
To compile this driver as a module, choose M here: the module will be
called exynos_adc.
+config HI8435
+ tristate "Holt Integrated Circuits HI-8435 threshold detector"
+ select IIO_TRIGGERED_EVENT
+ depends on SPI
+ help
+ If you say yes here you get support for Holt Integrated Circuits
+ HI-8435 chip.
+
+ This driver can also be built as a module. If so, the module will be
+ called hi8435.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
@@ -361,6 +372,8 @@ config TWL6030_GPADC
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on OF
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to support for Vybrid board analog-to-digital converter.
Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index a0962103e866..99b37a963a1e 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,9 +16,10 @@ obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
-obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
+obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
+obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index b99de00e57b8..01d71588d752 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -528,7 +528,6 @@ static struct attribute *ad799x_event_attributes[] = {
static struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes,
- .name = "events",
};
static const struct iio_info ad7991_info = {
diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c
index 4946d9bf1764..71c806ecc722 100644
--- a/drivers/iio/adc/berlin2-adc.c
+++ b/drivers/iio/adc/berlin2-adc.c
@@ -27,13 +27,13 @@
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
-#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
+#define BERLIN2_SM_CTRL_ADC_SEL_MASK GENMASK(8, 5)
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10)
-#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK (0x3 << 10)
+#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK GENMASK(11, 10)
#define BERLIN2_SM_CTRL_ADC_START BIT(12)
#define BERLIN2_SM_CTRL_ADC_RESET BIT(13)
#define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14)
@@ -50,7 +50,7 @@
#define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */
#define BERLIN2_SM_CTRL_TSEN_RESET BIT(29)
#define BERLIN2_SM_ADC_DATA 0x20
-#define BERLIN2_SM_ADC_MASK 0x3ff
+#define BERLIN2_SM_ADC_MASK GENMASK(9, 0)
#define BERLIN2_SM_ADC_STATUS 0x1c
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
@@ -65,9 +65,9 @@
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
#define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */
-#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK (0x1 << 21)
+#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK BIT(21)
#define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22)
-#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK (0xf << 22)
+#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK GENMASK(25, 22)
struct berlin2_adc_priv {
struct regmap *regmap;
@@ -78,13 +78,13 @@ struct berlin2_adc_priv {
};
#define BERLIN2_ADC_CHANNEL(n, t) \
- { \
- .channel = n, \
- .datasheet_name = "channel"#n, \
- .type = t, \
- .indexed = 1, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- }
+ { \
+ .channel = n, \
+ .datasheet_name = "channel"#n, \
+ .type = t, \
+ .indexed = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ }
static const struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
@@ -111,18 +111,24 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
mutex_lock(&priv->lock);
+ /* Enable the interrupts */
+ regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
+ BERLIN2_SM_ADC_STATUS_INT_EN(channel));
+
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK
- | BERLIN2_SM_CTRL_ADC_START,
- BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START);
+ BERLIN2_SM_CTRL_ADC_RESET |
+ BERLIN2_SM_CTRL_ADC_SEL_MASK |
+ BERLIN2_SM_CTRL_ADC_START,
+ BERLIN2_SM_CTRL_ADC_SEL(channel) |
+ BERLIN2_SM_CTRL_ADC_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
- msecs_to_jiffies(1000));
+ msecs_to_jiffies(1000));
/* Disable the interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
- BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
+ BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
if (ret == 0)
ret = -ETIMEDOUT;
@@ -132,7 +138,7 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
}
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_START, 0);
+ BERLIN2_SM_CTRL_ADC_START, 0);
data = priv->data;
priv->data_available = false;
@@ -149,24 +155,31 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
mutex_lock(&priv->lock);
+ /* Enable interrupts */
+ regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
+ BERLIN2_SM_TSEN_STATUS_INT_EN);
+
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
- BERLIN2_SM_CTRL_ADC_ROTATE);
+ BERLIN2_SM_CTRL_TSEN_RESET |
+ BERLIN2_SM_CTRL_ADC_ROTATE,
+ BERLIN2_SM_CTRL_ADC_ROTATE);
/* Configure the temperature sensor */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
- BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK
- | BERLIN2_SM_TSEN_CTRL_START,
- BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12
- | BERLIN2_SM_TSEN_CTRL_START);
+ BERLIN2_SM_TSEN_CTRL_TRIM_MASK |
+ BERLIN2_SM_TSEN_CTRL_SETTLING_MASK |
+ BERLIN2_SM_TSEN_CTRL_START,
+ BERLIN2_SM_TSEN_CTRL_TRIM(3) |
+ BERLIN2_SM_TSEN_CTRL_SETTLING_12 |
+ BERLIN2_SM_TSEN_CTRL_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
- msecs_to_jiffies(1000));
+ msecs_to_jiffies(1000));
/* Disable interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
- BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
+ BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
if (ret == 0)
ret = -ETIMEDOUT;
@@ -176,7 +189,7 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
}
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
- BERLIN2_SM_TSEN_CTRL_START, 0);
+ BERLIN2_SM_TSEN_CTRL_START, 0);
data = priv->data;
priv->data_available = false;
@@ -187,10 +200,9 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
}
static int berlin2_adc_read_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 berlin2_adc_priv *priv = iio_priv(indio_dev);
int temp;
switch (mask) {
@@ -198,10 +210,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_VOLTAGE)
return -EINVAL;
- /* Enable the interrupts */
- regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
- BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel));
-
*val = berlin2_adc_read(indio_dev, chan->channel);
if (*val < 0)
return *val;
@@ -211,10 +219,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_TEMP)
return -EINVAL;
- /* Enable interrupts */
- regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
- BERLIN2_SM_TSEN_STATUS_INT_EN);
-
temp = berlin2_adc_tsen_read(indio_dev);
if (temp < 0)
return temp;
@@ -306,12 +310,12 @@ static int berlin2_adc_probe(struct platform_device *pdev)
return tsen_irq;
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
- pdev->dev.driver->name, indio_dev);
+ pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
- 0, pdev->dev.driver->name, indio_dev);
+ 0, pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
@@ -328,13 +332,14 @@ static int berlin2_adc_probe(struct platform_device *pdev)
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
+ BERLIN2_SM_CTRL_ADC_POWER,
+ BERLIN2_SM_CTRL_ADC_POWER);
ret = iio_device_register(indio_dev);
if (ret) {
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, 0);
+ BERLIN2_SM_CTRL_ADC_POWER, 0);
return ret;
}
@@ -350,7 +355,7 @@ static int berlin2_adc_remove(struct platform_device *pdev)
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
- BERLIN2_SM_CTRL_ADC_POWER, 0);
+ BERLIN2_SM_CTRL_ADC_POWER, 0);
return 0;
}
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
new file mode 100644
index 000000000000..c73c6c62a6ac
--- /dev/null
+++ b/drivers/iio/adc/hi8435.c
@@ -0,0 +1,534 @@
+/*
+ * Holt Integrated Circuits HI-8435 threshold detector driver
+ *
+ * Copyright (C) 2015 Zodiac Inflight Innovations
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
+
+#define DRV_NAME "hi8435"
+
+/* Register offsets for HI-8435 */
+#define HI8435_CTRL_REG 0x02
+#define HI8435_PSEN_REG 0x04
+#define HI8435_TMDATA_REG 0x1E
+#define HI8435_GOCENHYS_REG 0x3A
+#define HI8435_SOCENHYS_REG 0x3C
+#define HI8435_SO7_0_REG 0x10
+#define HI8435_SO15_8_REG 0x12
+#define HI8435_SO23_16_REG 0x14
+#define HI8435_SO31_24_REG 0x16
+#define HI8435_SO31_0_REG 0x78
+
+#define HI8435_WRITE_OPCODE 0x00
+#define HI8435_READ_OPCODE 0x80
+
+/* CTRL register bits */
+#define HI8435_CTRL_TEST 0x01
+#define HI8435_CTRL_SRST 0x02
+
+struct hi8435_priv {
+ struct spi_device *spi;
+ struct mutex lock;
+
+ unsigned long event_scan_mask; /* soft mask/unmask channels events */
+ unsigned int event_prev_val;
+
+ unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */
+ unsigned threshold_hi[2]; /* GND-Open and Supply-Open thresholds */
+ u8 reg_buffer[3] ____cacheline_aligned;
+};
+
+static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val)
+{
+ reg |= HI8435_READ_OPCODE;
+ return spi_write_then_read(priv->spi, &reg, 1, val, 1);
+}
+
+static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val)
+{
+ int ret;
+ __be16 be_val;
+
+ reg |= HI8435_READ_OPCODE;
+ ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 2);
+ *val = be16_to_cpu(be_val);
+
+ return ret;
+}
+
+static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val)
+{
+ int ret;
+ __be32 be_val;
+
+ reg |= HI8435_READ_OPCODE;
+ ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 4);
+ *val = be32_to_cpu(be_val);
+
+ return ret;
+}
+
+static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val)
+{
+ priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
+ priv->reg_buffer[1] = val;
+
+ return spi_write(priv->spi, priv->reg_buffer, 2);
+}
+
+static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
+{
+ priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
+ priv->reg_buffer[1] = (val >> 8) & 0xff;
+ priv->reg_buffer[2] = val & 0xff;
+
+ return spi_write(priv->spi, priv->reg_buffer, 3);
+}
+
+static int hi8435_read_event_config(struct iio_dev *idev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+
+ return !!(priv->event_scan_mask & BIT(chan->channel));
+}
+
+static int hi8435_write_event_config(struct iio_dev *idev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+
+ priv->event_scan_mask &= ~BIT(chan->channel);
+ if (state)
+ priv->event_scan_mask |= BIT(chan->channel);
+
+ return 0;
+}
+
+static int hi8435_read_event_value(struct iio_dev *idev,
+ 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 hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u8 mode, psen;
+ u16 reg;
+
+ ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
+ if (ret < 0)
+ return ret;
+
+ /* Supply-Open or GND-Open sensing mode */
+ mode = !!(psen & BIT(chan->channel / 8));
+
+ ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+ HI8435_GOCENHYS_REG, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (dir == IIO_EV_DIR_FALLING)
+ *val = ((reg & 0xff) - (reg >> 8)) / 2;
+ else if (dir == IIO_EV_DIR_RISING)
+ *val = ((reg & 0xff) + (reg >> 8)) / 2;
+
+ return IIO_VAL_INT;
+}
+
+static int hi8435_write_event_value(struct iio_dev *idev,
+ 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 hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u8 mode, psen;
+ u16 reg;
+
+ ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
+ if (ret < 0)
+ return ret;
+
+ /* Supply-Open or GND-Open sensing mode */
+ mode = !!(psen & BIT(chan->channel / 8));
+
+ ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+ HI8435_GOCENHYS_REG, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (dir == IIO_EV_DIR_FALLING) {
+ /* falling threshold range 2..21V, hysteresis minimum 2V */
+ if (val < 2 || val > 21 || (val + 2) > priv->threshold_hi[mode])
+ return -EINVAL;
+
+ if (val == priv->threshold_lo[mode])
+ return 0;
+
+ priv->threshold_lo[mode] = val;
+
+ /* hysteresis must not be odd */
+ if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
+ priv->threshold_hi[mode]--;
+ } else if (dir == IIO_EV_DIR_RISING) {
+ /* rising threshold range 3..22V, hysteresis minimum 2V */
+ if (val < 3 || val > 22 || val < (priv->threshold_lo[mode] + 2))
+ return -EINVAL;
+
+ if (val == priv->threshold_hi[mode])
+ return 0;
+
+ priv->threshold_hi[mode] = val;
+
+ /* hysteresis must not be odd */
+ if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
+ priv->threshold_lo[mode]++;
+ }
+
+ /* program thresholds */
+ mutex_lock(&priv->lock);
+
+ ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+ HI8435_GOCENHYS_REG, &reg);
+ if (ret < 0) {
+ mutex_unlock(&priv->lock);
+ return ret;
+ }
+
+ /* hysteresis */
+ reg = priv->threshold_hi[mode] - priv->threshold_lo[mode];
+ reg <<= 8;
+ /* threshold center */
+ reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]);
+
+ ret = hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG :
+ HI8435_GOCENHYS_REG, reg);
+
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static int hi8435_debugfs_reg_access(struct iio_dev *idev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u8 val;
+
+ if (readval != NULL) {
+ ret = hi8435_readb(priv, reg, &val);
+ *readval = val;
+ } else {
+ val = (u8)writeval;
+ ret = hi8435_writeb(priv, reg, val);
+ }
+
+ return ret;
+}
+
+static const struct iio_event_spec hi8435_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ }, {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static int hi8435_get_sensing_mode(struct iio_dev *idev,
+ const struct iio_chan_spec *chan)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u8 reg;
+
+ ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
+ if (ret < 0)
+ return ret;
+
+ return !!(reg & BIT(chan->channel / 8));
+}
+
+static int hi8435_set_sensing_mode(struct iio_dev *idev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u8 reg;
+
+ mutex_lock(&priv->lock);
+
+ ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
+ if (ret < 0) {
+ mutex_unlock(&priv->lock);
+ return ret;
+ }
+
+ reg &= ~BIT(chan->channel / 8);
+ if (mode)
+ reg |= BIT(chan->channel / 8);
+
+ ret = hi8435_writeb(priv, HI8435_PSEN_REG, reg);
+
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static const char * const hi8435_sensing_modes[] = { "GND-Open",
+ "Supply-Open" };
+
+static const struct iio_enum hi8435_sensing_mode = {
+ .items = hi8435_sensing_modes,
+ .num_items = ARRAY_SIZE(hi8435_sensing_modes),
+ .get = hi8435_get_sensing_mode,
+ .set = hi8435_set_sensing_mode,
+};
+
+static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
+ IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
+ {},
+};
+
+#define HI8435_VOLTAGE_CHANNEL(num) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = num, \
+ .event_spec = hi8435_events, \
+ .num_event_specs = ARRAY_SIZE(hi8435_events), \
+ .ext_info = hi8435_ext_info, \
+}
+
+static const struct iio_chan_spec hi8435_channels[] = {
+ HI8435_VOLTAGE_CHANNEL(0),
+ HI8435_VOLTAGE_CHANNEL(1),
+ HI8435_VOLTAGE_CHANNEL(2),
+ HI8435_VOLTAGE_CHANNEL(3),
+ HI8435_VOLTAGE_CHANNEL(4),
+ HI8435_VOLTAGE_CHANNEL(5),
+ HI8435_VOLTAGE_CHANNEL(6),
+ HI8435_VOLTAGE_CHANNEL(7),
+ HI8435_VOLTAGE_CHANNEL(8),
+ HI8435_VOLTAGE_CHANNEL(9),
+ HI8435_VOLTAGE_CHANNEL(10),
+ HI8435_VOLTAGE_CHANNEL(11),
+ HI8435_VOLTAGE_CHANNEL(12),
+ HI8435_VOLTAGE_CHANNEL(13),
+ HI8435_VOLTAGE_CHANNEL(14),
+ HI8435_VOLTAGE_CHANNEL(15),
+ HI8435_VOLTAGE_CHANNEL(16),
+ HI8435_VOLTAGE_CHANNEL(17),
+ HI8435_VOLTAGE_CHANNEL(18),
+ HI8435_VOLTAGE_CHANNEL(19),
+ HI8435_VOLTAGE_CHANNEL(20),
+ HI8435_VOLTAGE_CHANNEL(21),
+ HI8435_VOLTAGE_CHANNEL(22),
+ HI8435_VOLTAGE_CHANNEL(23),
+ HI8435_VOLTAGE_CHANNEL(24),
+ HI8435_VOLTAGE_CHANNEL(25),
+ HI8435_VOLTAGE_CHANNEL(26),
+ HI8435_VOLTAGE_CHANNEL(27),
+ HI8435_VOLTAGE_CHANNEL(28),
+ HI8435_VOLTAGE_CHANNEL(29),
+ HI8435_VOLTAGE_CHANNEL(30),
+ HI8435_VOLTAGE_CHANNEL(31),
+ IIO_CHAN_SOFT_TIMESTAMP(32),
+};
+
+static const struct iio_info hi8435_info = {
+ .driver_module = THIS_MODULE,
+ .read_event_config = &hi8435_read_event_config,
+ .write_event_config = hi8435_write_event_config,
+ .read_event_value = &hi8435_read_event_value,
+ .write_event_value = &hi8435_write_event_value,
+ .debugfs_reg_access = &hi8435_debugfs_reg_access,
+};
+
+static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
+{
+ struct hi8435_priv *priv = iio_priv(idev);
+ enum iio_event_direction dir;
+ unsigned int i;
+ unsigned int status = priv->event_prev_val ^ val;
+
+ if (!status)
+ return;
+
+ for_each_set_bit(i, &priv->event_scan_mask, 32) {
+ if (status & BIT(i)) {
+ dir = val & BIT(i) ? IIO_EV_DIR_RISING :
+ IIO_EV_DIR_FALLING;
+ iio_push_event(idev,
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+ IIO_EV_TYPE_THRESH, dir),
+ iio_get_time_ns());
+ }
+ }
+
+ priv->event_prev_val = val;
+}
+
+static irqreturn_t hi8435_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *idev = pf->indio_dev;
+ struct hi8435_priv *priv = iio_priv(idev);
+ u32 val;
+ int ret;
+
+ ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val);
+ if (ret < 0)
+ goto err_read;
+
+ hi8435_iio_push_event(idev, val);
+
+err_read:
+ iio_trigger_notify_done(idev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int hi8435_probe(struct spi_device *spi)
+{
+ struct iio_dev *idev;
+ struct hi8435_priv *priv;
+ struct gpio_desc *reset_gpio;
+ int ret;
+
+ idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
+ if (!idev)
+ return -ENOMEM;
+
+ priv = iio_priv(idev);
+ priv->spi = spi;
+
+ reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
+ if (IS_ERR(reset_gpio)) {
+ /* chip s/w reset if h/w reset failed */
+ hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
+ hi8435_writeb(priv, HI8435_CTRL_REG, 0);
+ } else {
+ udelay(5);
+ gpiod_set_value(reset_gpio, 1);
+ }
+
+ spi_set_drvdata(spi, idev);
+ mutex_init(&priv->lock);
+
+ idev->dev.parent = &spi->dev;
+ idev->name = spi_get_device_id(spi)->name;
+ idev->modes = INDIO_DIRECT_MODE;
+ idev->info = &hi8435_info;
+ idev->channels = hi8435_channels;
+ idev->num_channels = ARRAY_SIZE(hi8435_channels);
+
+ /* unmask all events */
+ priv->event_scan_mask = ~(0);
+ /*
+ * There is a restriction in the chip - the hysteresis can not be odd.
+ * If the hysteresis is set to odd value then chip gets into lock state
+ * and not functional anymore.
+ * After chip reset the thresholds are in undefined state, so we need to
+ * initialize thresholds to some initial values and then prevent
+ * userspace setting odd hysteresis.
+ *
+ * Set threshold low voltage to 2V, threshold high voltage to 4V
+ * for both GND-Open and Supply-Open sensing modes.
+ */
+ priv->threshold_lo[0] = priv->threshold_lo[1] = 2;
+ priv->threshold_hi[0] = priv->threshold_hi[1] = 4;
+ hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206);
+ hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206);
+
+ ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler);
+ if (ret)
+ return ret;
+
+ ret = iio_device_register(idev);
+ if (ret < 0) {
+ dev_err(&spi->dev, "unable to register device\n");
+ goto unregister_triggered_event;
+ }
+
+ return 0;
+
+unregister_triggered_event:
+ iio_triggered_event_cleanup(idev);
+ return ret;
+}
+
+static int hi8435_remove(struct spi_device *spi)
+{
+ struct iio_dev *idev = spi_get_drvdata(spi);
+
+ iio_device_unregister(idev);
+ iio_triggered_event_cleanup(idev);
+
+ return 0;
+}
+
+static const struct of_device_id hi8435_dt_ids[] = {
+ { .compatible = "holt,hi8435" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
+
+static const struct spi_device_id hi8435_id[] = {
+ { "hi8435", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(spi, hi8435_id);
+
+static struct spi_driver hi8435_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(hi8435_dt_ids),
+ },
+ .probe = hi8435_probe,
+ .remove = hi8435_remove,
+ .id_table = hi8435_id,
+};
+module_spi_driver(hi8435_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("HI-8435 threshold detector");
diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c
index 44bf815adb6c..54a8302aaace 100644
--- a/drivers/iio/adc/max1027.c
+++ b/drivers/iio/adc/max1027.c
@@ -508,6 +508,7 @@ static int max1027_remove(struct spi_device *spi)
static struct spi_driver max1027_driver = {
.driver = {
.name = "max1027",
+ .of_match_table = of_match_ptr(max1027_adc_dt_ids),
.owner = THIS_MODULE,
},
.probe = max1027_probe,
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 1b3b74be5c20..929508e5266c 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1007,7 +1007,6 @@ static struct attribute *max1363_event_attributes[] = {
static struct attribute_group max1363_event_attribute_group = {
.attrs = max1363_event_attributes,
- .name = "events",
};
static int max1363_update_scan_mode(struct iio_dev *indio_dev,
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index b19e4f9d16e0..41a21e986c1a 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -404,6 +404,7 @@ MODULE_DEVICE_TABLE(spi, mcp320x_id);
static struct spi_driver mcp320x_driver = {
.driver = {
.name = "mcp320x",
+ .of_match_table = of_match_ptr(mcp320x_dt_ids),
.owner = THIS_MODULE,
},
.probe = mcp320x_probe,
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index 915be6b60097..98c0d2b444bf 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -174,6 +174,13 @@ static int adc128_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id adc128_of_match[] = {
+ { .compatible = "ti,adc128s052", },
+ { .compatible = "ti,adc122s021", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, adc128_of_match);
+
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
@@ -184,6 +191,7 @@ MODULE_DEVICE_TABLE(spi, adc128_id);
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
+ .of_match_table = of_match_ptr(adc128_of_match),
.owner = THIS_MODULE,
},
.probe = adc128_probe,
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index df12c57e6ce0..becbb0aef232 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -875,6 +875,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = {
},
{ /* end */ }
};
+MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl);
static int twl6030_gpadc_probe(struct platform_device *pdev)
{
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 6bf4c20eb231..599cde3d03a1 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -34,8 +34,11 @@
#include <linux/err.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/driver.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "vf610-adc"
@@ -170,6 +173,7 @@ struct vf610_adc {
u32 sample_freq_avail[5];
struct completion completion;
+ u16 buffer[8];
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
@@ -505,12 +509,24 @@ static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.ext_info = vf610_ext_info, \
+ .scan_index = (_idx), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
}
#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .scan_index = (_idx), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
@@ -531,6 +547,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
+ IIO_CHAN_SOFT_TIMESTAMP(32),
/* sentinel */
};
@@ -559,13 +576,20 @@ static int vf610_adc_read_data(struct vf610_adc *info)
static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
{
- struct vf610_adc *info = (struct vf610_adc *)dev_id;
+ struct iio_dev *indio_dev = (struct iio_dev *)dev_id;
+ struct vf610_adc *info = iio_priv(indio_dev);
int coco;
coco = readl(info->regs + VF610_REG_ADC_HS);
if (coco & VF610_ADC_HS_COCO0) {
info->value = vf610_adc_read_data(info);
- complete(&info->completion);
+ if (iio_buffer_enabled(indio_dev)) {
+ info->buffer[0] = info->value;
+ iio_push_to_buffers_with_timestamp(indio_dev,
+ info->buffer, iio_get_time_ns());
+ iio_trigger_notify_done(indio_dev->trig);
+ } else
+ complete(&info->completion);
}
return IRQ_HANDLED;
@@ -613,8 +637,12 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
- reinit_completion(&info->completion);
+ if (iio_buffer_enabled(indio_dev)) {
+ mutex_unlock(&indio_dev->mlock);
+ return -EBUSY;
+ }
+ reinit_completion(&info->completion);
hc_cfg = VF610_ADC_ADCHC(chan->channel);
hc_cfg |= VF610_ADC_AIEN;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
@@ -694,6 +722,56 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int vf610_adc_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int channel;
+ int ret;
+ int val;
+
+ ret = iio_triggered_buffer_postenable(indio_dev);
+ if (ret)
+ return ret;
+
+ val = readl(info->regs + VF610_REG_ADC_GC);
+ val |= VF610_ADC_ADCON;
+ writel(val, info->regs + VF610_REG_ADC_GC);
+
+ channel = find_first_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength);
+
+ val = VF610_ADC_ADCHC(channel);
+ val |= VF610_ADC_AIEN;
+
+ writel(val, info->regs + VF610_REG_ADC_HC0);
+
+ return 0;
+}
+
+static int vf610_adc_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct vf610_adc *info = iio_priv(indio_dev);
+ unsigned int hc_cfg = 0;
+ int val;
+
+ val = readl(info->regs + VF610_REG_ADC_GC);
+ val &= ~VF610_ADC_ADCON;
+ writel(val, info->regs + VF610_REG_ADC_GC);
+
+ hc_cfg |= VF610_ADC_CONV_DISABLE;
+ hc_cfg &= ~VF610_ADC_AIEN;
+
+ writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+ return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+ .postenable = &vf610_adc_buffer_postenable,
+ .predisable = &vf610_adc_buffer_predisable,
+ .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
static int vf610_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
@@ -753,7 +831,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,
- dev_name(&pdev->dev), info);
+ dev_name(&pdev->dev), indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
return ret;
@@ -806,15 +884,23 @@ static int vf610_adc_probe(struct platform_device *pdev)
vf610_adc_cfg_init(info);
vf610_adc_hw_init(info);
+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+ NULL, &iio_triggered_buffer_setup_ops);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't initialise the buffer\n");
+ goto error_iio_device_register;
+ }
+
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
- goto error_iio_device_register;
+ goto error_adc_buffer_init;
}
return 0;
-
+error_adc_buffer_init:
+ iio_triggered_buffer_cleanup(indio_dev);
error_iio_device_register:
clk_disable_unprepare(info->clk);
error_adc_clk_enable:
@@ -829,6 +915,7 @@ static int vf610_adc_remove(struct platform_device *pdev)
struct vf610_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index ce93bd8e3f68..0370624a35db 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -273,33 +273,13 @@ static void xadc_zynq_unmask_worker(struct work_struct *work)
schedule_delayed_work(&xadc->zynq_unmask_work,
msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
}
-}
-
-static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid)
-{
- struct iio_dev *indio_dev = devid;
- struct xadc *xadc = iio_priv(indio_dev);
- unsigned int alarm;
-
- spin_lock_irq(&xadc->lock);
- alarm = xadc->zynq_alarm;
- xadc->zynq_alarm = 0;
- spin_unlock_irq(&xadc->lock);
-
- xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm));
- /* unmask the required interrupts in timer. */
- schedule_delayed_work(&xadc->zynq_unmask_work,
- msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
-
- return IRQ_HANDLED;
}
static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
{
struct iio_dev *indio_dev = devid;
struct xadc *xadc = iio_priv(indio_dev);
- irqreturn_t ret = IRQ_HANDLED;
uint32_t status;
xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
@@ -321,18 +301,23 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
status &= XADC_ZYNQ_INT_ALARM_MASK;
if (status) {
- xadc->zynq_alarm |= status;
xadc->zynq_masked_alarm |= status;
/*
* mask the current event interrupt,
* unmask it when the interrupt is no more active.
*/
xadc_zynq_update_intmsk(xadc, 0, 0);
- ret = IRQ_WAKE_THREAD;
+
+ xadc_handle_events(indio_dev,
+ xadc_zynq_transform_alarm(status));
+
+ /* unmask the required interrupts in timer. */
+ schedule_delayed_work(&xadc->zynq_unmask_work,
+ msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
}
spin_unlock(&xadc->lock);
- return ret;
+ return IRQ_HANDLED;
}
#define XADC_ZYNQ_TCK_RATE_MAX 50000000
@@ -437,7 +422,6 @@ static const struct xadc_ops xadc_zynq_ops = {
.setup = xadc_zynq_setup,
.get_dclk_rate = xadc_zynq_get_dclk_rate,
.interrupt_handler = xadc_zynq_interrupt_handler,
- .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
.update_alarm = xadc_zynq_update_alarm,
};
@@ -1225,9 +1209,8 @@ static int xadc_probe(struct platform_device *pdev)
if (ret)
goto err_free_samplerate_trigger;
- ret = request_threaded_irq(irq, xadc->ops->interrupt_handler,
- xadc->ops->threaded_interrupt_handler,
- 0, dev_name(&pdev->dev), indio_dev);
+ ret = request_irq(irq, xadc->ops->interrupt_handler, 0,
+ dev_name(&pdev->dev), indio_dev);
if (ret)
goto err_clk_disable_unprepare;
diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h
index 54adc5087210..f6f081965647 100644
--- a/drivers/iio/adc/xilinx-xadc.h
+++ b/drivers/iio/adc/xilinx-xadc.h
@@ -60,7 +60,6 @@ struct xadc {
enum xadc_external_mux_mode external_mux_mode;
- unsigned int zynq_alarm;
unsigned int zynq_masked_alarm;
unsigned int zynq_intmask;
struct delayed_work zynq_unmask_work;
@@ -79,7 +78,6 @@ struct xadc_ops {
void (*update_alarm)(struct xadc *, unsigned int);
unsigned long (*get_dclk_rate)(struct xadc *);
irqreturn_t (*interrupt_handler)(int, void *);
- irqreturn_t (*threaded_interrupt_handler)(int, void *);
unsigned int flags;
};
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index c0d364ebaea8..32b82a2dc894 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -195,6 +195,7 @@ static const struct spi_device_id ad8366_id[] = {
{"ad8366", 0},
{}
};
+MODULE_DEVICE_TABLE(spi, ad8366_id);
static struct spi_driver ad8366_driver = {
.driver = {
diff --git a/drivers/iio/buffer/Kconfig b/drivers/iio/buffer/Kconfig
new file mode 100644
index 000000000000..0a7b2fd3699b
--- /dev/null
+++ b/drivers/iio/buffer/Kconfig
@@ -0,0 +1,24 @@
+#
+# Industrial I/O generic buffer implementations
+#
+# When adding new entries keep the list in alphabetical order
+
+config IIO_BUFFER_CB
+ tristate "IIO callback buffer used for push in-kernel interfaces"
+ help
+ Should be selected by any drivers that do in-kernel push
+ usage. That is, those where the data is pushed to the consumer.
+
+config IIO_KFIFO_BUF
+ tristate "Industrial I/O buffering based on kfifo"
+ help
+ A simple fifo based on kfifo. Note that this currently provides
+ no buffer events so it is up to userspace to work out how
+ often to read from the buffer.
+
+config IIO_TRIGGERED_BUFFER
+ tristate
+ select IIO_TRIGGER
+ select IIO_KFIFO_BUF
+ help
+ Provides helper functions for setting up triggered buffers.
diff --git a/drivers/iio/buffer/Makefile b/drivers/iio/buffer/Makefile
new file mode 100644
index 000000000000..4d193b9a9123
--- /dev/null
+++ b/drivers/iio/buffer/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the industrial I/O buffer implementations
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
+obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer/industrialio-buffer-cb.c
index 1648e6e5a848..323079c3ccce 100644
--- a/drivers/iio/buffer_cb.c
+++ b/drivers/iio/buffer/industrialio-buffer-cb.c
@@ -1,4 +1,12 @@
+/* The industrial I/O callback buffer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -124,3 +132,7 @@ struct iio_channel
return cb_buffer->channels;
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("Industrial I/O callback buffer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c
index 4b2858ba1fd6..4b2858ba1fd6 100644
--- a/drivers/iio/industrialio-triggered-buffer.c
+++ b/drivers/iio/buffer/industrialio-triggered-buffer.c
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c
index c5b999f0c519..c5b999f0c519 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
new file mode 100644
index 000000000000..3061b7299f0f
--- /dev/null
+++ b/drivers/iio/chemical/Kconfig
@@ -0,0 +1,15 @@
+#
+# Chemical sensors
+#
+
+menu "Chemical Sensors"
+
+config VZ89X
+ tristate "SGX Sensortech MiCS VZ89X VOC sensor"
+ depends on I2C
+ help
+ Say Y here to build I2C interface support for the SGX
+ Sensortech MiCS VZ89X VOC (Volatile Organic Compounds)
+ sensors
+
+endmenu
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
new file mode 100644
index 000000000000..7292f2ded587
--- /dev/null
+++ b/drivers/iio/chemical/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for IIO chemical sensors
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_VZ89X) += vz89x.o
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
new file mode 100644
index 000000000000..11e59a5a5112
--- /dev/null
+++ b/drivers/iio/chemical/vz89x.c
@@ -0,0 +1,256 @@
+/*
+ * vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define VZ89X_REG_MEASUREMENT 0x09
+#define VZ89X_REG_MEASUREMENT_SIZE 6
+
+#define VZ89X_VOC_CO2_IDX 0
+#define VZ89X_VOC_SHORT_IDX 1
+#define VZ89X_VOC_TVOC_IDX 2
+#define VZ89X_VOC_RESISTANCE_IDX 3
+
+struct vz89x_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ unsigned long last_update;
+
+ u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
+};
+
+static const struct iio_chan_spec vz89x_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+ .address = VZ89X_VOC_CO2_IDX,
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .address = VZ89X_VOC_SHORT_IDX,
+ .extend_name = "short",
+ },
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .modified = 1,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+ .address = VZ89X_VOC_TVOC_IDX,
+ },
+ {
+ .type = IIO_RESISTANCE,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .address = VZ89X_VOC_RESISTANCE_IDX,
+ },
+};
+
+static IIO_CONST_ATTR(in_concentration_co2_scale, "0.00000698689");
+static IIO_CONST_ATTR(in_concentration_voc_scale, "0.00000000436681223");
+
+static struct attribute *vz89x_attributes[] = {
+ &iio_const_attr_in_concentration_co2_scale.dev_attr.attr,
+ &iio_const_attr_in_concentration_voc_scale.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group vz89x_attrs_group = {
+ .attrs = vz89x_attributes,
+};
+
+/*
+ * Chipset sometime updates in the middle of a reading causing it to reset the
+ * data pointer, and causing invalid reading of previous data.
+ * We can check for this by reading MSB of the resistance reading that is
+ * always zero, and by also confirming the VOC_short isn't zero.
+ */
+
+static int vz89x_measurement_is_valid(struct vz89x_data *data)
+{
+ if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
+ return 1;
+
+ return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
+}
+
+static int vz89x_get_measurement(struct vz89x_data *data)
+{
+ int ret;
+ int i;
+
+ /* sensor can only be polled once a second max per datasheet */
+ if (!time_after(jiffies, data->last_update + HZ))
+ return 0;
+
+ ret = i2c_smbus_write_word_data(data->client,
+ VZ89X_REG_MEASUREMENT, 0);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
+ ret = i2c_smbus_read_byte(data->client);
+ if (ret < 0)
+ return ret;
+ data->buffer[i] = ret;
+ }
+
+ ret = vz89x_measurement_is_valid(data);
+ if (ret)
+ return -EAGAIN;
+
+ data->last_update = jiffies;
+
+ return 0;
+}
+
+static int vz89x_get_resistance_reading(struct vz89x_data *data)
+{
+ u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
+
+ return buf[0] | (buf[1] << 8);
+}
+
+static int vz89x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct vz89x_data *data = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->lock);
+ ret = vz89x_get_measurement(data);
+ mutex_unlock(&data->lock);
+
+ if (ret)
+ return ret;
+
+ switch (chan->address) {
+ case VZ89X_VOC_CO2_IDX:
+ case VZ89X_VOC_SHORT_IDX:
+ case VZ89X_VOC_TVOC_IDX:
+ *val = data->buffer[chan->address];
+ return IIO_VAL_INT;
+ case VZ89X_VOC_RESISTANCE_IDX:
+ *val = vz89x_get_resistance_reading(data);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_RESISTANCE:
+ *val = 10;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->address) {
+ case VZ89X_VOC_CO2_IDX:
+ *val = 44;
+ *val2 = 250000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case VZ89X_VOC_TVOC_IDX:
+ *val = -13;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static const struct iio_info vz89x_info = {
+ .attrs = &vz89x_attrs_group,
+ .read_raw = vz89x_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int vz89x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct vz89x_data *data;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BYTE))
+ return -ENODEV;
+
+ 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;
+ data->last_update = jiffies - HZ;
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &vz89x_info,
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ indio_dev->channels = vz89x_channels;
+ indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id vz89x_id[] = {
+ { "vz89x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vz89x_id);
+
+static const struct of_device_id vz89x_dt_ids[] = {
+ { .compatible = "sgx,vz89x" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
+
+static struct i2c_driver vz89x_driver = {
+ .driver = {
+ .name = "vz89x",
+ .of_match_table = of_match_ptr(vz89x_dt_ids),
+ },
+ .probe = vz89x_probe,
+ .id_table = vz89x_id,
+};
+module_i2c_driver(vz89x_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 790f106d719c..26a6026de614 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,5 +3,6 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/ms_sensors/Kconfig"
source "drivers/iio/common/ssp_sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index b1e4d9c9591c..585da6a1b188 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,5 +8,6 @@
# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
+obj-y += ms_sensors/
obj-y += ssp_sensors/
obj-y += st_sensors/
diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
new file mode 100644
index 000000000000..b28a92b97cf9
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Kconfig
@@ -0,0 +1,6 @@
+#
+# Measurements Specialties sensors common library
+#
+
+config IIO_MS_SENSORS_I2C
+ tristate
diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
new file mode 100644
index 000000000000..7846428abe06
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Measurement Specialties sensor common modules.
+#
+
+obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
new file mode 100644
index 000000000000..669dc7c270f5
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -0,0 +1,652 @@
+/*
+ * Measurements Specialties driver common i2c functions
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include "ms_sensors_i2c.h"
+
+/* Conversion times in us */
+static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
+ 13000, 7000 };
+static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
+ 5000, 8000 };
+static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
+ 4100, 8220, 16440 };
+
+#define MS_SENSORS_SERIAL_READ_MSB 0xFA0F
+#define MS_SENSORS_SERIAL_READ_LSB 0xFCC9
+#define MS_SENSORS_CONFIG_REG_WRITE 0xE6
+#define MS_SENSORS_CONFIG_REG_READ 0xE7
+#define MS_SENSORS_HT_T_CONVERSION_START 0xF3
+#define MS_SENSORS_HT_H_CONVERSION_START 0xF5
+
+#define MS_SENSORS_TP_PROM_READ 0xA0
+#define MS_SENSORS_TP_T_CONVERSION_START 0x50
+#define MS_SENSORS_TP_P_CONVERSION_START 0x40
+#define MS_SENSORS_TP_ADC_READ 0x00
+
+#define MS_SENSORS_NO_READ_CMD 0xFF
+
+/**
+ * ms_sensors_reset() - Reset function
+ * @cli: pointer to device client
+ * @cmd: reset cmd. Depends on device in use
+ * @delay: usleep minimal delay after reset command is issued
+ *
+ * Generic I2C reset function for Measurement Specialties devices.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay)
+{
+ int ret;
+ struct i2c_client *client = cli;
+
+ ret = i2c_smbus_write_byte(client, cmd);
+ if (ret) {
+ dev_err(&client->dev, "Failed to reset device\n");
+ return ret;
+ }
+ usleep_range(delay, delay + 1000);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_reset);
+
+/**
+ * ms_sensors_read_prom_word() - PROM word read function
+ * @cli: pointer to device client
+ * @cmd: PROM read cmd. Depends on device and prom id
+ * @word: pointer to word destination value
+ *
+ * Generic i2c prom word read function for Measurement Specialties devices.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
+{
+ int ret;
+ struct i2c_client *client = (struct i2c_client *)cli;
+
+ ret = i2c_smbus_read_word_swapped(client, cmd);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read prom word\n");
+ return ret;
+ }
+ *word = ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_prom_word);
+
+/**
+ * ms_sensors_convert_and_read() - ADC conversion & read function
+ * @cli: pointer to device client
+ * @conv: ADC conversion command. Depends on device in use
+ * @rd: ADC read command. Depends on device in use
+ * @delay: usleep minimal delay after conversion command is issued
+ * @adc: pointer to ADC destination value
+ *
+ * Generic ADC conversion & read function for Measurement Specialties
+ * devices.
+ * The function will issue conversion command, sleep appopriate delay, and
+ * issue command to read ADC.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc)
+{
+ int ret;
+ __be32 buf = 0;
+ struct i2c_client *client = (struct i2c_client *)cli;
+
+ /* Trigger conversion */
+ ret = i2c_smbus_write_byte(client, conv);
+ if (ret)
+ goto err;
+ usleep_range(delay, delay + 1000);
+
+ /* Retrieve ADC value */
+ if (rd != MS_SENSORS_NO_READ_CMD)
+ ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
+ else
+ ret = i2c_master_recv(client, (u8 *)&buf, 3);
+ if (ret < 0)
+ goto err;
+
+ dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
+ *adc = be32_to_cpu(buf) >> 8;
+
+ return 0;
+err:
+ dev_err(&client->dev, "Unable to make sensor adc conversion\n");
+ return ret;
+}
+EXPORT_SYMBOL(ms_sensors_convert_and_read);
+
+/**
+ * ms_sensors_crc_valid() - CRC check function
+ * @value: input and CRC compare value
+ *
+ * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
+ * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
+ * The argument contains CRC value in LSB byte while the bytes 1 and 2
+ * are used for CRC computation.
+ *
+ * Return: 1 if CRC is valid, 0 otherwise.
+ */
+static bool ms_sensors_crc_valid(u32 value)
+{
+ u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
+ u32 msb = 0x800000;
+ u32 mask = 0xFF8000;
+ u32 result = value & 0xFFFF00;
+ u8 crc = value & 0xFF;
+
+ while (msb != 0x80) {
+ if (result & msb)
+ result = ((result ^ polynom) & mask)
+ | (result & ~mask);
+ msb >>= 1;
+ mask >>= 1;
+ polynom >>= 1;
+ }
+
+ return result == crc;
+}
+
+/**
+ * ms_sensors_read_serial() - Serial number read function
+ * @cli: pointer to i2c client
+ * @sn: pointer to 64-bits destination value
+ *
+ * Generic i2c serial number read function for Measurement Specialties devices.
+ * This function is used for TSYS02d, HTU21, MS8607 chipset.
+ * Refer to datasheet:
+ * http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
+ *
+ * Sensor raw MSB serial number format is the following :
+ * [ SNB3, CRC, SNB2, CRC, SNB1, CRC, SNB0, CRC]
+ * Sensor raw LSB serial number format is the following :
+ * [ X, X, SNC1, SNC0, CRC, SNA1, SNA0, CRC]
+ * The resulting serial number is following :
+ * [ SNA1, SNA0, SNB3, SNB2, SNB1, SNB0, SNC1, SNC0]
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_serial(struct i2c_client *client, u64 *sn)
+{
+ u8 i;
+ __be64 rcv_buf = 0;
+ u64 rcv_val;
+ __be16 send_buf;
+ int ret;
+
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 2,
+ .buf = (__u8 *)&send_buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .buf = (__u8 *)&rcv_buf,
+ },
+ };
+
+ /* Read MSB part of serial number */
+ send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
+ msg[1].len = 8;
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read device serial number");
+ return ret;
+ }
+
+ rcv_val = be64_to_cpu(rcv_buf);
+ dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
+
+ for (i = 0; i < 64; i += 16) {
+ if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFF))
+ return -ENODEV;
+ }
+
+ *sn = (((rcv_val >> 32) & 0xFF000000) |
+ ((rcv_val >> 24) & 0x00FF0000) |
+ ((rcv_val >> 16) & 0x0000FF00) |
+ ((rcv_val >> 8) & 0x000000FF)) << 16;
+
+ /* Read LSB part of serial number */
+ send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
+ msg[1].len = 6;
+ rcv_buf = 0;
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read device serial number");
+ return ret;
+ }
+
+ rcv_val = be64_to_cpu(rcv_buf) >> 16;
+ dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
+
+ for (i = 0; i < 48; i += 24) {
+ if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFFFF))
+ return -ENODEV;
+ }
+
+ *sn |= (rcv_val & 0xFFFF00) << 40 | (rcv_val >> 32);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_serial);
+
+static int ms_sensors_read_config_reg(struct i2c_client *client,
+ u8 *config_reg)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte(client, MS_SENSORS_CONFIG_REG_READ);
+ if (ret) {
+ dev_err(&client->dev, "Unable to read config register");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, config_reg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read config register");
+ return ret;
+ }
+ dev_dbg(&client->dev, "Config register :%x\n", *config_reg);
+
+ return 0;
+}
+
+/**
+ * ms_sensors_write_resolution() - Set resolution function
+ * @dev_data: pointer to temperature/humidity device data
+ * @i: resolution index to set
+ *
+ * This function will program the appropriate resolution based on the index
+ * provided when user space will set samp_freq channel.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data,
+ u8 i)
+{
+ u8 config_reg;
+ int ret;
+
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ if (ret)
+ return ret;
+
+ config_reg &= 0x7E;
+ config_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
+
+ return i2c_smbus_write_byte_data(dev_data->client,
+ MS_SENSORS_CONFIG_REG_WRITE,
+ config_reg);
+}
+EXPORT_SYMBOL(ms_sensors_write_resolution);
+
+/**
+ * ms_sensors_show_battery_low() - Show device battery low indicator
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer to write result
+ *
+ * This function will read battery indicator value in the device and
+ * return 1 if the device voltage is below 2.25V.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data,
+ char *buf)
+{
+ int ret;
+ u8 config_reg;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6);
+}
+EXPORT_SYMBOL(ms_sensors_show_battery_low);
+
+/**
+ * ms_sensors_show_heater() - Show device heater
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer to write result
+ *
+ * This function will read heater enable value in the device and
+ * return 1 if the heater is enabled.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data,
+ char *buf)
+{
+ u8 config_reg;
+ int ret;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2);
+}
+EXPORT_SYMBOL(ms_sensors_show_heater);
+
+/**
+ * ms_sensors_write_heater() - Write device heater
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer from user space
+ * @len: length of buf
+ *
+ * This function will write 1 or 0 value in the device
+ * to enable or disable heater.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: length of buffer, negative errno otherwise.
+ */
+ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
+ const char *buf, size_t len)
+{
+ u8 val, config_reg;
+ int ret;
+
+ ret = kstrtou8(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val > 1)
+ return -EINVAL;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ if (ret) {
+ mutex_unlock(&dev_data->lock);
+ return ret;
+ }
+
+ config_reg &= 0xFB;
+ config_reg |= val << 2;
+
+ ret = i2c_smbus_write_byte_data(dev_data->client,
+ MS_SENSORS_CONFIG_REG_WRITE,
+ config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret) {
+ dev_err(&dev_data->client->dev, "Unable to write config register\n");
+ return ret;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL(ms_sensors_write_heater);
+
+/**
+ * ms_sensors_ht_read_temperature() - Read temperature
+ * @dev_data: pointer to temperature/humidity device data
+ * @temperature:pointer to temperature destination value
+ *
+ * This function will get temperature ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
+ s32 *temperature)
+{
+ int ret;
+ u32 adc;
+ u16 delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
+ ret = ms_sensors_convert_and_read(dev_data->client,
+ MS_SENSORS_HT_T_CONVERSION_START,
+ MS_SENSORS_NO_READ_CMD,
+ delay, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ if (!ms_sensors_crc_valid(adc)) {
+ dev_err(&dev_data->client->dev,
+ "Temperature read crc check error\n");
+ return -ENODEV;
+ }
+
+ /* Temperature algorithm */
+ *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_ht_read_temperature);
+
+/**
+ * ms_sensors_ht_read_humidity() - Read humidity
+ * @dev_data: pointer to temperature/humidity device data
+ * @humidity: pointer to humidity destination value
+ *
+ * This function will get humidity ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
+ u32 *humidity)
+{
+ int ret;
+ u32 adc;
+ u16 delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
+ ret = ms_sensors_convert_and_read(dev_data->client,
+ MS_SENSORS_HT_H_CONVERSION_START,
+ MS_SENSORS_NO_READ_CMD,
+ delay, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ if (!ms_sensors_crc_valid(adc)) {
+ dev_err(&dev_data->client->dev,
+ "Humidity read crc check error\n");
+ return -ENODEV;
+ }
+
+ /* Humidity algorithm */
+ *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
+ if (*humidity >= 100000)
+ *humidity = 100000;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_ht_read_humidity);
+
+/**
+ * ms_sensors_tp_crc_valid() - CRC check function for
+ * Temperature and pressure devices.
+ * This function is only used when reading PROM coefficients
+ *
+ * @prom: pointer to PROM coefficients array
+ * @len: length of PROM coefficients array
+ *
+ * Return: True if CRC is ok.
+ */
+static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
+{
+ unsigned int cnt, n_bit;
+ u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
+
+ prom[len - 1] = 0;
+ prom[0] &= 0x0FFF; /* Clear the CRC computation part */
+
+ for (cnt = 0; cnt < len * 2; cnt++) {
+ if (cnt % 2 == 1)
+ n_rem ^= prom[cnt >> 1] & 0x00FF;
+ else
+ n_rem ^= prom[cnt >> 1] >> 8;
+
+ for (n_bit = 8; n_bit > 0; n_bit--) {
+ if (n_rem & 0x8000)
+ n_rem = (n_rem << 1) ^ 0x3000;
+ else
+ n_rem <<= 1;
+ }
+ }
+ n_rem >>= 12;
+ prom[0] = crc_read;
+
+ return n_rem == crc;
+}
+
+/**
+ * ms_sensors_tp_read_prom() - prom coeff read function
+ * @dev_data: pointer to temperature/pressure device data
+ *
+ * This function will read prom coefficients and check CRC.
+ * This function is used for MS5637 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
+{
+ int i, ret;
+
+ for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
+ ret = ms_sensors_read_prom_word(
+ dev_data->client,
+ MS_SENSORS_TP_PROM_READ + (i << 1),
+ &dev_data->prom[i]);
+
+ if (ret)
+ return ret;
+ }
+
+ if (!ms_sensors_tp_crc_valid(dev_data->prom,
+ MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
+ dev_err(&dev_data->client->dev,
+ "Calibration coefficients crc check error\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_tp_read_prom);
+
+/**
+ * ms_sensors_read_temp_and_pressure() - read temp and pressure
+ * @dev_data: pointer to temperature/pressure device data
+ * @temperature:pointer to temperature destination value
+ * @pressure: pointer to pressure destination value
+ *
+ * This function will read ADC and compute pressure and temperature value.
+ * This function is used for MS5637 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+ int *temperature,
+ unsigned int *pressure)
+{
+ int ret;
+ u32 t_adc, p_adc;
+ s32 dt, temp;
+ s64 off, sens, t2, off2, sens2;
+ u16 *prom = dev_data->prom, delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_tp_conversion_time[dev_data->res_index];
+
+ ret = ms_sensors_convert_and_read(
+ dev_data->client,
+ MS_SENSORS_TP_T_CONVERSION_START +
+ dev_data->res_index * 2,
+ MS_SENSORS_TP_ADC_READ,
+ delay, &t_adc);
+ if (ret) {
+ mutex_unlock(&dev_data->lock);
+ return ret;
+ }
+
+ ret = ms_sensors_convert_and_read(
+ dev_data->client,
+ MS_SENSORS_TP_P_CONVERSION_START +
+ dev_data->res_index * 2,
+ MS_SENSORS_TP_ADC_READ,
+ delay, &p_adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ dt = (s32)t_adc - (prom[5] << 8);
+
+ /* Actual temperature = 2000 + dT * TEMPSENS */
+ temp = 2000 + (((s64)dt * prom[6]) >> 23);
+
+ /* Second order temperature compensation */
+ if (temp < 2000) {
+ s64 tmp = (s64)temp - 2000;
+
+ t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
+ off2 = (61 * tmp * tmp) >> 4;
+ sens2 = (29 * tmp * tmp) >> 4;
+
+ if (temp < -1500) {
+ s64 tmp = (s64)temp + 1500;
+
+ off2 += 17 * tmp * tmp;
+ sens2 += 9 * tmp * tmp;
+ }
+ } else {
+ t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
+ off2 = 0;
+ sens2 = 0;
+ }
+
+ /* OFF = OFF_T1 + TCO * dT */
+ off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
+ off -= off2;
+
+ /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
+ sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
+ sens -= sens2;
+
+ /* Temperature compensated pressure = D1 * SENS - OFF */
+ *temperature = (temp - t2) * 10;
+ *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
+
+MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
new file mode 100644
index 000000000000..7b614adc5cae
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
@@ -0,0 +1,66 @@
+/*
+ * Measurements Specialties common sensor driver
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MS_SENSORS_I2C_H
+#define _MS_SENSORS_I2C_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#define MS_SENSORS_TP_PROM_WORDS_NB 7
+
+/**
+ * struct ms_ht_dev - Humidity/Temperature sensor device structure
+ * @client: i2c client
+ * @lock: lock protecting the i2c conversion
+ * @res_index: index to selected sensor resolution
+ */
+struct ms_ht_dev {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 res_index;
+};
+
+/**
+ * struct ms_tp_dev - Temperature/Pressure sensor device structure
+ * @client: i2c client
+ * @lock: lock protecting the i2c conversion
+ * @prom: array of PROM coefficients used for conversion. Added element
+ * for CRC computation
+ * @res_index: index to selected sensor resolution
+ */
+struct ms_tp_dev {
+ struct i2c_client *client;
+ struct mutex lock;
+ u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
+ u8 res_index;
+};
+
+int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay);
+int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word);
+int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc);
+int ms_sensors_read_serial(struct i2c_client *client, u64 *sn);
+ssize_t ms_sensors_show_serial(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, u8 i);
+ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
+ const char *buf, size_t len);
+int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
+ s32 *temperature);
+int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
+ u32 *humidity);
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+ int *temperature,
+ unsigned int *pressure);
+
+#endif /* _MS_SENSORS_I2C_H */
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 2e7fdb502645..25258e2c1a82 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -44,6 +44,28 @@ st_sensors_write_data_with_mask_error:
return err;
}
+int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct st_sensor_data *sdata = iio_priv(indio_dev);
+ u8 readdata;
+ int err;
+
+ if (!readval)
+ return sdata->tf->write_byte(&sdata->tb, sdata->dev,
+ (u8)reg, (u8)writeval);
+
+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata);
+ if (err < 0)
+ return err;
+
+ *readval = (unsigned)readdata;
+
+ return 0;
+}
+EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
+
static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
unsigned int odr, struct st_sensor_odr_avl *odr_out)
{
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 581ec141de3d..e6e9756580af 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -214,7 +214,6 @@ static struct attribute *ad5504_ev_attributes[] = {
static struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes,
- .name = "events",
};
static irqreturn_t ad5504_event_handler(int irq, void *private)
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index fa2810032968..18a4ad5ff8c5 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -281,6 +281,12 @@ static int ad7303_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id ad7303_spi_of_match[] = {
+ { .compatible = "adi,ad7303", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ad7303_spi_of_match);
+
static const struct spi_device_id ad7303_spi_ids[] = {
{ "ad7303", 0 },
{}
@@ -290,6 +296,7 @@ MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
static struct spi_driver ad7303_driver = {
.driver = {
.name = "ad7303",
+ .of_match_table = of_match_ptr(ad7303_spi_of_match),
.owner = THIS_MODULE,
},
.probe = ad7303_probe,
diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c
index c23d7fa889ee..76e8b044b979 100644
--- a/drivers/iio/dac/m62332.c
+++ b/drivers/iio/dac/m62332.c
@@ -31,7 +31,6 @@
struct m62332_data {
struct i2c_client *client;
- u16 vref_mv;
struct regulator *vcc;
struct mutex mutex;
u8 raw[M62332_CHANNELS];
@@ -40,8 +39,7 @@ struct m62332_data {
#endif
};
-static int m62332_set_value(struct iio_dev *indio_dev,
- u8 val, int channel)
+static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
{
struct m62332_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
@@ -62,8 +60,8 @@ static int m62332_set_value(struct iio_dev *indio_dev,
goto out;
}
- res = i2c_master_send(client, outbuf, 2);
- if (res >= 0 && res != 2)
+ res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
+ if (res >= 0 && res != ARRAY_SIZE(outbuf))
res = -EIO;
if (res < 0)
goto out;
@@ -87,46 +85,52 @@ static int m62332_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
- long m)
+ long mask)
{
struct m62332_data *data = iio_priv(indio_dev);
+ int ret;
- switch (m) {
+ switch (mask) {
case IIO_CHAN_INFO_SCALE:
/* Corresponds to Vref / 2^(bits) */
- *val = data->vref_mv;
+ ret = regulator_get_voltage(data->vcc);
+ if (ret < 0)
+ return ret;
+
+ *val = ret / 1000; /* mV */
*val2 = 8;
+
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_RAW:
*val = data->raw[chan->channel];
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = 1;
+
return IIO_VAL_INT;
default:
break;
}
+
return -EINVAL;
}
static int m62332_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)
{
- int ret;
-
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val > 255)
return -EINVAL;
- ret = m62332_set_value(indio_dev, val, chan->channel);
- break;
+ return m62332_set_value(indio_dev, val, chan->channel);
default:
- ret = -EINVAL;
break;
}
- return ret;
+ return -EINVAL;
}
#ifdef CONFIG_PM_SLEEP
@@ -173,15 +177,15 @@ static const struct iio_info m62332_info = {
.driver_module = THIS_MODULE,
};
-#define M62332_CHANNEL(chan) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .output = 1, \
- .channel = (chan), \
- .datasheet_name = "CH" #chan, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_OFFSET), \
+#define M62332_CHANNEL(chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (chan), \
+ .datasheet_name = "CH" #chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
@@ -199,6 +203,7 @@ static int m62332_probe(struct i2c_client *client,
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;
@@ -212,16 +217,11 @@ static int m62332_probe(struct i2c_client *client,
/* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
- indio_dev->num_channels = M62332_CHANNELS;
+ indio_dev->num_channels = ARRAY_SIZE(m62332_channels);
indio_dev->channels = m62332_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &m62332_info;
- ret = regulator_get_voltage(data->vcc);
- if (ret < 0)
- return ret;
- data->vref_mv = ret / 1000; /* mV */
-
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
return ret;
@@ -234,6 +234,7 @@ static int m62332_probe(struct i2c_client *client,
err:
iio_map_array_unregister(indio_dev);
+
return ret;
}
@@ -243,6 +244,8 @@ static int m62332_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
+ m62332_set_value(indio_dev, 0, 0);
+ m62332_set_value(indio_dev, 0, 1);
return 0;
}
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index 28b8748ea824..86e9e112f554 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -387,6 +387,7 @@ static const struct of_device_id max5821_of_match[] = {
{ .compatible = "maxim,max5821" },
{ }
};
+MODULE_DEVICE_TABLE(of, max5821_of_match);
static struct i2c_driver max5821_driver = {
.driver = {
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 9890c81c027d..73f27e0a08dd 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -616,15 +616,24 @@ static int adf4350_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id adf4350_of_match[] = {
+ { .compatible = "adi,adf4350", },
+ { .compatible = "adi,adf4351", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, adf4350_of_match);
+
static const struct spi_device_id adf4350_id[] = {
{"adf4350", 4350},
{"adf4351", 4351},
{}
};
+MODULE_DEVICE_TABLE(spi, adf4350_id);
static struct spi_driver adf4350_driver = {
.driver = {
.name = "adf4350",
+ .of_match_table = of_match_ptr(adf4350_of_match),
.owner = THIS_MODULE,
},
.probe = adf4350_probe,
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 8d2439345673..e816d29d6a62 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -52,15 +52,26 @@ config ADXRS450
config BMG160
tristate "BOSCH BMG160 Gyro Sensor"
- depends on I2C
+ depends on (I2C || SPI_MASTER)
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+ select BMG160_I2C if (I2C)
+ select BMG160_SPI if (SPI)
help
- Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
- driver. This driver also supports BMI055 gyroscope.
+ Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor
+ driver connected via I2C or SPI. This driver also supports BMI055
+ gyroscope.
This driver can also be built as a module. If so, the module
- will be called bmg160.
+ will be called bmg160_i2c or bmg160_spi.
+
+config BMG160_I2C
+ tristate
+ select REGMAP_I2C
+
+config BMG160_SPI
+ tristate
+ select REGMAP_SPI
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index f46341b39139..f866a4be0667 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -8,7 +8,9 @@ obj-$(CONFIG_ADIS16130) += adis16130.o
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_ADIS16260) += adis16260.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
-obj-$(CONFIG_BMG160) += bmg160.o
+obj-$(CONFIG_BMG160) += bmg160_core.o
+obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
+obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/bmg160.h b/drivers/iio/gyro/bmg160.h
new file mode 100644
index 000000000000..72db723c8fb6
--- /dev/null
+++ b/drivers/iio/gyro/bmg160.h
@@ -0,0 +1,10 @@
+#ifndef BMG160_H_
+#define BMG160_H_
+
+extern const struct dev_pm_ops bmg160_pm_ops;
+
+int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name);
+void bmg160_core_remove(struct device *dev);
+
+#endif /* BMG160_H_ */
diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160_core.c
index 460bf715d541..02ff789852a0 100644
--- a/drivers/iio/gyro/bmg160.c
+++ b/drivers/iio/gyro/bmg160_core.c
@@ -13,7 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -28,8 +27,9 @@
#include <linux/iio/events.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include <linux/regmap.h>
+#include "bmg160.h"
-#define BMG160_DRV_NAME "bmg160"
#define BMG160_IRQ_NAME "bmg160_event"
#define BMG160_GPIO_NAME "gpio_int"
@@ -97,7 +97,8 @@
#define BMG160_AUTO_SUSPEND_DELAY_MS 2000
struct bmg160_data {
- struct i2c_client *client;
+ struct device *dev;
+ struct regmap *regmap;
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
struct mutex mutex;
@@ -108,6 +109,7 @@ struct bmg160_data {
int slope_thres;
bool dready_trigger_on;
bool motion_trigger_on;
+ int irq;
};
enum bmg160_axis {
@@ -138,10 +140,9 @@ static int bmg160_set_mode(struct bmg160_data *data, u8 mode)
{
int ret;
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_PMU_LPW, mode);
+ ret = regmap_write(data->regmap, BMG160_REG_PMU_LPW, mode);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n");
+ dev_err(data->dev, "Error writing reg_pmu_lpw\n");
return ret;
}
@@ -169,10 +170,9 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
if (bw_bits < 0)
return bw_bits;
- ret = i2c_smbus_write_byte_data(data->client, BMG160_REG_PMU_BW,
- bw_bits);
+ ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bw_bits);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_bw\n");
+ dev_err(data->dev, "Error writing reg_pmu_bw\n");
return ret;
}
@@ -184,16 +184,17 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
static int bmg160_chip_init(struct bmg160_data *data)
{
int ret;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_CHIP_ID);
+ ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_chip_id\n");
+ dev_err(data->dev, "Error reading reg_chip_id\n");
return ret;
}
- dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
- if (ret != BMG160_CHIP_ID_VAL) {
- dev_err(&data->client->dev, "invalid chip %x\n", ret);
+ dev_dbg(data->dev, "Chip Id %x\n", val);
+ if (val != BMG160_CHIP_ID_VAL) {
+ dev_err(data->dev, "invalid chip %x\n", val);
return -ENODEV;
}
@@ -210,42 +211,33 @@ static int bmg160_chip_init(struct bmg160_data *data)
return ret;
/* Set Default Range */
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_RANGE,
- BMG160_RANGE_500DPS);
+ ret = regmap_write(data->regmap, BMG160_REG_RANGE, BMG160_RANGE_500DPS);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_range\n");
+ dev_err(data->dev, "Error writing reg_range\n");
return ret;
}
data->dps_range = BMG160_RANGE_500DPS;
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_SLOPE_THRES);
+ ret = regmap_read(data->regmap, BMG160_REG_SLOPE_THRES, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_slope_thres\n");
+ dev_err(data->dev, "Error reading reg_slope_thres\n");
return ret;
}
- data->slope_thres = ret;
+ data->slope_thres = val;
/* Set default interrupt mode */
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1);
+ ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
+ BMG160_INT1_BIT_OD, 0);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_en_1\n");
- return ret;
- }
- ret &= ~BMG160_INT1_BIT_OD;
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_EN_1, ret);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
+ dev_err(data->dev, "Error updating bits in reg_int_en_1\n");
return ret;
}
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_motion_intr\n");
return ret;
}
@@ -259,17 +251,17 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on)
int ret;
if (on)
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_get_sync(data->dev);
else {
- pm_runtime_mark_last_busy(&data->client->dev);
- ret = pm_runtime_put_autosuspend(&data->client->dev);
+ pm_runtime_mark_last_busy(data->dev);
+ ret = pm_runtime_put_autosuspend(data->dev);
}
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Failed: bmg160_set_power_state for %d\n", on);
if (on)
- pm_runtime_put_noidle(&data->client->dev);
+ pm_runtime_put_noidle(data->dev);
return ret;
}
@@ -284,43 +276,30 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
int ret;
/* Enable/Disable INT_MAP0 mapping */
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_0);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_map0\n");
- return ret;
- }
- if (status)
- ret |= BMG160_INT_MAP_0_BIT_ANY;
- else
- ret &= ~BMG160_INT_MAP_0_BIT_ANY;
-
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_MAP_0,
- ret);
+ ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_0,
+ BMG160_INT_MAP_0_BIT_ANY,
+ (status ? BMG160_INT_MAP_0_BIT_ANY : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_map0\n");
+ dev_err(data->dev, "Error updating bits reg_int_map0\n");
return ret;
}
/* Enable/Disable slope interrupts */
if (status) {
/* Update slope thres */
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_SLOPE_THRES,
- data->slope_thres);
+ ret = regmap_write(data->regmap, BMG160_REG_SLOPE_THRES,
+ data->slope_thres);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_slope_thres\n");
return ret;
}
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_MOTION_INTR,
- BMG160_INT_MOTION_X |
- BMG160_INT_MOTION_Y |
- BMG160_INT_MOTION_Z);
+ ret = regmap_write(data->regmap, BMG160_REG_MOTION_INTR,
+ BMG160_INT_MOTION_X | BMG160_INT_MOTION_Y |
+ BMG160_INT_MOTION_Z);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_motion_intr\n");
return ret;
}
@@ -331,28 +310,26 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
* to set latched mode, we will be flooded anyway with INTR
*/
if (!data->dready_trigger_on) {
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap,
+ BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_rst_latch\n");
return ret;
}
}
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_EN_0,
- BMG160_DATA_ENABLE_INT);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
+ BMG160_DATA_ENABLE_INT);
- } else
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_EN_0,
- 0);
+ } else {
+ ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
+ }
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_en0\n");
+ dev_err(data->dev, "Error writing reg_int_en0\n");
return ret;
}
@@ -365,59 +342,43 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
int ret;
/* Enable/Disable INT_MAP1 mapping */
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_1);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_map1\n");
- return ret;
- }
-
- if (status)
- ret |= BMG160_INT_MAP_1_BIT_NEW_DATA;
- else
- ret &= ~BMG160_INT_MAP_1_BIT_NEW_DATA;
-
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_MAP_1,
- ret);
+ ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_1,
+ BMG160_INT_MAP_1_BIT_NEW_DATA,
+ (status ? BMG160_INT_MAP_1_BIT_NEW_DATA : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_map1\n");
+ dev_err(data->dev, "Error updating bits in reg_int_map1\n");
return ret;
}
if (status) {
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_NON_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_NON_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_rst_latch\n");
return ret;
}
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_EN_0,
- BMG160_DATA_ENABLE_INT);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
+ BMG160_DATA_ENABLE_INT);
} else {
/* Restore interrupt mode */
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_rst_latch\n");
return ret;
}
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_EN_0,
- 0);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
}
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_en0\n");
+ dev_err(data->dev, "Error writing reg_int_en0\n");
return ret;
}
@@ -444,12 +405,10 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
if (bmg160_scale_table[i].scale == val) {
- ret = i2c_smbus_write_byte_data(
- data->client,
- BMG160_REG_RANGE,
- bmg160_scale_table[i].dps_range);
+ ret = regmap_write(data->regmap, BMG160_REG_RANGE,
+ bmg160_scale_table[i].dps_range);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_range\n");
return ret;
}
@@ -464,6 +423,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
static int bmg160_get_temp(struct bmg160_data *data, int *val)
{
int ret;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
ret = bmg160_set_power_state(data, true);
@@ -472,15 +432,15 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
return ret;
}
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_TEMP);
+ ret = regmap_read(data->regmap, BMG160_REG_TEMP, &raw_val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_temp\n");
+ dev_err(data->dev, "Error reading reg_temp\n");
bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret, 7);
+ *val = sign_extend32(raw_val, 7);
ret = bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
if (ret < 0)
@@ -492,6 +452,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
{
int ret;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
ret = bmg160_set_power_state(data, true);
@@ -500,15 +461,16 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
return ret;
}
- ret = i2c_smbus_read_word_data(data->client, BMG160_AXIS_TO_REG(axis));
+ ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
+ 2);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading axis %d\n", axis);
+ dev_err(data->dev, "Error reading axis %d\n", axis);
bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret, 15);
+ *val = sign_extend32(raw_val, 15);
ret = bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
if (ret < 0)
@@ -807,12 +769,13 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct bmg160_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
+ unsigned int val;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
- ret = i2c_smbus_read_word_data(data->client,
- BMG160_AXIS_TO_REG(bit));
+ ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit),
+ &val, 2);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err;
@@ -840,12 +803,11 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
return 0;
/* Set latched mode interrupt and clear any latched interrupt */
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_rst_latch\n");
+ dev_err(data->dev, "Error writing reg_rst_latch\n");
return ret;
}
@@ -907,33 +869,34 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
struct bmg160_data *data = iio_priv(indio_dev);
int ret;
int dir;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_STATUS_2);
+ ret = regmap_read(data->regmap, BMG160_REG_INT_STATUS_2, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_status2\n");
+ dev_err(data->dev, "Error reading reg_int_status2\n");
goto ack_intr_status;
}
- if (ret & 0x08)
+ if (val & 0x08)
dir = IIO_EV_DIR_RISING;
else
dir = IIO_EV_DIR_FALLING;
- if (ret & BMG160_ANY_MOTION_BIT_X)
+ if (val & BMG160_ANY_MOTION_BIT_X)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
IIO_MOD_X,
IIO_EV_TYPE_ROC,
dir),
iio_get_time_ns());
- if (ret & BMG160_ANY_MOTION_BIT_Y)
+ if (val & BMG160_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_ROC,
dir),
iio_get_time_ns());
- if (ret & BMG160_ANY_MOTION_BIT_Z)
+ if (val & BMG160_ANY_MOTION_BIT_Z)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
IIO_MOD_Z,
@@ -943,12 +906,11 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
ack_intr_status:
if (!data->dready_trigger_on) {
- ret = i2c_smbus_write_byte_data(data->client,
- BMG160_REG_INT_RST_LATCH,
- BMG160_INT_MODE_LATCH_INT |
- BMG160_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+ BMG160_INT_MODE_LATCH_INT |
+ BMG160_INT_MODE_LATCH_RESET);
if (ret < 0)
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_rst_latch\n");
}
@@ -993,18 +955,13 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
.postdisable = bmg160_buffer_postdisable,
};
-static int bmg160_gpio_probe(struct i2c_client *client,
- struct bmg160_data *data)
+static int bmg160_gpio_probe(struct bmg160_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
- dev = &client->dev;
+ dev = data->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
@@ -1013,11 +970,12 @@ static int bmg160_gpio_probe(struct i2c_client *client,
return PTR_ERR(gpio);
}
- ret = gpiod_to_irq(gpio);
+ data->irq = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+ dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
+ data->irq);
- return ret;
+ return 0;
}
static const char *bmg160_match_acpi_device(struct device *dev)
@@ -1031,21 +989,22 @@ static const char *bmg160_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static int bmg160_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name)
{
struct bmg160_data *data;
struct iio_dev *indio_dev;
int ret;
- const char *name = NULL;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
- data->client = client;
+ dev_set_drvdata(dev, indio_dev);
+ data->dev = dev;
+ data->irq = irq;
+ data->regmap = regmap;
ret = bmg160_chip_init(data);
if (ret < 0)
@@ -1053,25 +1012,22 @@ static int bmg160_probe(struct i2c_client *client,
mutex_init(&data->mutex);
- if (id)
- name = id->name;
+ if (ACPI_HANDLE(dev))
+ name = bmg160_match_acpi_device(dev);
- if (ACPI_HANDLE(&client->dev))
- name = bmg160_match_acpi_device(&client->dev);
-
- indio_dev->dev.parent = &client->dev;
+ indio_dev->dev.parent = dev;
indio_dev->channels = bmg160_channels;
indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmg160_info;
- if (client->irq <= 0)
- client->irq = bmg160_gpio_probe(client, data);
+ if (data->irq <= 0)
+ bmg160_gpio_probe(data);
- if (client->irq > 0) {
- ret = devm_request_threaded_irq(&client->dev,
- client->irq,
+ if (data->irq > 0) {
+ ret = devm_request_threaded_irq(dev,
+ data->irq,
bmg160_data_rdy_trig_poll,
bmg160_event_handler,
IRQF_TRIGGER_RISING,
@@ -1080,28 +1036,28 @@ static int bmg160_probe(struct i2c_client *client,
if (ret)
return ret;
- data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+ data->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
indio_dev->id);
if (!data->dready_trig)
return -ENOMEM;
- data->motion_trig = devm_iio_trigger_alloc(&client->dev,
+ data->motion_trig = devm_iio_trigger_alloc(dev,
"%s-any-motion-dev%d",
indio_dev->name,
indio_dev->id);
if (!data->motion_trig)
return -ENOMEM;
- data->dready_trig->dev.parent = &client->dev;
+ data->dready_trig->dev.parent = dev;
data->dready_trig->ops = &bmg160_trigger_ops;
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
ret = iio_trigger_register(data->dready_trig);
if (ret)
return ret;
- data->motion_trig->dev.parent = &client->dev;
+ data->motion_trig->dev.parent = dev;
data->motion_trig->ops = &bmg160_trigger_ops;
iio_trigger_set_drvdata(data->motion_trig, indio_dev);
ret = iio_trigger_register(data->motion_trig);
@@ -1116,25 +1072,25 @@ static int bmg160_probe(struct i2c_client *client,
bmg160_trigger_handler,
&bmg160_buffer_setup_ops);
if (ret < 0) {
- dev_err(&client->dev,
+ dev_err(dev,
"iio triggered buffer setup failed\n");
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
- dev_err(&client->dev, "unable to register iio device\n");
+ dev_err(dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
- ret = pm_runtime_set_active(&client->dev);
+ ret = pm_runtime_set_active(dev);
if (ret)
goto err_iio_unregister;
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev,
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev,
BMG160_AUTO_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_use_autosuspend(dev);
return 0;
@@ -1150,15 +1106,16 @@ err_trigger_unregister:
return ret;
}
+EXPORT_SYMBOL_GPL(bmg160_core_probe);
-static int bmg160_remove(struct i2c_client *client)
+void bmg160_core_remove(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
@@ -1171,14 +1128,13 @@ static int bmg160_remove(struct i2c_client *client)
mutex_lock(&data->mutex);
bmg160_set_mode(data, BMG160_MODE_DEEP_SUSPEND);
mutex_unlock(&data->mutex);
-
- return 0;
}
+EXPORT_SYMBOL_GPL(bmg160_core_remove);
#ifdef CONFIG_PM_SLEEP
static int bmg160_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1190,7 +1146,7 @@ static int bmg160_suspend(struct device *dev)
static int bmg160_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1206,13 +1162,13 @@ static int bmg160_resume(struct device *dev)
#ifdef CONFIG_PM
static int bmg160_runtime_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
int ret;
ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
if (ret < 0) {
- dev_err(&data->client->dev, "set mode failed\n");
+ dev_err(data->dev, "set mode failed\n");
return -EAGAIN;
}
@@ -1221,7 +1177,7 @@ static int bmg160_runtime_suspend(struct device *dev)
static int bmg160_runtime_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmg160_data *data = iio_priv(indio_dev);
int ret;
@@ -1235,39 +1191,12 @@ static int bmg160_runtime_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bmg160_pm_ops = {
+const struct dev_pm_ops bmg160_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bmg160_suspend, bmg160_resume)
SET_RUNTIME_PM_OPS(bmg160_runtime_suspend,
bmg160_runtime_resume, NULL)
};
-
-static const struct acpi_device_id bmg160_acpi_match[] = {
- {"BMG0160", 0},
- {"BMI055B", 0},
- {},
-};
-
-MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
-
-static const struct i2c_device_id bmg160_id[] = {
- {"bmg160", 0},
- {"bmi055_gyro", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, bmg160_id);
-
-static struct i2c_driver bmg160_driver = {
- .driver = {
- .name = BMG160_DRV_NAME,
- .acpi_match_table = ACPI_PTR(bmg160_acpi_match),
- .pm = &bmg160_pm_ops,
- },
- .probe = bmg160_probe,
- .remove = bmg160_remove,
- .id_table = bmg160_id,
-};
-module_i2c_driver(bmg160_driver);
+EXPORT_SYMBOL_GPL(bmg160_pm_ops);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
new file mode 100644
index 000000000000..90126a5a7663
--- /dev/null
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -0,0 +1,71 @@
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+
+#include "bmg160.h"
+
+static const struct regmap_config bmg160_regmap_i2c_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f
+};
+
+static int bmg160_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ const char *name = NULL;
+
+ regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+ (int)PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ if (id)
+ name = id->name;
+
+ return bmg160_core_probe(&client->dev, regmap, client->irq, name);
+}
+
+static int bmg160_i2c_remove(struct i2c_client *client)
+{
+ bmg160_core_remove(&client->dev);
+
+ return 0;
+}
+
+static const struct acpi_device_id bmg160_acpi_match[] = {
+ {"BMG0160", 0},
+ {"BMI055B", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
+
+static const struct i2c_device_id bmg160_i2c_id[] = {
+ {"bmg160", 0},
+ {"bmi055_gyro", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
+
+static struct i2c_driver bmg160_i2c_driver = {
+ .driver = {
+ .name = "bmg160_i2c",
+ .acpi_match_table = ACPI_PTR(bmg160_acpi_match),
+ .pm = &bmg160_pm_ops,
+ },
+ .probe = bmg160_i2c_probe,
+ .remove = bmg160_i2c_remove,
+ .id_table = bmg160_i2c_id,
+};
+module_i2c_driver(bmg160_i2c_driver);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMG160 I2C Gyro driver");
diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c
new file mode 100644
index 000000000000..021ea5fe6a37
--- /dev/null
+++ b/drivers/iio/gyro/bmg160_spi.c
@@ -0,0 +1,57 @@
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+
+#include "bmg160.h"
+
+static const struct regmap_config bmg160_regmap_spi_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f,
+};
+
+static int bmg160_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ regmap = devm_regmap_init_spi(spi, &bmg160_regmap_spi_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to register spi regmap %d\n",
+ (int)PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return bmg160_core_probe(&spi->dev, regmap, spi->irq, id->name);
+}
+
+static int bmg160_spi_remove(struct spi_device *spi)
+{
+ bmg160_core_remove(&spi->dev);
+
+ return 0;
+}
+
+static const struct spi_device_id bmg160_spi_id[] = {
+ {"bmg160", 0},
+ {"bmi055_gyro", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(spi, bmg160_spi_id);
+
+static struct spi_driver bmg160_spi_driver = {
+ .driver = {
+ .name = "bmg160_spi",
+ .pm = &bmg160_pm_ops,
+ },
+ .probe = bmg160_spi_probe,
+ .remove = bmg160_spi_remove,
+ .id_table = bmg160_spi_id,
+};
+module_spi_driver(bmg160_spi_driver);
+
+MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMG160 SPI Gyro driver");
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index 4b993a5bc9a1..02eddcebeea3 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -383,6 +383,7 @@ static const struct iio_info gyro_info = {
.attrs = &st_gyro_attribute_group,
.read_raw = &st_gyro_read_raw,
.write_raw = &st_gyro_write_raw,
+ .debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 688c0d1cb47d..6a23698d347c 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -12,6 +12,29 @@ config DHT11
Other sensors should work as well as long as they speak the
same protocol.
+config HDC100X
+ tristate "TI HDC100x relative humidity and temperature sensor"
+ depends on I2C
+ help
+ Say yes here to build support for the TI HDC100x series of
+ relative humidity and temperature sensors.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hdc100x.
+
+config HTU21
+ tristate "Measurement Specialties HTU21 humidity & temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ HTU21 humidity and temperature sensor.
+ This driver is also used for MS8607 temperature, pressure & humidity
+ sensor
+
+ This driver can also be built as a module. If so, the module will
+ be called htu21.
+
config SI7005
tristate "SI7005 relative humidity and temperature sensor"
depends on I2C
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index 86e2d26e9f4d..c9f089a9a6b8 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -3,5 +3,7 @@
#
obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_HDC100X) += hdc100x.o
+obj-$(CONFIG_HTU21) += htu21.o
obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
new file mode 100644
index 000000000000..a7f61e881a49
--- /dev/null
+++ b/drivers/iio/humidity/hdc100x.c
@@ -0,0 +1,320 @@
+/*
+ * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define HDC100X_REG_TEMP 0x00
+#define HDC100X_REG_HUMIDITY 0x01
+
+#define HDC100X_REG_CONFIG 0x02
+#define HDC100X_REG_CONFIG_HEATER_EN BIT(13)
+
+struct hdc100x_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ u16 config;
+
+ /* integration time of the sensor */
+ int adc_int_us[2];
+};
+
+/* integration time in us */
+static const int hdc100x_int_time[][3] = {
+ { 6350, 3650, 0 }, /* IIO_TEMP channel*/
+ { 6500, 3850, 2500 }, /* IIO_HUMIDITYRELATIVE channel */
+};
+
+/* HDC100X_REG_CONFIG shift and mask values */
+static const struct {
+ int shift;
+ int mask;
+} hdc100x_resolution_shift[2] = {
+ { /* IIO_TEMP channel */
+ .shift = 10,
+ .mask = 1
+ },
+ { /* IIO_HUMIDITYRELATIVE channel */
+ .shift = 8,
+ .mask = 2,
+ },
+};
+
+static IIO_CONST_ATTR(temp_integration_time_available,
+ "0.00365 0.00635");
+
+static IIO_CONST_ATTR(humidityrelative_integration_time_available,
+ "0.0025 0.00385 0.0065");
+
+static IIO_CONST_ATTR(out_current_heater_raw_available,
+ "0 1");
+
+static struct attribute *hdc100x_attributes[] = {
+ &iio_const_attr_temp_integration_time_available.dev_attr.attr,
+ &iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr,
+ &iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group hdc100x_attribute_group = {
+ .attrs = hdc100x_attributes,
+};
+
+static const struct iio_chan_spec hdc100x_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .address = HDC100X_REG_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .address = HDC100X_REG_HUMIDITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME)
+ },
+ {
+ .type = IIO_CURRENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .extend_name = "heater",
+ .output = 1,
+ },
+};
+
+static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val)
+{
+ int tmp = (~mask & data->config) | val;
+ int ret;
+
+ ret = i2c_smbus_write_word_swapped(data->client,
+ HDC100X_REG_CONFIG, tmp);
+ if (!ret)
+ data->config = tmp;
+
+ return ret;
+}
+
+static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2)
+{
+ int shift = hdc100x_resolution_shift[chan].shift;
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) {
+ if (val2 && val2 == hdc100x_int_time[chan][i]) {
+ ret = hdc100x_update_config(data,
+ hdc100x_resolution_shift[chan].mask << shift,
+ i << shift);
+ if (!ret)
+ data->adc_int_us[chan] = val2;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int hdc100x_get_measurement(struct hdc100x_data *data,
+ struct iio_chan_spec const *chan)
+{
+ struct i2c_client *client = data->client;
+ int delay = data->adc_int_us[chan->address];
+ int ret;
+ int val;
+
+ /* start measurement */
+ ret = i2c_smbus_write_byte(client, chan->address);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot start measurement");
+ return ret;
+ }
+
+ /* wait for integration time to pass */
+ usleep_range(delay, delay + 1000);
+
+ /*
+ * i2c_smbus_read_word_data cannot() be used here due to the command
+ * value not being understood and causes NAKs preventing any reading
+ * from being accessed.
+ */
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read high byte measurement");
+ return ret;
+ }
+ val = ret << 6;
+
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read low byte measurement");
+ return ret;
+ }
+ val |= ret >> 2;
+
+ return val;
+}
+
+static int hdc100x_get_heater_status(struct hdc100x_data *data)
+{
+ return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN);
+}
+
+static int hdc100x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct hdc100x_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ int ret;
+
+ mutex_lock(&data->lock);
+ if (chan->type == IIO_CURRENT) {
+ *val = hdc100x_get_heater_status(data);
+ ret = IIO_VAL_INT;
+ } else {
+ ret = hdc100x_get_measurement(data, chan);
+ if (ret >= 0) {
+ *val = ret;
+ ret = IIO_VAL_INT;
+ }
+ }
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = 0;
+ *val2 = data->adc_int_us[chan->address];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_TEMP) {
+ *val = 165;
+ *val2 = 65536 >> 2;
+ return IIO_VAL_FRACTIONAL;
+ } else {
+ *val = 0;
+ *val2 = 10000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -3971;
+ *val2 = 879096;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hdc100x_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct hdc100x_data *data = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ if (val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ ret = hdc100x_set_it_time(data, chan->address, val2);
+ mutex_unlock(&data->lock);
+ return ret;
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_CURRENT || val2 != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
+ val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
+ mutex_unlock(&data->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info hdc100x_info = {
+ .read_raw = hdc100x_read_raw,
+ .write_raw = hdc100x_write_raw,
+ .attrs = &hdc100x_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int hdc100x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct hdc100x_data *data;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
+ return -ENODEV;
+
+ 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;
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = dev_name(&client->dev);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &hdc100x_info;
+
+ indio_dev->channels = hdc100x_channels;
+ indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels);
+
+ /* be sure we are in a known state */
+ hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]);
+ hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id hdc100x_id[] = {
+ { "hdc100x", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, hdc100x_id);
+
+static struct i2c_driver hdc100x_driver = {
+ .driver = {
+ .name = "hdc100x",
+ },
+ .probe = hdc100x_probe,
+ .id_table = hdc100x_id,
+};
+module_i2c_driver(hdc100x_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
new file mode 100644
index 000000000000..d1636a74980e
--- /dev/null
+++ b/drivers/iio/humidity/htu21.c
@@ -0,0 +1,253 @@
+/*
+ * htu21.c - Support for Measurement-Specialties
+ * htu21 temperature & humidity sensor
+ * and humidity part of MS8607 sensor
+ *
+ * Copyright (c) 2014 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/HTU21D.pdf
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define HTU21_RESET 0xFE
+
+enum {
+ HTU21,
+ MS8607
+};
+
+static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
+/* String copy of the above const for readability purpose */
+static const char htu21_show_samp_freq[] = "20 40 70 120";
+
+static int htu21_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret, temperature;
+ unsigned int humidity;
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = ms_sensors_ht_read_temperature(dev_data,
+ &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ case IIO_HUMIDITYRELATIVE: /* in milli %RH */
+ ret = ms_sensors_ht_read_humidity(dev_data,
+ &humidity);
+ if (ret)
+ return ret;
+ *val = humidity;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = htu21_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int htu21_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+ int i, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(htu21_samp_freq);
+ while (i-- > 0)
+ if (val == htu21_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ mutex_lock(&dev_data->lock);
+ dev_data->res_index = i;
+ ret = ms_sensors_write_resolution(dev_data, i);
+ mutex_unlock(&dev_data->lock);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec htu21_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+/*
+ * Meas Spec recommendation is to not read temperature
+ * on this driver part for MS8607
+ */
+static const struct iio_chan_spec ms8607_channels[] = {
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static ssize_t htu21_show_battery_low(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_battery_low(dev_data, buf);
+}
+
+static ssize_t htu21_show_heater(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_heater(dev_data, buf);
+}
+
+static ssize_t htu21_write_heater(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_write_heater(dev_data, buf, len);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+ htu21_show_battery_low, NULL, 0);
+static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
+ htu21_show_heater, htu21_write_heater, 0);
+
+static struct attribute *htu21_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_battery_low.dev_attr.attr,
+ &iio_dev_attr_heater_enable.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group htu21_attribute_group = {
+ .attrs = htu21_attributes,
+};
+
+static const struct iio_info htu21_info = {
+ .read_raw = htu21_read_raw,
+ .write_raw = htu21_write_raw,
+ .attrs = &htu21_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int htu21_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_ht_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+ u64 serial_number;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 0;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &htu21_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (id->driver_data == MS8607) {
+ indio_dev->channels = ms8607_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
+ } else {
+ indio_dev->channels = htu21_channels;
+ indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+ }
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, HTU21_RESET, 15000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_read_serial(client, &serial_number);
+ if (ret)
+ return ret;
+ dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id htu21_id[] = {
+ {"htu21", HTU21},
+ {"ms8607-humidity", MS8607},
+ {}
+};
+
+static struct i2c_driver htu21_driver = {
+ .probe = htu21_probe,
+ .id_table = htu21_id,
+ .driver = {
+ .name = "htu21",
+ },
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index fa3b809aff5e..12128d1ca570 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -57,8 +57,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*val = ret >> 2;
+ /*
+ * Humidity values can slightly exceed the 0-100%RH
+ * range and should be corrected by software
+ */
if (chan->type == IIO_HUMIDITYRELATIVE)
- *val &= GENMASK(11, 0);
+ *val = clamp_val(*val, 786, 13893);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP)
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 82cdf5090fa7..dbf5e9936635 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -27,7 +27,6 @@
#include <linux/iio/trigger_consumer.h>
#define KMX61_DRV_NAME "kmx61"
-#define KMX61_GPIO_NAME "kmx61_int"
#define KMX61_IRQ_NAME "kmx61_event"
#define KMX61_REG_WHO_AM_I 0x00
@@ -1243,30 +1242,6 @@ static const char *kmx61_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
- return ret;
-}
-
static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
const struct iio_info *info,
const struct iio_chan_spec *chan,
@@ -1360,9 +1335,6 @@ static int kmx61_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0)
- client->irq = kmx61_gpio_probe(client, data);
-
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kmx61_data_rdy_trig_poll,
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index b3fcc2c449d8..208358f9e7e3 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -75,6 +75,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_ENERGY] = "energy",
[IIO_DISTANCE] = "distance",
[IIO_VELOCITY] = "velocity",
+ [IIO_CONCENTRATION] = "concentration",
+ [IIO_RESISTANCE] = "resistance",
};
static const char * const iio_modifier_names[] = {
@@ -111,6 +113,8 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
[IIO_MOD_I] = "i",
[IIO_MOD_Q] = "q",
+ [IIO_MOD_CO2] = "co2",
+ [IIO_MOD_VOC] = "voc",
};
/* relies on pairs of these shared then separate */
@@ -962,7 +966,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
static void iio_dev_release(struct device *device)
{
struct iio_dev *indio_dev = dev_to_iio_dev(device);
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
iio_device_unregister_trigger_consumer(indio_dev);
iio_device_unregister_eventset(indio_dev);
iio_device_unregister_sysfs(indio_dev);
@@ -1153,6 +1157,8 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (cmd == IIO_GET_EVENT_FD_IOCTL) {
fd = iio_event_getfd(indio_dev);
+ if (fd < 0)
+ return fd;
if (copy_to_user(ip, &fd, sizeof(fd)))
return -EFAULT;
return 0;
@@ -1241,7 +1247,7 @@ int iio_device_register(struct iio_dev *indio_dev)
"Failed to register event set\n");
goto error_free_sysfs;
}
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
iio_device_register_trigger_consumer(indio_dev);
if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 570606c2adbd..ae2806aafb72 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -366,10 +366,18 @@ static ssize_t iio_trigger_write_current(struct device *dev,
indio_dev->trig = trig;
- if (oldtrig)
+ if (oldtrig) {
+ if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
+ iio_trigger_detach_poll_func(oldtrig,
+ indio_dev->pollfunc_event);
iio_trigger_put(oldtrig);
- if (indio_dev->trig)
+ }
+ if (indio_dev->trig) {
iio_trigger_get(indio_dev->trig);
+ if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
+ iio_trigger_attach_poll_func(indio_dev->trig,
+ indio_dev->pollfunc_event);
+ }
return len;
}
diff --git a/drivers/iio/industrialio-triggered-event.c b/drivers/iio/industrialio-triggered-event.c
new file mode 100644
index 000000000000..8cc254fac16a
--- /dev/null
+++ b/drivers/iio/industrialio-triggered-event.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/iio/trigger_consumer.h>
+
+/**
+ * iio_triggered_event_setup() - Setup pollfunc_event for triggered event
+ * @indio_dev: IIO device structure
+ * @h: Function which will be used as pollfunc_event top half
+ * @thread: Function which will be used as pollfunc_event bottom half
+ *
+ * This function combines some common tasks which will normally be performed
+ * when setting up a triggered event. It will allocate the pollfunc_event and
+ * set mode to use it for triggered event.
+ *
+ * Before calling this function the indio_dev structure should already be
+ * completely initialized, but not yet registered. In practice this means that
+ * this function should be called right before iio_device_register().
+ *
+ * To free the resources allocated by this function call
+ * iio_triggered_event_cleanup().
+ */
+int iio_triggered_event_setup(struct iio_dev *indio_dev,
+ irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p))
+{
+ indio_dev->pollfunc_event = iio_alloc_pollfunc(h,
+ thread,
+ IRQF_ONESHOT,
+ indio_dev,
+ "%s_consumer%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (indio_dev->pollfunc_event == NULL)
+ return -ENOMEM;
+
+ /* Flag that events polling is possible */
+ indio_dev->modes |= INDIO_EVENT_TRIGGERED;
+
+ return 0;
+}
+EXPORT_SYMBOL(iio_triggered_event_setup);
+
+/**
+ * iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup()
+ * @indio_dev: IIO device structure
+ */
+void iio_triggered_event_cleanup(struct iio_dev *indio_dev)
+{
+ indio_dev->modes &= ~INDIO_EVENT_TRIGGERED;
+ iio_dealloc_pollfunc(indio_dev->pollfunc_event);
+}
+EXPORT_SYMBOL(iio_triggered_event_cleanup);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("IIO helper functions for setting up triggered events");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 7ed859a700c4..cfd3df8416bb 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -50,6 +50,19 @@ config APDS9300
To compile this driver as a module, choose M here: the
module will be called apds9300.
+config APDS9960
+ tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor"
+ select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ depends on I2C
+ help
+ Say Y here to build I2C interface support for the Avago
+ APDS9960 gesture/RGB/ALS/proximity sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apds9960
+
config BH1750
tristate "ROHM BH1750 ambient light sensor"
depends on I2C
@@ -287,6 +300,16 @@ config TSL4531
To compile this driver as a module, choose M here: the
module will be called tsl4531.
+config US5182D
+ tristate "UPISEMI light and proximity sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for the UPISEMI US5182D
+ ambient light and proximity sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called us5182d.
+
config VCNL4000
tristate "VCNL4000 combined ALS and proximity sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 91c74c014b6f..b2c31053db0c 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ACPI_ALS) += acpi-als.o
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
+obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
@@ -27,4 +28,5 @@ obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o
+obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
new file mode 100644
index 000000000000..7d269ef9e062
--- /dev/null
+++ b/drivers/iio/light/apds9960.c
@@ -0,0 +1,1130 @@
+/*
+ * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * TODO: gesture + proximity calib offsets
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+#include <linux/of_gpio.h>
+
+#define APDS9960_REGMAP_NAME "apds9960_regmap"
+#define APDS9960_DRV_NAME "apds9960"
+
+#define APDS9960_REG_RAM_START 0x00
+#define APDS9960_REG_RAM_END 0x7f
+
+#define APDS9960_REG_ENABLE 0x80
+#define APDS9960_REG_ATIME 0x81
+#define APDS9960_REG_WTIME 0x83
+
+#define APDS9960_REG_AILTL 0x84
+#define APDS9960_REG_AILTH 0x85
+#define APDS9960_REG_AIHTL 0x86
+#define APDS9960_REG_AIHTH 0x87
+
+#define APDS9960_REG_PILT 0x89
+#define APDS9960_REG_PIHT 0x8b
+#define APDS9960_REG_PERS 0x8c
+
+#define APDS9960_REG_CONFIG_1 0x8d
+#define APDS9960_REG_PPULSE 0x8e
+
+#define APDS9960_REG_CONTROL 0x8f
+#define APDS9960_REG_CONTROL_AGAIN_MASK 0x03
+#define APDS9960_REG_CONTROL_PGAIN_MASK 0x0c
+#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT 0
+#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT 2
+
+#define APDS9960_REG_CONFIG_2 0x90
+#define APDS9960_REG_CONFIG_2_GGAIN_MASK 0x60
+#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT 5
+
+#define APDS9960_REG_ID 0x92
+
+#define APDS9960_REG_STATUS 0x93
+#define APDS9960_REG_STATUS_PS_INT BIT(5)
+#define APDS9960_REG_STATUS_ALS_INT BIT(4)
+#define APDS9960_REG_STATUS_GINT BIT(2)
+
+#define APDS9960_REG_PDATA 0x9c
+#define APDS9960_REG_POFFSET_UR 0x9d
+#define APDS9960_REG_POFFSET_DL 0x9e
+#define APDS9960_REG_CONFIG_3 0x9f
+
+#define APDS9960_REG_GPENTH 0xa0
+#define APDS9960_REG_GEXTH 0xa1
+
+#define APDS9960_REG_GCONF_1 0xa2
+#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK 0xc0
+#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT 6
+
+#define APDS9960_REG_GCONF_2 0xa3
+#define APDS9960_REG_GOFFSET_U 0xa4
+#define APDS9960_REG_GOFFSET_D 0xa5
+#define APDS9960_REG_GPULSE 0xa6
+#define APDS9960_REG_GOFFSET_L 0xa7
+#define APDS9960_REG_GOFFSET_R 0xa9
+#define APDS9960_REG_GCONF_3 0xaa
+
+#define APDS9960_REG_GCONF_4 0xab
+#define APDS9960_REG_GFLVL 0xae
+#define APDS9960_REG_GSTATUS 0xaf
+
+#define APDS9960_REG_IFORCE 0xe4
+#define APDS9960_REG_PICLEAR 0xe5
+#define APDS9960_REG_CICLEAR 0xe6
+#define APDS9960_REG_AICLEAR 0xe7
+
+#define APDS9960_DEFAULT_PERS 0x33
+#define APDS9960_DEFAULT_GPENTH 0x50
+#define APDS9960_DEFAULT_GEXTH 0x40
+
+#define APDS9960_MAX_PXS_THRES_VAL 255
+#define APDS9960_MAX_ALS_THRES_VAL 0xffff
+#define APDS9960_MAX_INT_TIME_IN_US 1000000
+
+enum apds9960_als_channel_idx {
+ IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE,
+};
+
+#define APDS9960_REG_ALS_BASE 0x94
+#define APDS9960_REG_ALS_CHANNEL(_colour) \
+ (APDS9960_REG_ALS_BASE + (IDX_ALS_##_colour * 2))
+
+enum apds9960_gesture_channel_idx {
+ IDX_DIR_UP, IDX_DIR_DOWN, IDX_DIR_LEFT, IDX_DIR_RIGHT,
+};
+
+#define APDS9960_REG_GFIFO_BASE 0xfc
+#define APDS9960_REG_GFIFO_DIR(_dir) \
+ (APDS9960_REG_GFIFO_BASE + IDX_DIR_##_dir)
+
+struct apds9960_data {
+ struct i2c_client *client;
+ struct iio_dev *indio_dev;
+ struct mutex lock;
+
+ /* regmap fields */
+ struct regmap *regmap;
+ struct regmap_field *reg_int_als;
+ struct regmap_field *reg_int_ges;
+ struct regmap_field *reg_int_pxs;
+
+ struct regmap_field *reg_enable_als;
+ struct regmap_field *reg_enable_ges;
+ struct regmap_field *reg_enable_pxs;
+
+ /* state */
+ int als_int;
+ int pxs_int;
+ int gesture_mode_running;
+
+ /* gain values */
+ int als_gain;
+ int pxs_gain;
+
+ /* integration time value in us */
+ int als_adc_int_us;
+
+ /* gesture buffer */
+ u8 buffer[4]; /* 4 8-bit channels */
+};
+
+static const struct reg_default apds9960_reg_defaults[] = {
+ /* Default ALS integration time = 2.48ms */
+ { APDS9960_REG_ATIME, 0xff },
+};
+
+static const struct regmap_range apds9960_volatile_ranges[] = {
+ regmap_reg_range(APDS9960_REG_STATUS,
+ APDS9960_REG_PDATA),
+ regmap_reg_range(APDS9960_REG_GFLVL,
+ APDS9960_REG_GSTATUS),
+ regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
+ APDS9960_REG_GFIFO_DIR(RIGHT)),
+ regmap_reg_range(APDS9960_REG_IFORCE,
+ APDS9960_REG_AICLEAR),
+};
+
+static const struct regmap_access_table apds9960_volatile_table = {
+ .yes_ranges = apds9960_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(apds9960_volatile_ranges),
+};
+
+static const struct regmap_range apds9960_precious_ranges[] = {
+ regmap_reg_range(APDS9960_REG_RAM_START, APDS9960_REG_RAM_END),
+};
+
+static const struct regmap_access_table apds9960_precious_table = {
+ .yes_ranges = apds9960_precious_ranges,
+ .n_yes_ranges = ARRAY_SIZE(apds9960_precious_ranges),
+};
+
+static const struct regmap_range apds9960_readable_ranges[] = {
+ regmap_reg_range(APDS9960_REG_ENABLE,
+ APDS9960_REG_GSTATUS),
+ regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
+ APDS9960_REG_GFIFO_DIR(RIGHT)),
+};
+
+static const struct regmap_access_table apds9960_readable_table = {
+ .yes_ranges = apds9960_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(apds9960_readable_ranges),
+};
+
+static const struct regmap_range apds9960_writeable_ranges[] = {
+ regmap_reg_range(APDS9960_REG_ENABLE, APDS9960_REG_CONFIG_2),
+ regmap_reg_range(APDS9960_REG_POFFSET_UR, APDS9960_REG_GCONF_4),
+ regmap_reg_range(APDS9960_REG_IFORCE, APDS9960_REG_AICLEAR),
+};
+
+static const struct regmap_access_table apds9960_writeable_table = {
+ .yes_ranges = apds9960_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(apds9960_writeable_ranges),
+};
+
+static const struct regmap_config apds9960_regmap_config = {
+ .name = APDS9960_REGMAP_NAME,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .use_single_rw = 1,
+
+ .volatile_table = &apds9960_volatile_table,
+ .precious_table = &apds9960_precious_table,
+ .rd_table = &apds9960_readable_table,
+ .wr_table = &apds9960_writeable_table,
+
+ .reg_defaults = apds9960_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(apds9960_reg_defaults),
+ .max_register = APDS9960_REG_GFIFO_DIR(RIGHT),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct iio_event_spec apds9960_pxs_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_event_spec apds9960_als_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),
+ },
+};
+
+#define APDS9960_GESTURE_CHANNEL(_dir, _si) { \
+ .type = IIO_PROXIMITY, \
+ .channel = _si + 1, \
+ .scan_index = _si, \
+ .indexed = 1, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 8, \
+ .storagebits = 8, \
+ }, \
+}
+
+#define APDS9960_INTENSITY_CHANNEL(_colour) { \
+ .type = IIO_INTENSITY, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_INT_TIME), \
+ .channel2 = IIO_MOD_LIGHT_##_colour, \
+ .address = APDS9960_REG_ALS_CHANNEL(_colour), \
+ .modified = 1, \
+ .scan_index = -1, \
+}
+
+static const unsigned long apds9960_scan_masks[] = {0xf, 0};
+
+static const struct iio_chan_spec apds9960_channels[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .address = APDS9960_REG_PDATA,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .channel = 0,
+ .indexed = 0,
+ .scan_index = -1,
+
+ .event_spec = apds9960_pxs_event_spec,
+ .num_event_specs = ARRAY_SIZE(apds9960_pxs_event_spec),
+ },
+ /* Gesture Sensor */
+ APDS9960_GESTURE_CHANNEL(UP, 0),
+ APDS9960_GESTURE_CHANNEL(DOWN, 1),
+ APDS9960_GESTURE_CHANNEL(LEFT, 2),
+ APDS9960_GESTURE_CHANNEL(RIGHT, 3),
+ /* ALS */
+ {
+ .type = IIO_INTENSITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ .channel2 = IIO_MOD_LIGHT_CLEAR,
+ .address = APDS9960_REG_ALS_CHANNEL(CLEAR),
+ .modified = 1,
+ .scan_index = -1,
+
+ .event_spec = apds9960_als_event_spec,
+ .num_event_specs = ARRAY_SIZE(apds9960_als_event_spec),
+ },
+ /* RGB Sensor */
+ APDS9960_INTENSITY_CHANNEL(RED),
+ APDS9960_INTENSITY_CHANNEL(GREEN),
+ APDS9960_INTENSITY_CHANNEL(BLUE),
+};
+
+/* integration time in us */
+static const int apds9960_int_time[][2] =
+ { {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} };
+
+/* gain mapping */
+static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};
+static const int apds9960_als_gain_map[] = {1, 4, 16, 64};
+
+static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8");
+static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64");
+static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7");
+
+static struct attribute *apds9960_attributes[] = {
+ &iio_const_attr_proximity_scale_available.dev_attr.attr,
+ &iio_const_attr_intensity_scale_available.dev_attr.attr,
+ &iio_const_attr_integration_time_available.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group apds9960_attribute_group = {
+ .attrs = apds9960_attributes,
+};
+
+static const struct reg_field apds9960_reg_field_int_als =
+ REG_FIELD(APDS9960_REG_ENABLE, 4, 4);
+
+static const struct reg_field apds9960_reg_field_int_ges =
+ REG_FIELD(APDS9960_REG_GCONF_4, 1, 1);
+
+static const struct reg_field apds9960_reg_field_int_pxs =
+ REG_FIELD(APDS9960_REG_ENABLE, 5, 5);
+
+static const struct reg_field apds9960_reg_field_enable_als =
+ REG_FIELD(APDS9960_REG_ENABLE, 1, 1);
+
+static const struct reg_field apds9960_reg_field_enable_ges =
+ REG_FIELD(APDS9960_REG_ENABLE, 6, 6);
+
+static const struct reg_field apds9960_reg_field_enable_pxs =
+ REG_FIELD(APDS9960_REG_ENABLE, 2, 2);
+
+static int apds9960_set_it_time(struct apds9960_data *data, int val2)
+{
+ int ret = -EINVAL;
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) {
+ if (apds9960_int_time[idx][0] == val2) {
+ mutex_lock(&data->lock);
+ ret = regmap_write(data->regmap, APDS9960_REG_ATIME,
+ apds9960_int_time[idx][1]);
+ if (!ret)
+ data->als_adc_int_us = val2;
+ mutex_unlock(&data->lock);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
+{
+ int ret = -EINVAL;
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) {
+ if (apds9960_pxs_gain_map[idx] == val) {
+ /* pxs + gesture gains are mirrored */
+ mutex_lock(&data->lock);
+ ret = regmap_update_bits(data->regmap,
+ APDS9960_REG_CONTROL,
+ APDS9960_REG_CONTROL_PGAIN_MASK,
+ idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT);
+ if (ret) {
+ mutex_unlock(&data->lock);
+ break;
+ }
+
+ ret = regmap_update_bits(data->regmap,
+ APDS9960_REG_CONFIG_2,
+ APDS9960_REG_CONFIG_2_GGAIN_MASK,
+ idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
+ if (!ret)
+ data->pxs_gain = idx;
+ mutex_unlock(&data->lock);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int apds9960_set_als_gain(struct apds9960_data *data, int val)
+{
+ int ret = -EINVAL;
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) {
+ if (apds9960_als_gain_map[idx] == val) {
+ mutex_lock(&data->lock);
+ ret = regmap_update_bits(data->regmap,
+ APDS9960_REG_CONTROL,
+ APDS9960_REG_CONTROL_AGAIN_MASK, idx);
+ if (!ret)
+ data->als_gain = idx;
+ mutex_unlock(&data->lock);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int apds9960_set_power_state(struct apds9960_data *data, bool on)
+{
+ struct device *dev = &data->client->dev;
+ int ret = 0;
+
+ mutex_lock(&data->lock);
+
+ if (on) {
+ int suspended;
+
+ suspended = pm_runtime_suspended(dev);
+ ret = pm_runtime_get_sync(dev);
+
+ /* Allow one integration cycle before allowing a reading */
+ if (suspended)
+ usleep_range(data->als_adc_int_us,
+ APDS9960_MAX_INT_TIME_IN_US);
+ } else {
+ ret = pm_runtime_put_autosuspend(dev);
+ }
+
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+#else
+static int apds9960_set_power_state(struct apds9960_data *data, bool on)
+{
+ return 0;
+}
+#endif
+
+static int apds9960_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct apds9960_data *data = iio_priv(indio_dev);
+ __le16 buf;
+ int ret = -EINVAL;
+
+ if (data->gesture_mode_running)
+ return -EBUSY;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ apds9960_set_power_state(data, true);
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ ret = regmap_read(data->regmap, chan->address, val);
+ if (!ret)
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_INTENSITY:
+ ret = regmap_bulk_read(data->regmap, chan->address,
+ &buf, 2);
+ if (!ret)
+ ret = IIO_VAL_INT;
+ *val = le16_to_cpu(buf);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ apds9960_set_power_state(data, false);
+ break;
+ case IIO_CHAN_INFO_INT_TIME:
+ /* RGB + ALS sensors only have integration time */
+ mutex_lock(&data->lock);
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ *val = 0;
+ *val2 = data->als_adc_int_us;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&data->lock);
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ mutex_lock(&data->lock);
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ *val = apds9960_pxs_gain_map[data->pxs_gain];
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_INTENSITY:
+ *val = apds9960_als_gain_map[data->als_gain];
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&data->lock);
+ break;
+ }
+
+ return ret;
+};
+
+static int apds9960_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct apds9960_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ /* RGB + ALS sensors only have int time */
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ if (val != 0)
+ return -EINVAL;
+ return apds9960_set_it_time(data, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ if (val2 != 0)
+ return -EINVAL;
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ return apds9960_set_pxs_gain(data, val);
+ case IIO_INTENSITY:
+ return apds9960_set_als_gain(data, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan,
+ enum iio_event_direction dir,
+ u8 *reg)
+{
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ *reg = APDS9960_REG_PIHT;
+ break;
+ case IIO_INTENSITY:
+ *reg = APDS9960_REG_AIHTL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_DIR_FALLING:
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ *reg = APDS9960_REG_PILT;
+ break;
+ case IIO_INTENSITY:
+ *reg = APDS9960_REG_AILTL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int apds9960_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ u8 reg;
+ __le16 buf;
+ int ret = 0;
+ struct apds9960_data *data = iio_priv(indio_dev);
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EINVAL;
+
+ ret = apds9960_get_thres_reg(chan, dir, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (chan->type == IIO_PROXIMITY) {
+ ret = regmap_read(data->regmap, reg, val);
+ if (ret < 0)
+ return ret;
+ } else if (chan->type == IIO_INTENSITY) {
+ ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+ if (ret < 0)
+ return ret;
+ *val = le16_to_cpu(buf);
+ } else
+ return -EINVAL;
+
+ *val2 = 0;
+
+ return IIO_VAL_INT;
+}
+
+static int apds9960_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ u8 reg;
+ __le16 buf;
+ int ret = 0;
+ struct apds9960_data *data = iio_priv(indio_dev);
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EINVAL;
+
+ ret = apds9960_get_thres_reg(chan, dir, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (chan->type == IIO_PROXIMITY) {
+ if (val < 0 || val > APDS9960_MAX_PXS_THRES_VAL)
+ return -EINVAL;
+ ret = regmap_write(data->regmap, reg, val);
+ if (ret < 0)
+ return ret;
+ } else if (chan->type == IIO_INTENSITY) {
+ if (val < 0 || val > APDS9960_MAX_ALS_THRES_VAL)
+ return -EINVAL;
+ buf = cpu_to_le16(val);
+ ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
+ if (ret < 0)
+ return ret;
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int apds9960_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 apds9960_data *data = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ return data->pxs_int;
+ case IIO_INTENSITY:
+ return data->als_int;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int apds9960_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 apds9960_data *data = iio_priv(indio_dev);
+ int ret;
+
+ state = !!state;
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ if (data->pxs_int == state)
+ return -EINVAL;
+
+ ret = regmap_field_write(data->reg_int_pxs, state);
+ if (ret)
+ return ret;
+ data->pxs_int = state;
+ apds9960_set_power_state(data, state);
+ break;
+ case IIO_INTENSITY:
+ if (data->als_int == state)
+ return -EINVAL;
+
+ ret = regmap_field_write(data->reg_int_als, state);
+ if (ret)
+ return ret;
+ data->als_int = state;
+ apds9960_set_power_state(data, state);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct iio_info apds9960_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &apds9960_attribute_group,
+ .read_raw = apds9960_read_raw,
+ .write_raw = apds9960_write_raw,
+ .read_event_value = apds9960_read_event,
+ .write_event_value = apds9960_write_event,
+ .read_event_config = apds9960_read_event_config,
+ .write_event_config = apds9960_write_event_config,
+
+};
+
+static inline int apds9660_fifo_is_empty(struct apds9960_data *data)
+{
+ int cnt;
+ int ret;
+
+ ret = regmap_read(data->regmap, APDS9960_REG_GFLVL, &cnt);
+ if (ret)
+ return ret;
+
+ return cnt;
+}
+
+static void apds9960_read_gesture_fifo(struct apds9960_data *data)
+{
+ int ret, cnt = 0;
+
+ mutex_lock(&data->lock);
+ data->gesture_mode_running = 1;
+
+ while (cnt-- || (cnt = apds9660_fifo_is_empty(data) > 0)) {
+ ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE,
+ &data->buffer, 4);
+
+ if (ret)
+ goto err_read;
+
+ iio_push_to_buffers(data->indio_dev, data->buffer);
+ }
+
+err_read:
+ data->gesture_mode_running = 0;
+ mutex_unlock(&data->lock);
+}
+
+static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct apds9960_data *data = iio_priv(indio_dev);
+ int ret, status;
+
+ ret = regmap_read(data->regmap, APDS9960_REG_STATUS, &status);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "irq status reg read failed\n");
+ return IRQ_HANDLED;
+ }
+
+ if ((status & APDS9960_REG_STATUS_ALS_INT) && data->als_int) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+ regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);
+ }
+
+ if ((status & APDS9960_REG_STATUS_PS_INT) && data->pxs_int) {
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns());
+ regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);
+ }
+
+ if (status & APDS9960_REG_STATUS_GINT)
+ apds9960_read_gesture_fifo(data);
+
+ return IRQ_HANDLED;
+}
+
+static int apds9960_set_powermode(struct apds9960_data *data, bool state)
+{
+ return regmap_update_bits(data->regmap, APDS9960_REG_ENABLE, 1, state);
+}
+
+static int apds9960_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct apds9960_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_field_write(data->reg_int_ges, 1);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->reg_enable_ges, 1);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_sync(&data->client->dev);
+
+ return 0;
+}
+
+static int apds9960_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct apds9960_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_field_write(data->reg_enable_ges, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_field_write(data->reg_int_ges, 0);
+ if (ret)
+ return ret;
+
+ pm_runtime_put_autosuspend(&data->client->dev);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops = {
+ .postenable = apds9960_buffer_postenable,
+ .predisable = apds9960_buffer_predisable,
+};
+
+static int apds9960_regfield_init(struct apds9960_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct regmap *regmap = data->regmap;
+
+ data->reg_int_als = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_int_als);
+ if (IS_ERR(data->reg_int_als)) {
+ dev_err(dev, "INT ALS reg field init failed\n");
+ return PTR_ERR(data->reg_int_als);
+ }
+
+ data->reg_int_ges = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_int_ges);
+ if (IS_ERR(data->reg_int_ges)) {
+ dev_err(dev, "INT gesture reg field init failed\n");
+ return PTR_ERR(data->reg_int_ges);
+ }
+
+ data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_int_pxs);
+ if (IS_ERR(data->reg_int_pxs)) {
+ dev_err(dev, "INT pxs reg field init failed\n");
+ return PTR_ERR(data->reg_int_pxs);
+ }
+
+ data->reg_enable_als = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_enable_als);
+ if (IS_ERR(data->reg_enable_als)) {
+ dev_err(dev, "Enable ALS reg field init failed\n");
+ return PTR_ERR(data->reg_enable_als);
+ }
+
+ data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_enable_ges);
+ if (IS_ERR(data->reg_enable_ges)) {
+ dev_err(dev, "Enable gesture reg field init failed\n");
+ return PTR_ERR(data->reg_enable_ges);
+ }
+
+ data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap,
+ apds9960_reg_field_enable_pxs);
+ if (IS_ERR(data->reg_enable_pxs)) {
+ dev_err(dev, "Enable PXS reg field init failed\n");
+ return PTR_ERR(data->reg_enable_pxs);
+ }
+
+ return 0;
+}
+
+static int apds9960_chip_init(struct apds9960_data *data)
+{
+ int ret;
+
+ /* Default IT for ALS of 28 ms */
+ ret = apds9960_set_it_time(data, 28000);
+ if (ret)
+ return ret;
+
+ /* Ensure gesture interrupt is OFF */
+ ret = regmap_field_write(data->reg_int_ges, 0);
+ if (ret)
+ return ret;
+
+ /* Disable gesture sensor, since polling is useless from user-space */
+ ret = regmap_field_write(data->reg_enable_ges, 0);
+ if (ret)
+ return ret;
+
+ /* Ensure proximity interrupt is OFF */
+ ret = regmap_field_write(data->reg_int_pxs, 0);
+ if (ret)
+ return ret;
+
+ /* Enable proximity sensor for polling */
+ ret = regmap_field_write(data->reg_enable_pxs, 1);
+ if (ret)
+ return ret;
+
+ /* Ensure ALS interrupt is OFF */
+ ret = regmap_field_write(data->reg_int_als, 0);
+ if (ret)
+ return ret;
+
+ /* Enable ALS sensor for polling */
+ ret = regmap_field_write(data->reg_enable_als, 1);
+ if (ret)
+ return ret;
+ /*
+ * When enabled trigger an interrupt after 3 readings
+ * outside threshold for ALS + PXS
+ */
+ ret = regmap_write(data->regmap, APDS9960_REG_PERS,
+ APDS9960_DEFAULT_PERS);
+ if (ret)
+ return ret;
+
+ /*
+ * Wait for 4 event outside gesture threshold to prevent interrupt
+ * flooding.
+ */
+ ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1,
+ APDS9960_REG_GCONF_1_GFIFO_THRES_MASK,
+ BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT);
+ if (ret)
+ return ret;
+
+ /* Default ENTER and EXIT thresholds for the GESTURE engine. */
+ ret = regmap_write(data->regmap, APDS9960_REG_GPENTH,
+ APDS9960_DEFAULT_GPENTH);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, APDS9960_REG_GEXTH,
+ APDS9960_DEFAULT_GEXTH);
+ if (ret)
+ return ret;
+
+ return apds9960_set_powermode(data, 1);
+}
+
+static int apds9960_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct apds9960_data *data;
+ struct iio_buffer *buffer;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ buffer = devm_iio_kfifo_allocate(&client->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ indio_dev->info = &apds9960_info;
+ indio_dev->name = APDS9960_DRV_NAME;
+ indio_dev->channels = apds9960_channels;
+ indio_dev->num_channels = ARRAY_SIZE(apds9960_channels);
+ indio_dev->available_scan_masks = apds9960_scan_masks;
+ indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
+ indio_dev->setup_ops = &apds9960_buffer_setup_ops;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+
+ data->regmap = devm_regmap_init_i2c(client, &apds9960_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(&client->dev, "regmap initialization failed.\n");
+ return PTR_ERR(data->regmap);
+ }
+
+ data->client = client;
+ data->indio_dev = indio_dev;
+ mutex_init(&data->lock);
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret)
+ goto error_power_down;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, 5000);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ apds9960_set_power_state(data, true);
+
+ ret = apds9960_regfield_init(data);
+ if (ret)
+ goto error_power_down;
+
+ ret = apds9960_chip_init(data);
+ if (ret)
+ goto error_power_down;
+
+ if (client->irq <= 0) {
+ dev_err(&client->dev, "no valid irq defined\n");
+ ret = -EINVAL;
+ goto error_power_down;
+ }
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, apds9960_interrupt_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "apds9960_event",
+ indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+ goto error_power_down;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_power_down;
+
+ apds9960_set_power_state(data, false);
+
+ return 0;
+
+error_power_down:
+ apds9960_set_power_state(data, false);
+
+ return ret;
+}
+
+static int apds9960_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct apds9960_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ apds9960_set_powermode(data, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds9960_runtime_suspend(struct device *dev)
+{
+ struct apds9960_data *data =
+ iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+ return apds9960_set_powermode(data, 0);
+}
+
+static int apds9960_runtime_resume(struct device *dev)
+{
+ struct apds9960_data *data =
+ iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+ return apds9960_set_powermode(data, 1);
+}
+#endif
+
+static const struct dev_pm_ops apds9960_pm_ops = {
+ SET_RUNTIME_PM_OPS(apds9960_runtime_suspend,
+ apds9960_runtime_resume, NULL)
+};
+
+static const struct i2c_device_id apds9960_id[] = {
+ { "apds9960", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, apds9960_id);
+
+static struct i2c_driver apds9960_driver = {
+ .driver = {
+ .name = APDS9960_DRV_NAME,
+ .pm = &apds9960_pm_ops,
+ },
+ .probe = apds9960_probe,
+ .remove = apds9960_remove,
+ .id_table = apds9960_id,
+};
+module_i2c_driver(apds9960_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
index 923aa6aef0ed..01e111e72d4b 100644
--- a/drivers/iio/light/opt3001.c
+++ b/drivers/iio/light/opt3001.c
@@ -793,7 +793,6 @@ static struct i2c_driver opt3001_driver = {
.driver = {
.name = "opt3001",
.of_match_table = of_match_ptr(opt3001_of_match),
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 993eb201148e..42d334ba612e 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -35,8 +35,8 @@
#define STK3310_REG_ID 0x3E
#define STK3310_MAX_REG 0x80
-#define STK3310_STATE_EN_PS 0x01
-#define STK3310_STATE_EN_ALS 0x02
+#define STK3310_STATE_EN_PS BIT(0)
+#define STK3310_STATE_EN_ALS BIT(1)
#define STK3310_STATE_STANDBY 0x00
#define STK3310_CHIP_ID_VAL 0x13
@@ -47,7 +47,6 @@
#define STK3310_DRIVER_NAME "stk3310"
#define STK3310_REGMAP_NAME "stk3310_regmap"
#define STK3310_EVENT "stk3310_event"
-#define STK3310_GPIO "stk3310_gpio"
#define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1"
@@ -241,8 +240,11 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
- regmap_field_read(data->reg_ps_gain, &index);
- if (val > stk3310_ps_max[index])
+ ret = regmap_field_read(data->reg_ps_gain, &index);
+ if (ret < 0)
+ return ret;
+
+ if (val < 0 || val > stk3310_ps_max[index])
return -EINVAL;
if (dir == IIO_EV_DIR_RISING)
@@ -266,9 +268,12 @@ static int stk3310_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
unsigned int event_val;
+ int ret;
struct stk3310_data *data = iio_priv(indio_dev);
- regmap_field_read(data->reg_int_ps, &event_val);
+ ret = regmap_field_read(data->reg_int_ps, &event_val);
+ if (ret < 0)
+ return ret;
return event_val;
}
@@ -307,14 +312,16 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
+ if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_LIGHT)
reg = STK3310_REG_ALS_DATA_MSB;
- else if (chan->type == IIO_PROXIMITY)
- reg = STK3310_REG_PS_DATA_MSB;
else
- return -EINVAL;
+ reg = STK3310_REG_PS_DATA_MSB;
+
mutex_lock(&data->lock);
ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
if (ret < 0) {
@@ -327,17 +334,23 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
if (chan->type == IIO_LIGHT)
- regmap_field_read(data->reg_als_it, &index);
+ ret = regmap_field_read(data->reg_als_it, &index);
else
- regmap_field_read(data->reg_ps_it, &index);
+ ret = regmap_field_read(data->reg_ps_it, &index);
+ if (ret < 0)
+ return ret;
+
*val = stk3310_it_table[index][0];
*val2 = stk3310_it_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_LIGHT)
- regmap_field_read(data->reg_als_gain, &index);
+ ret = regmap_field_read(data->reg_als_gain, &index);
else
- regmap_field_read(data->reg_ps_gain, &index);
+ ret = regmap_field_read(data->reg_ps_gain, &index);
+ if (ret < 0)
+ return ret;
+
*val = stk3310_scale_table[index][0];
*val2 = stk3310_scale_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
@@ -354,6 +367,9 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
int index;
struct stk3310_data *data = iio_priv(indio_dev);
+ if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
index = stk3310_get_index(stk3310_it_table,
@@ -368,7 +384,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
ret = regmap_field_write(data->reg_ps_it, index);
if (ret < 0)
dev_err(&data->client->dev,
- "sensor configuration failed\n");
+ "sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
@@ -385,7 +401,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
ret = regmap_field_write(data->reg_ps_gain, index);
if (ret < 0)
dev_err(&data->client->dev,
- "sensor configuration failed\n");
+ "sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
}
@@ -419,8 +435,8 @@ static int stk3310_set_state(struct stk3310_data *data, u8 state)
dev_err(&client->dev, "failed to change sensor state\n");
} else if (state != STK3310_STATE_STANDBY) {
/* Don't reset the 'enabled' flags if we're going in standby */
- data->ps_enabled = !!(state & 0x01);
- data->als_enabled = !!(state & 0x02);
+ data->ps_enabled = !!(state & STK3310_STATE_EN_PS);
+ data->als_enabled = !!(state & STK3310_STATE_EN_ALS);
}
mutex_unlock(&data->lock);
@@ -435,7 +451,10 @@ static int stk3310_init(struct iio_dev *indio_dev)
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
- regmap_read(data->regmap, STK3310_REG_ID, &chipid);
+ ret = regmap_read(data->regmap, STK3310_REG_ID, &chipid);
+ if (ret < 0)
+ return ret;
+
if (chipid != STK3310_CHIP_ID_VAL &&
chipid != STK3311_CHIP_ID_VAL) {
dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
@@ -457,30 +476,6 @@ static int stk3310_init(struct iio_dev *indio_dev)
return ret;
}
-static int stk3310_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -604,27 +599,30 @@ static int stk3310_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0)
- client->irq = stk3310_gpio_probe(client);
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk3310_irq_handler,
stk3310_irq_event_handler,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
STK3310_EVENT, indio_dev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ client->irq);
+ goto err_standby;
+ }
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
- stk3310_set_state(data, STK3310_STATE_STANDBY);
+ goto err_standby;
}
+ return 0;
+
+err_standby:
+ stk3310_set_state(data, STK3310_STATE_STANDBY);
return ret;
}
@@ -648,7 +646,7 @@ static int stk3310_suspend(struct device *dev)
static int stk3310_resume(struct device *dev)
{
- int state = 0;
+ u8 state = 0;
struct stk3310_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c
index 26979183d27c..cf94ec72b181 100644
--- a/drivers/iio/light/tsl4531.c
+++ b/drivers/iio/light/tsl4531.c
@@ -158,9 +158,9 @@ static int tsl4531_check_id(struct i2c_client *client)
case TSL45313_ID:
case TSL45315_ID:
case TSL45317_ID:
- return 1;
- default:
return 0;
+ default:
+ return -ENODEV;
}
}
@@ -180,9 +180,10 @@ static int tsl4531_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->lock);
- if (!tsl4531_check_id(client)) {
+ ret = tsl4531_check_id(client);
+ if (ret) {
dev_err(&client->dev, "no TSL4531 sensor\n");
- return -ENODEV;
+ return ret;
}
ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
new file mode 100644
index 000000000000..49dab3cb3e23
--- /dev/null
+++ b/drivers/iio/light/us5182d.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * To do: Interrupt support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+
+#define US5182D_REG_CFG0 0x00
+#define US5182D_CFG0_ONESHOT_EN BIT(6)
+#define US5182D_CFG0_SHUTDOWN_EN BIT(7)
+#define US5182D_CFG0_WORD_ENABLE BIT(0)
+
+#define US5182D_REG_CFG1 0x01
+#define US5182D_CFG1_ALS_RES16 BIT(4)
+#define US5182D_CFG1_AGAIN_DEFAULT 0x00
+
+#define US5182D_REG_CFG2 0x02
+#define US5182D_CFG2_PX_RES16 BIT(4)
+#define US5182D_CFG2_PXGAIN_DEFAULT BIT(2)
+
+#define US5182D_REG_CFG3 0x03
+#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))
+
+#define US5182D_REG_CFG4 0x10
+
+/*
+ * Registers for tuning the auto dark current cancelling feature.
+ * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling.
+ * when ALS > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark
+ * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark
+ */
+#define US5182D_REG_UDARK_TH 0x27
+#define US5182D_REG_DARK_AUTO_EN 0x2b
+#define US5182D_REG_AUTO_LDARK_GAIN 0x29
+#define US5182D_REG_AUTO_HDARK_GAIN 0x2a
+
+#define US5182D_OPMODE_ALS 0x01
+#define US5182D_OPMODE_PX 0x02
+#define US5182D_OPMODE_SHIFT 4
+
+#define US5182D_REG_DARK_AUTO_EN_DEFAULT 0x80
+#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT 0x16
+#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT 0x00
+
+#define US5182D_REG_ADL 0x0c
+#define US5182D_REG_PDL 0x0e
+
+#define US5182D_REG_MODE_STORE 0x21
+#define US5182D_STORE_MODE 0x01
+
+#define US5182D_REG_CHIPID 0xb2
+
+#define US5182D_OPMODE_MASK GENMASK(5, 4)
+#define US5182D_AGAIN_MASK 0x07
+#define US5182D_RESET_CHIP 0x01
+
+#define US5182D_CHIPID 0x26
+#define US5182D_DRV_NAME "us5182d"
+
+#define US5182D_GA_RESOLUTION 1000
+
+#define US5182D_READ_BYTE 1
+#define US5182D_READ_WORD 2
+#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
+
+/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
+static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
+ 3900, 2100};
+
+/*
+ * Experimental thresholds that work with US5182D sensor on evaluation board
+ * roughly between 12-32 lux
+ */
+static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000,
+ 8000};
+
+enum mode {
+ US5182D_ALS_PX,
+ US5182D_ALS_ONLY,
+ US5182D_PX_ONLY
+};
+
+struct us5182d_data {
+ struct i2c_client *client;
+ struct mutex lock;
+
+ /* Glass attenuation factor */
+ u32 ga;
+
+ /* Dark gain tuning */
+ u8 lower_dark_gain;
+ u8 upper_dark_gain;
+ u16 *us5182d_dark_ths;
+
+ u8 opmode;
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available,
+ "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");
+
+static struct attribute *us5182d_attrs[] = {
+ &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group us5182d_attr_group = {
+ .attrs = us5182d_attrs,
+};
+
+static const struct {
+ u8 reg;
+ u8 val;
+} us5182d_regvals[] = {
+ {US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN |
+ US5182D_CFG0_WORD_ENABLE)},
+ {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
+ {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
+ US5182D_CFG2_PXGAIN_DEFAULT)},
+ {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
+ {US5182D_REG_MODE_STORE, US5182D_STORE_MODE},
+ {US5182D_REG_CFG4, 0x00},
+};
+
+static const struct iio_chan_spec us5182d_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }
+};
+
+static int us5182d_get_als(struct us5182d_data *data)
+{
+ int ret;
+ unsigned long result;
+
+ ret = i2c_smbus_read_word_data(data->client,
+ US5182D_REG_ADL);
+ if (ret < 0)
+ return ret;
+
+ result = ret * data->ga / US5182D_GA_RESOLUTION;
+ if (result > 0xffff)
+ result = 0xffff;
+
+ return result;
+}
+
+static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * In oneshot mode the chip will power itself down after taking the
+ * required measurement.
+ */
+ ret = ret | US5182D_CFG0_ONESHOT_EN;
+
+ /* update mode */
+ ret = ret & ~US5182D_OPMODE_MASK;
+ ret = ret | (mode << US5182D_OPMODE_SHIFT);
+
+ /*
+ * After updating the operating mode, the chip requires that
+ * the operation is stored, by writing 1 in the STORE_MODE
+ * register (auto-clearing).
+ */
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
+ if (ret < 0)
+ return ret;
+
+ if (mode == data->opmode)
+ return 0;
+
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
+ US5182D_STORE_MODE);
+ if (ret < 0)
+ return ret;
+
+ data->opmode = mode;
+ msleep(US5182D_OPSTORE_SLEEP_TIME);
+
+ return 0;
+}
+
+static int us5182d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ mutex_lock(&data->lock);
+ ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
+ if (ret < 0)
+ goto out_err;
+
+ ret = us5182d_get_als(data);
+ if (ret < 0)
+ goto out_err;
+ mutex_unlock(&data->lock);
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_PROXIMITY:
+ mutex_lock(&data->lock);
+ ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
+ if (ret < 0)
+ goto out_err;
+
+ ret = i2c_smbus_read_word_data(data->client,
+ US5182D_REG_PDL);
+ if (ret < 0)
+ goto out_err;
+ mutex_unlock(&data->lock);
+ *val = ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+ *val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+out_err:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/**
+ * us5182d_update_dark_th - update Darh_Th registers
+ * @data us5182d_data structure
+ * @index index in us5182d_dark_ths array to use for the updated value
+ *
+ * Function needs to be called with a lock held because it needs two i2c write
+ * byte operations as these registers (0x27 0x28) don't work in word mode
+ * accessing.
+ */
+static int us5182d_update_dark_th(struct us5182d_data *data, int index)
+{
+ __be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH,
+ ((u8 *)&dark_th)[0]);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1,
+ ((u8 *)&dark_th)[1]);
+}
+
+/**
+ * us5182d_apply_scale - update the ALS scale
+ * @data us5182d_data structure
+ * @index index in us5182d_scales array to use for the updated value
+ *
+ * Function needs to be called with a lock held as we're having more than one
+ * i2c operation.
+ */
+static int us5182d_apply_scale(struct us5182d_data *data, int index)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
+ if (ret < 0)
+ return ret;
+
+ ret = ret & (~US5182D_AGAIN_MASK);
+ ret |= index;
+
+ ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret);
+ if (ret < 0)
+ return ret;
+
+ return us5182d_update_dark_th(data, index);
+}
+
+static int us5182d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret, i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (val != 0)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++)
+ if (val2 == us5182d_scales[i]) {
+ mutex_lock(&data->lock);
+ ret = us5182d_apply_scale(data, i);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info us5182d_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = us5182d_read_raw,
+ .write_raw = us5182d_write_raw,
+ .attrs = &us5182d_attr_group,
+};
+
+static int us5182d_reset(struct iio_dev *indio_dev)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3,
+ US5182D_RESET_CHIP);
+}
+
+static int us5182d_init(struct iio_dev *indio_dev)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int i, ret;
+
+ ret = us5182d_reset(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ data->opmode = 0;
+ for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
+ ret = i2c_smbus_write_byte_data(data->client,
+ us5182d_regvals[i].reg,
+ us5182d_regvals[i].val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void us5182d_get_platform_data(struct iio_dev *indio_dev)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+
+ if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef",
+ &data->ga))
+ data->ga = US5182D_GA_RESOLUTION;
+ if (device_property_read_u16_array(&data->client->dev,
+ "upisemi,dark-ths",
+ data->us5182d_dark_ths,
+ ARRAY_SIZE(us5182d_dark_ths_vals)))
+ data->us5182d_dark_ths = us5182d_dark_ths_vals;
+ if (device_property_read_u8(&data->client->dev,
+ "upisemi,upper-dark-gain",
+ &data->upper_dark_gain))
+ data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT;
+ if (device_property_read_u8(&data->client->dev,
+ "upisemi,lower-dark-gain",
+ &data->lower_dark_gain))
+ data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
+}
+
+static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
+{
+ struct us5182d_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ US5182D_REG_AUTO_LDARK_GAIN,
+ data->lower_dark_gain);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ US5182D_REG_AUTO_HDARK_GAIN,
+ data->upper_dark_gain);
+ if (ret < 0)
+ return ret;
+
+ return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN,
+ US5182D_REG_DARK_AUTO_EN_DEFAULT);
+}
+
+static int us5182d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct us5182d_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;
+
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &us5182d_info;
+ indio_dev->name = US5182D_DRV_NAME;
+ indio_dev->channels = us5182d_channels;
+ indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);
+ if (ret != US5182D_CHIPID) {
+ dev_err(&data->client->dev,
+ "Failed to detect US5182 light chip\n");
+ return (ret < 0) ? ret : -ENODEV;
+ }
+
+ us5182d_get_platform_data(indio_dev);
+ ret = us5182d_init(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ ret = us5182d_dark_gain_config(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ return iio_device_register(indio_dev);
+}
+
+static int us5182d_remove(struct i2c_client *client)
+{
+ iio_device_unregister(i2c_get_clientdata(client));
+ return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0,
+ US5182D_CFG0_SHUTDOWN_EN);
+}
+
+static const struct acpi_device_id us5182d_acpi_match[] = {
+ { "USD5182", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
+
+static const struct i2c_device_id us5182d_id[] = {
+ {"usd5182", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, us5182d_id);
+
+static struct i2c_driver us5182d_driver = {
+ .driver = {
+ .name = US5182D_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
+ },
+ .probe = us5182d_probe,
+ .remove = us5182d_remove,
+ .id_table = us5182d_id,
+
+};
+module_i2c_driver(us5182d_driver);
+
+MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
+MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index efb9350b0d76..868abada3409 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -24,6 +24,24 @@ config AK09911
help
Deprecated: AK09911 is now supported by AK8975 driver.
+config BMC150_MAGN
+ tristate "Bosch BMC150 Magnetometer Driver"
+ depends on I2C
+ select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for the BMC150 magnetometer.
+
+ Currently this only supports the device via an i2c interface.
+
+ This is a combo module with both accelerometer and magnetometer.
+ This driver is only implementing magnetometer part, which has
+ its own address and register map.
+
+ To compile this driver as a module, choose M here: the module will be
+ called bmc150_magn.
+
config MAG3110
tristate "Freescale MAG3110 3-Axis Magnetometer"
depends on I2C
@@ -87,19 +105,4 @@ config IIO_ST_MAGN_SPI_3AXIS
depends on IIO_ST_MAGN_3AXIS
depends on IIO_ST_SENSORS_SPI
-config BMC150_MAGN
- tristate "Bosch BMC150 Magnetometer Driver"
- depends on I2C
- select REGMAP_I2C
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- Say yes here to build support for the BMC150 magnetometer.
-
- Currently this only supports the device via an i2c interface.
-
- This is a combo module with both accelerometer and magnetometer.
- This driver is only implementing magnetometer part, which has
- its own address and register map.
-
endmenu
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 33b1d4d54ee7..2c72df458ec2 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -4,6 +4,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AK8975) += ak8975.o
+obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_MMC35240) += mmc35240.o
@@ -14,5 +15,3 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
-
-obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index d8e614ca069f..1615b23d7b2a 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -37,7 +37,6 @@
#define BMC150_MAGN_DRV_NAME "bmc150_magn"
#define BMC150_MAGN_IRQ_NAME "bmc150_magn_event"
-#define BMC150_MAGN_GPIO_INT "interrupt"
#define BMC150_MAGN_REG_CHIP_ID 0x40
#define BMC150_MAGN_CHIP_ID_VAL 0x32
@@ -833,31 +832,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = {
.postdisable = bmc150_magn_buffer_postdisable,
};
-static int bmc150_magn_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready GPIO interrupt pin */
- gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "ACPI GPIO get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const char *bmc150_magn_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
@@ -911,9 +885,6 @@ static int bmc150_magn_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_magn_info;
- if (client->irq <= 0)
- client->irq = bmc150_magn_gpio_probe(client);
-
if (client->irq > 0) {
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index f8dc4b85d70c..b27f0146647b 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -560,6 +560,7 @@ static const struct iio_info magn_info = {
.attrs = &st_magn_attribute_group,
.read_raw = &st_magn_read_raw,
.write_raw = &st_magn_write_raw,
+ .debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
new file mode 100644
index 000000000000..fd75db73e582
--- /dev/null
+++ b/drivers/iio/potentiometer/Kconfig
@@ -0,0 +1,20 @@
+#
+# Potentiometer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Digital potentiometers"
+
+config MCP4531
+ tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Microchip
+ MCP4531, MCP4532, MCP4551, MCP4552,
+ MCP4631, MCP4632, MCP4651, MCP4652
+ digital potentiomenter chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcp4531.
+
+endmenu
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
new file mode 100644
index 000000000000..8afe49227012
--- /dev/null
+++ b/drivers/iio/potentiometer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O potentiometer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_MCP4531) += mcp4531.o
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
new file mode 100644
index 000000000000..a3f66874ee2e
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -0,0 +1,231 @@
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ * Copyright (c) 2015 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
+ *
+ * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
+ * mcp4531 1 129 5, 10, 50, 100 010111x
+ * mcp4532 1 129 5, 10, 50, 100 01011xx
+ * mcp4551 1 257 5, 10, 50, 100 010111x
+ * mcp4552 1 257 5, 10, 50, 100 01011xx
+ * mcp4631 2 129 5, 10, 50, 100 0101xxx
+ * mcp4632 2 129 5, 10, 50, 100 01011xx
+ * mcp4651 2 257 5, 10, 50, 100 0101xxx
+ * mcp4652 2 257 5, 10, 50, 100 01011xx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+
+struct mcp4531_cfg {
+ int wipers;
+ int max_pos;
+ int kohms;
+};
+
+enum mcp4531_type {
+ MCP453x_502,
+ MCP453x_103,
+ MCP453x_503,
+ MCP453x_104,
+ MCP455x_502,
+ MCP455x_103,
+ MCP455x_503,
+ MCP455x_104,
+ MCP463x_502,
+ MCP463x_103,
+ MCP463x_503,
+ MCP463x_104,
+ MCP465x_502,
+ MCP465x_103,
+ MCP465x_503,
+ MCP465x_104,
+};
+
+static const struct mcp4531_cfg mcp4531_cfg[] = {
+ [MCP453x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
+ [MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
+ [MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
+ [MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
+ [MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
+ [MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
+ [MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
+ [MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+ [MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
+ [MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
+ [MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
+ [MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
+ [MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
+ [MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
+ [MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
+ [MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
+};
+
+#define MCP4531_WRITE (0 << 2)
+#define MCP4531_INCR (1 << 2)
+#define MCP4531_DECR (2 << 2)
+#define MCP4531_READ (3 << 2)
+
+#define MCP4531_WIPER_SHIFT (4)
+
+struct mcp4531_data {
+ struct i2c_client *client;
+ unsigned long devid;
+};
+
+#define MCP4531_CHANNEL(ch) { \
+ .type = IIO_RESISTANCE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (ch), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mcp4531_channels[] = {
+ MCP4531_CHANNEL(0),
+ MCP4531_CHANNEL(1),
+};
+
+static int mcp4531_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ MCP4531_READ | address);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * mcp4531_cfg[data->devid].kohms;
+ *val2 = mcp4531_cfg[data->devid].max_pos;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int mcp4531_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i2c_smbus_write_byte_data(data->client,
+ MCP4531_WRITE | address | (val >> 8),
+ val & 0xff);
+}
+
+static const struct iio_info mcp4531_info = {
+ .read_raw = mcp4531_read_raw,
+ .write_raw = mcp4531_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int mcp4531_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ unsigned long devid = id->driver_data;
+ struct mcp4531_data *data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(dev, "SMBUS Word Data not supported\n");
+ return -EIO;
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->devid = devid;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &mcp4531_info;
+ indio_dev->channels = mcp4531_channels;
+ indio_dev->num_channels = mcp4531_cfg[devid].wipers;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id mcp4531_id[] = {
+ { "mcp4531-502", MCP453x_502 },
+ { "mcp4531-103", MCP453x_103 },
+ { "mcp4531-503", MCP453x_503 },
+ { "mcp4531-104", MCP453x_104 },
+ { "mcp4532-502", MCP453x_502 },
+ { "mcp4532-103", MCP453x_103 },
+ { "mcp4532-503", MCP453x_503 },
+ { "mcp4532-104", MCP453x_104 },
+ { "mcp4551-502", MCP455x_502 },
+ { "mcp4551-103", MCP455x_103 },
+ { "mcp4551-503", MCP455x_503 },
+ { "mcp4551-104", MCP455x_104 },
+ { "mcp4552-502", MCP455x_502 },
+ { "mcp4552-103", MCP455x_103 },
+ { "mcp4552-503", MCP455x_503 },
+ { "mcp4552-104", MCP455x_104 },
+ { "mcp4631-502", MCP463x_502 },
+ { "mcp4631-103", MCP463x_103 },
+ { "mcp4631-503", MCP463x_503 },
+ { "mcp4631-104", MCP463x_104 },
+ { "mcp4632-502", MCP463x_502 },
+ { "mcp4632-103", MCP463x_103 },
+ { "mcp4632-503", MCP463x_503 },
+ { "mcp4632-104", MCP463x_104 },
+ { "mcp4651-502", MCP465x_502 },
+ { "mcp4651-103", MCP465x_103 },
+ { "mcp4651-503", MCP465x_503 },
+ { "mcp4651-104", MCP465x_104 },
+ { "mcp4652-502", MCP465x_502 },
+ { "mcp4652-103", MCP465x_103 },
+ { "mcp4652-503", MCP465x_503 },
+ { "mcp4652-104", MCP465x_104 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4531_id);
+
+static struct i2c_driver mcp4531_driver = {
+ .driver = {
+ .name = "mcp4531",
+ },
+ .probe = mcp4531_probe,
+ .id_table = mcp4531_id,
+};
+
+module_i2c_driver(mcp4531_driver);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_DESCRIPTION("MCP4531 digital potentiometer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 4745179ff64b..6f2e7c9ac23e 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -79,6 +79,19 @@ config MS5611_SPI
To compile this driver as a module, choose M here: the module will
be called ms5611_spi.
+config MS5637
+ tristate "Measurement Specialties MS5637 pressure & temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ MS5637 pressure and temperature sensor.
+ This driver is also used for MS8607 temperature, pressure & humidity
+ sensor
+
+ This driver can also be built as a module. If so, the module will
+ be called ms5637.
+
config IIO_ST_PRESS
tristate "STMicroelectronics pressure sensor Driver"
depends on (I2C || SPI_MASTER) && SYSFS
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index a4f98f8d90ed..46571c96823f 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_MS5611) += ms5611_core.o
obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
+obj-$(CONFIG_MS5637) += ms5637.o
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
new file mode 100644
index 000000000000..e8d0e0da938d
--- /dev/null
+++ b/drivers/iio/pressure/ms5637.c
@@ -0,0 +1,190 @@
+/*
+ * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
+ * pressure & temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x76)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 };
+/* String copy of the above const for readability purpose */
+static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30";
+
+static int ms5637_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ int temperature;
+ unsigned int pressure;
+ struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = ms_sensors_read_temp_and_pressure(dev_data,
+ &temperature,
+ &pressure);
+ if (ret)
+ return ret;
+
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ case IIO_PRESSURE: /* in kPa */
+ *val = pressure / 1000;
+ *val2 = (pressure % 1000) * 1000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = ms5637_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ms5637_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(ms5637_samp_freq);
+ while (i-- > 0)
+ if (val == ms5637_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ dev_data->res_index = i;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec ms5637_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
+
+static struct attribute *ms5637_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ms5637_attribute_group = {
+ .attrs = ms5637_attributes,
+};
+
+static const struct iio_info ms5637_info = {
+ .read_raw = ms5637_read_raw,
+ .write_raw = ms5637_write_raw,
+ .attrs = &ms5637_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int ms5637_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_tp_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 5;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &ms5637_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ms5637_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ms5637_channels);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, 0x1E, 3000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_tp_read_prom(dev_data);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ms5637_id[] = {
+ {"ms5637", 0},
+ {"ms8607-temppressure", 1},
+ {}
+};
+
+static struct i2c_driver ms5637_driver = {
+ .probe = ms5637_probe,
+ .id_table = ms5637_id,
+ .driver = {
+ .name = "ms5637"
+ },
+};
+
+module_i2c_driver(ms5637_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index eb41d2b92c24..b39a2fb0671c 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -400,6 +400,7 @@ static const struct iio_info press_info = {
.attrs = &st_press_attribute_group,
.read_raw = &st_press_read_raw,
.write_raw = &st_press_write_raw,
+ .debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 41a8d8ffa0de..ef4c73db5b53 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -20,6 +20,18 @@ endmenu
menu "Proximity sensors"
+config LIDAR_LITE_V2
+ tristate "PulsedLight LIDAR sensor"
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ depends on I2C
+ help
+ Say Y to build a driver for PulsedLight LIDAR range finding
+ sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pulsedlight-lite-v2
+
config SX9500
tristate "SX9500 Semtech proximity sensor"
select IIO_BUFFER
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 9818dc562abd..9aadd9a8ee99 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -4,4 +4,5 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
+obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_SX9500) += sx9500.o
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index bc0d68efd455..e95035136889 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -434,6 +434,12 @@ static int as3935_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id as3935_of_match[] = {
+ { .compatible = "ams,as3935", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, as3935_of_match);
+
static const struct spi_device_id as3935_id[] = {
{"as3935", 0},
{},
@@ -443,6 +449,7 @@ MODULE_DEVICE_TABLE(spi, as3935_id);
static struct spi_driver as3935_driver = {
.driver = {
.name = "as3935",
+ .of_match_table = of_match_ptr(as3935_of_match),
.owner = THIS_MODULE,
.pm = AS3935_PM_OPS,
},
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
new file mode 100644
index 000000000000..961f9f990faf
--- /dev/null
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -0,0 +1,289 @@
+/*
+ * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * TODO: runtime pm, interrupt mode, and signal strength reporting
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define LIDAR_REG_CONTROL 0x00
+#define LIDAR_REG_CONTROL_ACQUIRE BIT(2)
+
+#define LIDAR_REG_STATUS 0x01
+#define LIDAR_REG_STATUS_INVALID BIT(3)
+#define LIDAR_REG_STATUS_READY BIT(0)
+
+#define LIDAR_REG_DATA_HBYTE 0x0f
+#define LIDAR_REG_DATA_LBYTE 0x10
+
+#define LIDAR_DRV_NAME "lidar"
+
+struct lidar_data {
+ struct iio_dev *indio_dev;
+ struct i2c_client *client;
+
+ u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
+};
+
+static const struct iio_chan_spec lidar_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static int lidar_read_byte(struct lidar_data *data, int reg)
+{
+ struct i2c_client *client = data->client;
+ int ret;
+
+ /*
+ * Device needs a STOP condition between address write, and data read
+ * so in turn i2c_smbus_read_byte_data cannot be used
+ */
+
+ ret = i2c_smbus_write_byte(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot write addr value");
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0)
+ dev_err(&client->dev, "cannot read data value");
+
+ return ret;
+}
+
+static inline int lidar_write_control(struct lidar_data *data, int val)
+{
+ return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
+}
+
+static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
+{
+ int ret;
+ int val;
+
+ ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
+ if (ret < 0)
+ return ret;
+ val = ret << 8;
+
+ ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
+ if (ret < 0)
+ return ret;
+
+ val |= ret;
+ *reg = val;
+
+ return 0;
+}
+
+static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
+{
+ struct i2c_client *client = data->client;
+ int tries = 10;
+ int ret;
+
+ /* start sample */
+ ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot send start measurement command");
+ return ret;
+ }
+
+ while (tries--) {
+ usleep_range(1000, 2000);
+
+ ret = lidar_read_byte(data, LIDAR_REG_STATUS);
+ if (ret < 0)
+ break;
+
+ /* return 0 since laser is likely pointed out of range */
+ if (ret & LIDAR_REG_STATUS_INVALID) {
+ *reg = 0;
+ ret = 0;
+ break;
+ }
+
+ /* sample ready to read */
+ if (!(ret & LIDAR_REG_STATUS_READY)) {
+ ret = lidar_read_measurement(data, reg);
+ break;
+ }
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int lidar_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct lidar_data *data = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ if (iio_buffer_enabled(indio_dev) && mask == IIO_CHAN_INFO_RAW) {
+ ret = -EBUSY;
+ goto error_busy;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ u16 reg;
+
+ ret = lidar_get_measurement(data, &reg);
+ if (!ret) {
+ *val = reg;
+ ret = IIO_VAL_INT;
+ }
+ break;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = 10000;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ }
+
+error_busy:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static irqreturn_t lidar_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct lidar_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = lidar_get_measurement(data, data->buffer);
+ if (!ret) {
+ iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_get_time_ns());
+ } else {
+ dev_err(&data->client->dev, "cannot read LIDAR measurement");
+ }
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info lidar_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = lidar_read_raw,
+};
+
+static int lidar_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lidar_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ indio_dev->info = &lidar_info;
+ indio_dev->name = LIDAR_DRV_NAME;
+ indio_dev->channels = lidar_channels;
+ indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+
+ data->client = client;
+ data->indio_dev = indio_dev;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ lidar_trigger_handler, NULL);
+ if (ret)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_unreg_buffer;
+
+ return 0;
+
+error_unreg_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ return ret;
+}
+
+static int lidar_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id lidar_id[] = {
+ {"lidar-lite-v2", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, lidar_id);
+
+static const struct of_device_id lidar_dt_ids[] = {
+ { .compatible = "pulsedlight,lidar-lite-v2" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lidar_dt_ids);
+
+static struct i2c_driver lidar_driver = {
+ .driver = {
+ .name = LIDAR_DRV_NAME,
+ .of_match_table = of_match_ptr(lidar_dt_ids),
+ },
+ .probe = lidar_probe,
+ .remove = lidar_remove,
+ .id_table = lidar_id,
+};
+module_i2c_driver(lidar_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 3d756bd8c703..66cd09a18786 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -868,21 +868,12 @@ static void sx9500_gpio_probe(struct i2c_client *client,
struct sx9500_data *data)
{
struct device *dev;
- struct gpio_desc *gpio;
if (!client)
return;
dev = &client->dev;
- if (client->irq <= 0) {
- gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN);
- if (IS_ERR(gpio))
- dev_err(dev, "gpio get irq failed\n");
- else
- client->irq = gpiod_to_irq(gpio);
- }
-
data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET,
0, GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_rst)) {
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 21feaa4661b4..c4664e5de791 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -23,4 +23,26 @@ config TMP006
This driver can also be built as a module. If so, the module will
be called tmp006.
+config TSYS01
+ tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ TSYS01 I2C temperature sensor.
+
+ This driver can also be built as a module. If so, the module will
+ be called tsys01.
+
+config TSYS02D
+ tristate "Measurement Specialties TSYS02D temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ TSYS02D temperature sensor.
+
+ This driver can also be built as a module. If so, the module will
+ be called tsys02d.
+
endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 40710a81158e..02bc79d49b24 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -4,3 +4,5 @@
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
+obj-$(CONFIG_TSYS01) += tsys01.o
+obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 5d033a5af615..a570c2e2aac3 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
* Copyright (c) 2015 Essensium NV
+ * Copyright (c) 2015 Melexis
*
* 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
@@ -20,7 +21,6 @@
* always has a pull-up so we do not need an extra GPIO to drive it high. If
* the "wakeup" GPIO is not given, power management will be disabled.
*
- * TODO: filter configuration
*/
#include <linux/err.h>
@@ -32,6 +32,7 @@
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define MLX90614_OP_RAM 0x00
#define MLX90614_OP_EEPROM 0x20
@@ -71,6 +72,7 @@
#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
+#define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */
struct mlx90614_data {
struct i2c_client *client;
@@ -79,6 +81,20 @@ struct mlx90614_data {
unsigned long ready_timestamp; /* in jiffies */
};
+/* Bandwidth values for IIR filtering */
+static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
+static IIO_CONST_ATTR(in_temp_object_filter_low_pass_3db_frequency_available,
+ "0.15 0.20 0.31 0.77 0.86 1.10 1.53 7.23");
+
+static struct attribute *mlx90614_attributes[] = {
+ &iio_const_attr_in_temp_object_filter_low_pass_3db_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group mlx90614_attr_group = {
+ .attrs = mlx90614_attributes,
+};
+
/*
* Erase an address and write word.
* The mutex must be locked before calling.
@@ -117,6 +133,43 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command,
return ret;
}
+/*
+ * Find the IIR value inside mlx90614_iir_values array and return its position
+ * which is equivalent to the bit value in sensor register
+ */
+static inline s32 mlx90614_iir_search(const struct i2c_client *client,
+ int value)
+{
+ int i;
+ s32 ret;
+
+ for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) {
+ if (value == mlx90614_iir_values[i])
+ break;
+ }
+
+ if (i == ARRAY_SIZE(mlx90614_iir_values))
+ return -EINVAL;
+
+ /*
+ * CONFIG register values must not be changed so
+ * we must read them before we actually write
+ * changes
+ */
+ ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~MLX90614_CONFIG_FIR_MASK;
+ ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT;
+ ret &= ~MLX90614_CONFIG_IIR_MASK;
+ ret |= i << MLX90614_CONFIG_IIR_SHIFT;
+
+ /* Write changed values */
+ ret = mlx90614_write_word(client, MLX90614_CONFIG, ret);
+ return ret;
+}
+
#ifdef CONFIG_PM
/*
* If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since
@@ -236,6 +289,21 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
}
return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
+ FIR = 1024 */
+ mlx90614_power_get(data, false);
+ mutex_lock(&data->lock);
+ ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
+ mutex_unlock(&data->lock);
+ mlx90614_power_put(data);
+
+ if (ret < 0)
+ return ret;
+
+ *val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100;
+ *val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) *
+ 10000;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -263,6 +331,18 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
mlx90614_power_put(data);
return ret;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR Filter setting */
+ if (val < 0 || val2 < 0)
+ return -EINVAL;
+
+ mlx90614_power_get(data, false);
+ mutex_lock(&data->lock);
+ ret = mlx90614_iir_search(data->client,
+ val * 100 + val2 / 10000);
+ mutex_unlock(&data->lock);
+ mlx90614_power_put(data);
+
+ return ret;
default:
return -EINVAL;
}
@@ -275,6 +355,8 @@ static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_CALIBEMISSIVITY:
return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -294,7 +376,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.modified = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+ BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
@@ -305,7 +388,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.channel = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+ BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
@@ -315,6 +399,7 @@ static const struct iio_info mlx90614_info = {
.read_raw = mlx90614_read_raw,
.write_raw = mlx90614_write_raw,
.write_raw_get_fmt = mlx90614_write_raw_get_fmt,
+ .attrs = &mlx90614_attr_group,
.driver_module = THIS_MODULE,
};
@@ -569,5 +654,6 @@ module_i2c_driver(mlx90614_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
+MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
new file mode 100644
index 000000000000..05c12060ce8d
--- /dev/null
+++ b/drivers/iio/temperature/tsys01.c
@@ -0,0 +1,230 @@
+/*
+ * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+/* TSYS01 Commands */
+#define TSYS01_RESET 0x1E
+#define TSYS01_CONVERSION_START 0x48
+#define TSYS01_ADC_READ 0x00
+#define TSYS01_PROM_READ 0xA0
+
+#define TSYS01_PROM_WORDS_NB 8
+
+struct tsys01_dev {
+ void *client;
+ struct mutex lock; /* lock during conversion */
+
+ int (*reset)(void *cli, u8 cmd, unsigned int delay);
+ int (*convert_and_read)(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc);
+ int (*read_prom_word)(void *cli, int cmd, u16 *word);
+
+ u16 prom[TSYS01_PROM_WORDS_NB];
+};
+
+/* Multiplication coefficients for temperature computation */
+static const int coeff_mul[] = { -1500000, 1000000, -2000000,
+ 4000000, -2000000 };
+
+static int tsys01_read_temperature(struct iio_dev *indio_dev,
+ s32 *temperature)
+{
+ int ret, i;
+ u32 adc;
+ s64 temp = 0;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+ mutex_lock(&dev_data->lock);
+ ret = dev_data->convert_and_read(dev_data->client,
+ TSYS01_CONVERSION_START,
+ TSYS01_ADC_READ, 9000, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ adc >>= 8;
+
+ /* Temperature algorithm */
+ for (i = 4; i > 0; i--) {
+ temp += coeff_mul[i] *
+ (s64)dev_data->prom[5 - i];
+ temp *= (s64)adc;
+ temp = div64_s64(temp, 100000);
+ }
+ temp *= 10;
+ temp += coeff_mul[0] * (s64)dev_data->prom[5];
+ temp = div64_s64(temp, 100000);
+
+ *temperature = temp;
+
+ return 0;
+}
+
+static int tsys01_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ s32 temperature;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = tsys01_read_temperature(indio_dev, &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tsys01_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ }
+};
+
+static const struct iio_info tsys01_info = {
+ .read_raw = tsys01_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static bool tsys01_crc_valid(u16 *n_prom)
+{
+ u8 cnt;
+ u8 sum = 0;
+
+ for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
+ sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
+
+ return (sum == 0);
+}
+
+static int tsys01_read_prom(struct iio_dev *indio_dev)
+{
+ int i, ret;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+ char buf[7 * TSYS01_PROM_WORDS_NB + 1];
+ char *ptr = buf;
+
+ for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
+ ret = dev_data->read_prom_word(dev_data->client,
+ TSYS01_PROM_READ + (i << 1),
+ &dev_data->prom[i]);
+ if (ret)
+ return ret;
+
+ ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
+ ptr += ret;
+ }
+
+ if (!tsys01_crc_valid(dev_data->prom)) {
+ dev_err(&indio_dev->dev, "prom crc check error\n");
+ return -ENODEV;
+ }
+ *ptr = 0;
+ dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
+
+ return 0;
+}
+
+static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
+{
+ int ret;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &tsys01_info;
+ indio_dev->name = dev->driver->name;
+ indio_dev->dev.parent = dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = tsys01_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
+
+ ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
+ if (ret)
+ return ret;
+
+ ret = tsys01_read_prom(indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int tsys01_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tsys01_dev *dev_data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->reset = ms_sensors_reset;
+ dev_data->read_prom_word = ms_sensors_read_prom_word;
+ dev_data->convert_and_read = ms_sensors_convert_and_read;
+
+ i2c_set_clientdata(client, indio_dev);
+
+ return tsys01_probe(indio_dev, &client->dev);
+}
+
+static const struct i2c_device_id tsys01_id[] = {
+ {"tsys01", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tsys01_id);
+
+static struct i2c_driver tsys01_driver = {
+ .probe = tsys01_i2c_probe,
+ .id_table = tsys01_id,
+ .driver = {
+ .name = "tsys01",
+ },
+};
+
+module_i2c_driver(tsys01_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
new file mode 100644
index 000000000000..4c1fbd52ea08
--- /dev/null
+++ b/drivers/iio/temperature/tsys02d.c
@@ -0,0 +1,191 @@
+/*
+ * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define TSYS02D_RESET 0xFE
+
+static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
+/* String copy of the above const for readability purpose */
+static const char tsys02d_show_samp_freq[] = "20 40 70 140";
+
+static int tsys02d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ s32 temperature;
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = ms_sensors_ht_read_temperature(dev_data,
+ &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = tsys02d_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsys02d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+ int i, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(tsys02d_samp_freq);
+ while (i-- > 0)
+ if (val == tsys02d_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ mutex_lock(&dev_data->lock);
+ dev_data->res_index = i;
+ ret = ms_sensors_write_resolution(dev_data, i);
+ mutex_unlock(&dev_data->lock);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tsys02d_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static ssize_t tsys02_read_battery_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_battery_low(dev_data, buf);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+ tsys02_read_battery_low, NULL, 0);
+
+static struct attribute *tsys02d_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_battery_low.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group tsys02d_attribute_group = {
+ .attrs = tsys02d_attributes,
+};
+
+static const struct iio_info tsys02d_info = {
+ .read_raw = tsys02d_read_raw,
+ .write_raw = tsys02d_write_raw,
+ .attrs = &tsys02d_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int tsys02d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_ht_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+ u64 serial_number;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 0;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &tsys02d_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = tsys02d_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, TSYS02D_RESET, 15000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_read_serial(client, &serial_number);
+ if (ret)
+ return ret;
+ dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id tsys02d_id[] = {
+ {"tsys02d", 0},
+ {}
+};
+
+static struct i2c_driver tsys02d_driver = {
+ .probe = tsys02d_probe,
+ .id_table = tsys02d_id,
+ .driver = {
+ .name = "tsys02d",
+ },
+};
+
+module_i2c_driver(tsys02d_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 39d950584c9f..5d3b86a33857 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -62,8 +62,6 @@ source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/emxx_udc/Kconfig"
-source "drivers/staging/ft1000/Kconfig"
-
source "drivers/staging/speakup/Kconfig"
source "drivers/staging/ste_rmi4/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e4f33d91872b..30918edef5e3 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_SM750) += sm750fb/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
-obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
obj-$(CONFIG_MFD_NVEC) += nvec/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 68307121c9c1..42b15126aa06 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -54,7 +54,7 @@ config SW_SYNC
depends on SYNC
---help---
A sync object driver that uses a 32bit counter to coordinate
- syncrhronization. Useful when there is no hardware primitive backing
+ synchronization. Useful when there is no hardware primitive backing
the synchronization.
config SW_SYNC_USER
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 60200a3da821..3f2a3d611e4b 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -18,7 +18,8 @@
#define pr_fmt(fmt) "ashmem: " fmt
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/falloc.h>
@@ -43,7 +44,7 @@
* @unpinned_list: The list of all ashmem areas
* @file: The shmem-based backing file
* @size: The size of the mapping, in bytes
- * @prot_masks: The allowed protection bits, as vm_flags
+ * @prot_mask: The allowed protection bits, as vm_flags
*
* The lifecycle of this structure is from our parent file's open() until
* its release(). It is also protected by 'ashmem_mutex'
@@ -82,14 +83,14 @@ struct ashmem_range {
/* LRU list of unpinned pages, protected by ashmem_mutex */
static LIST_HEAD(ashmem_lru_list);
-/**
+/*
* long lru_count - The count of pages on our LRU list.
*
* This is protected by ashmem_mutex.
*/
static unsigned long lru_count;
-/**
+/*
* ashmem_mutex - protects the list of and each individual ashmem_area
*
* Lock Ordering: ashmex_mutex -> i_mutex -> i_alloc_sem
@@ -311,10 +312,9 @@ static ssize_t ashmem_read(struct file *file, char __user *buf,
* ashmem_release is called.
*/
ret = __vfs_read(asma->file, buf, len, pos);
- if (ret >= 0) {
+ if (ret >= 0)
/** Update backing file pos, since f_ops->read() doesn't */
asma->file->f_pos = *pos;
- }
return ret;
out_unlock:
@@ -618,7 +618,8 @@ static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend)
/* Case #3: We overlap from the rear, so adjust it */
if (range->pgend <= pgend) {
- range_shrink(range, range->pgstart, pgstart-1);
+ range_shrink(range, range->pgstart,
+ pgstart - 1);
continue;
}
@@ -715,7 +716,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
return -EINVAL;
- if (unlikely(((__u32) -1) - pin.offset < pin.len))
+ if (unlikely(((__u32)-1) - pin.offset < pin.len))
return -EINVAL;
if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
@@ -759,7 +760,7 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EINVAL;
if (!asma->file) {
ret = 0;
- asma->size = (size_t) arg;
+ asma->size = (size_t)arg;
}
break;
case ASHMEM_GET_SIZE:
@@ -833,16 +834,16 @@ static int __init ashmem_init(void)
int ret;
ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",
- sizeof(struct ashmem_area),
- 0, 0, NULL);
+ sizeof(struct ashmem_area),
+ 0, 0, NULL);
if (unlikely(!ashmem_area_cachep)) {
pr_err("failed to create slab cache\n");
return -ENOMEM;
}
ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",
- sizeof(struct ashmem_range),
- 0, 0, NULL);
+ sizeof(struct ashmem_range),
+ 0, 0, NULL);
if (unlikely(!ashmem_range_cachep)) {
pr_err("failed to create slab cache\n");
return -ENOMEM;
@@ -860,19 +861,4 @@ static int __init ashmem_init(void)
return 0;
}
-
-static void __exit ashmem_exit(void)
-{
- unregister_shrinker(&ashmem_shrinker);
-
- misc_deregister(&ashmem_misc);
- kmem_cache_destroy(ashmem_range_cachep);
- kmem_cache_destroy(ashmem_area_cachep);
-
- pr_info("unloaded\n");
-}
-
-module_init(ashmem_init);
-module_exit(ashmem_exit);
-
-MODULE_LICENSE("GPL");
+device_initcall(ashmem_init);
diff --git a/drivers/staging/android/ion/compat_ion.h b/drivers/staging/android/ion/compat_ion.h
index c2ad5893dfda..9da8f917670b 100644
--- a/drivers/staging/android/ion/compat_ion.h
+++ b/drivers/staging/android/ion/compat_ion.h
@@ -1,5 +1,4 @@
/*
-
* drivers/staging/android/ion/compat_ion.h
*
* Copyright (C) 2013 Google, Inc.
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 6e8d8392ca38..e237e9f3312d 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1,5 +1,5 @@
/*
-
+ *
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
@@ -213,10 +213,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
"heap->ops->map_dma should return ERR_PTR on error"))
table = ERR_PTR(-EINVAL);
if (IS_ERR(table)) {
- heap->ops->free(buffer);
- kfree(buffer);
- return ERR_CAST(table);
+ ret = -EINVAL;
+ goto err1;
}
+
buffer->sg_table = table;
if (ion_buffer_fault_user_mappings(buffer)) {
int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
@@ -226,7 +226,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
buffer->pages = vmalloc(sizeof(struct page *) * num_pages);
if (!buffer->pages) {
ret = -ENOMEM;
- goto err1;
+ goto err;
}
for_each_sg(table->sgl, sg, table->nents, i) {
@@ -235,23 +235,22 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
for (j = 0; j < sg->length / PAGE_SIZE; j++)
buffer->pages[k++] = page++;
}
-
- if (ret)
- goto err;
}
buffer->dev = dev;
buffer->size = len;
INIT_LIST_HEAD(&buffer->vmas);
mutex_init(&buffer->lock);
- /* this will set up dma addresses for the sglist -- it is not
- technically correct as per the dma api -- a specific
- device isn't really taking ownership here. However, in practice on
- our systems the only dma_address space is physical addresses.
- Additionally, we can't afford the overhead of invalidating every
- allocation via dma_map_sg. The implicit contract here is that
- memory coming from the heaps is ready for dma, ie if it has a
- cached mapping that mapping has been invalidated */
+ /*
+ * this will set up dma addresses for the sglist -- it is not
+ * technically correct as per the dma api -- a specific
+ * device isn't really taking ownership here. However, in practice on
+ * our systems the only dma_address space is physical addresses.
+ * Additionally, we can't afford the overhead of invalidating every
+ * allocation via dma_map_sg. The implicit contract here is that
+ * memory coming from the heaps is ready for dma, ie if it has a
+ * cached mapping that mapping has been invalidated
+ */
for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i)
sg_dma_address(sg) = sg_phys(sg);
mutex_lock(&dev->buffer_lock);
@@ -261,9 +260,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
err:
heap->ops->unmap_dma(heap, buffer);
- heap->ops->free(buffer);
err1:
- vfree(buffer->pages);
+ heap->ops->free(buffer);
err2:
kfree(buffer);
return ERR_PTR(ret);
@@ -753,8 +751,10 @@ struct ion_client *ion_client_create(struct ion_device *dev,
get_task_struct(current->group_leader);
task_lock(current->group_leader);
pid = task_pid_nr(current->group_leader);
- /* don't bother to store task struct for kernel threads,
- they can't be killed anyway */
+ /*
+ * don't bother to store task struct for kernel threads,
+ * they can't be killed anyway
+ */
if (current->group_leader->flags & PF_KTHREAD) {
put_task_struct(current->group_leader);
task = NULL;
@@ -1521,8 +1521,10 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
heap->dev = dev;
down_write(&dev->lock);
- /* use negative heap->id to reverse the priority -- when traversing
- the list later attempt higher id numbers first */
+ /*
+ * use negative heap->id to reverse the priority -- when traversing
+ * the list later attempt higher id numbers first
+ */
plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
debug_file = debugfs_create_file(heap->name, 0664,
@@ -1555,6 +1557,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
up_write(&dev->lock);
}
+EXPORT_SYMBOL(ion_device_add_heap);
struct ion_device *ion_device_create(long (*custom_ioctl)
(struct ion_client *client,
@@ -1604,6 +1607,7 @@ debugfs_done:
idev->clients = RB_ROOT;
return idev;
}
+EXPORT_SYMBOL(ion_device_create);
void ion_device_destroy(struct ion_device *dev)
{
@@ -1612,6 +1616,7 @@ void ion_device_destroy(struct ion_device *dev)
/* XXX need to free the heaps and clients ? */
kfree(dev);
}
+EXPORT_SYMBOL(ion_device_destroy);
void __init ion_reserve(struct ion_platform_data *data)
{
diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h
index 443db8459a9e..b860c5f579f5 100644
--- a/drivers/staging/android/ion/ion.h
+++ b/drivers/staging/android/ion/ion.h
@@ -28,10 +28,12 @@ struct ion_mapper;
struct ion_client;
struct ion_buffer;
-/* This should be removed some day when phys_addr_t's are fully
- plumbed in the kernel, and all instances of ion_phys_addr_t should
- be converted to phys_addr_t. For the time being many kernel interfaces
- do not accept phys_addr_t's that would have to */
+/*
+ * This should be removed some day when phys_addr_t's are fully
+ * plumbed in the kernel, and all instances of ion_phys_addr_t should
+ * be converted to phys_addr_t. For the time being many kernel interfaces
+ * do not accept phys_addr_t's that would have to
+ */
#define ion_phys_addr_t unsigned long
/**
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index 0b2448c32495..a3446da4fdc2 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -180,8 +180,10 @@ struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data)
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 */
+ /*
+ * get device from private heaps data, later it will be
+ * used to make the link with reserved CMA memory
+ */
cma_heap->dev = data->priv;
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 fd13d05b538a..ca15a87f6fd3 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -56,7 +56,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap,
vaddr = vmap(pages, npages, VM_MAP, pgprot);
vfree(pages);
- if (vaddr == NULL)
+ if (!vaddr)
return ERR_PTR(-ENOMEM);
return vaddr;
@@ -352,6 +352,7 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
heap->id = heap_data->id;
return heap;
}
+EXPORT_SYMBOL(ion_heap_create);
void ion_heap_destroy(struct ion_heap *heap)
{
@@ -379,3 +380,4 @@ void ion_heap_destroy(struct ion_heap *heap)
heap->type);
}
}
+EXPORT_SYMBOL(ion_heap_destroy);
diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c
index 19ad3aba499a..fd7e23e0c06e 100644
--- a/drivers/staging/android/ion/ion_page_pool.c
+++ b/drivers/staging/android/ion/ion_page_pool.c
@@ -19,7 +19,7 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/list.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <linux/swap.h>
#include "ion_priv.h"
@@ -174,10 +174,4 @@ static int __init ion_page_pool_init(void)
{
return 0;