summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accel/ivpu/ivpu_fw.c12
-rw-r--r--drivers/accel/ivpu/ivpu_gem.c89
-rw-r--r--drivers/accel/ivpu/ivpu_gem.h2
-rw-r--r--drivers/accel/ivpu/ivpu_job.c14
-rw-r--r--drivers/accel/ivpu/ivpu_jsm_msg.c9
-rw-r--r--drivers/android/binder.c248
-rw-r--r--drivers/android/binder_internal.h8
-rw-r--r--drivers/android/binderfs.c2
-rw-r--r--drivers/base/power/main.c16
-rw-r--r--drivers/base/property.c27
-rw-r--r--drivers/block/loop.c8
-rw-r--r--drivers/block/ublk_drv.c111
-rw-r--r--drivers/bluetooth/btnxpuart.c2
-rw-r--r--drivers/bluetooth/hci_qca.c14
-rw-r--r--drivers/bus/mhi/ep/ring.c16
-rw-r--r--drivers/bus/mhi/host/pci_generic.c43
-rw-r--r--drivers/bus/mhi/host/pm.c18
-rw-r--r--drivers/cdx/cdx_msi.c4
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/apm-emulation.c5
-rw-r--r--drivers/char/hpet.c3
-rw-r--r--drivers/char/misc.c28
-rw-r--r--drivers/char/xillybus/xillybus_core.c3
-rw-r--r--drivers/comedi/comedi_buf.c155
-rw-r--r--drivers/comedi/comedi_fops.c120
-rw-r--r--drivers/comedi/drivers/adl_pci9118.c4
-rw-r--r--drivers/comedi/drivers/ni_atmio.c2
-rw-r--r--drivers/comedi/drivers/ni_pcidio.c2
-rw-r--r--drivers/counter/interrupt-cnt.c17
-rw-r--r--drivers/counter/microchip-tcb-capture.c25
-rw-r--r--drivers/counter/stm32-timer-cnt.c7
-rw-r--r--drivers/crypto/Kconfig1
-rw-r--r--drivers/eisa/Makefile10
-rw-r--r--drivers/eisa/eisa-bus.c2
-rw-r--r--drivers/firmware/sysfb.c26
-rw-r--r--drivers/fpga/tests/fpga-mgr-test.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/Kconfig2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c32
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c14
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c75
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c28
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c146
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c31
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c76
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c182
-rw-r--r--drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c55
-rw-r--r--drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c59
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c21
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c19
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c81
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c180
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/Kconfig2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_events.c1
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c23
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.h11
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c34
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c26
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c24
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c4
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h34
-rw-r--r--drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h2
-rw-r--r--drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c3
-rw-r--r--drivers/gpu/drm/amd/include/amd_shared.h10
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h26
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h16
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h6
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h16
-rw-r--r--drivers/gpu/drm/amd/include/atombios.h4
-rw-r--r--drivers/gpu/drm/amd/include/atomfirmware.h2
-rw-r--r--drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h1
-rw-r--r--drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h74
-rw-r--r--drivers/gpu/drm/amd/include/kgd_pp_interface.h24
-rw-r--r--drivers/gpu/drm/amd/pm/amdgpu_dpm.c54
-rw-r--r--drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h3
-rw-r--r--drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c2
-rw-r--r--drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c14
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h4
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c71
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c158
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h6
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c67
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h26
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c20
-rw-r--r--drivers/gpu/drm/display/drm_hdmi_audio_helper.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.c27
-rw-r--r--drivers/gpu/drm/i915/display/intel_audio.h1
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c3
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr_regs.h4
-rw-r--r--drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c16
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig2
-rw-r--r--drivers/gpu/drm/panel/panel-novatek-nt37801.c4
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c5
-rw-r--r--drivers/gpu/drm/radeon/atombios.h2
-rw-r--r--drivers/gpu/drm/radeon/kv_dpm.c2
-rw-r--r--drivers/gpu/drm/scheduler/sched_entity.c1
-rw-r--r--drivers/gpu/drm/xe/Kconfig3
-rw-r--r--drivers/gpu/drm/xe/regs/xe_mchbar_regs.h10
-rw-r--r--drivers/gpu/drm/xe/regs/xe_pcode_regs.h4
-rw-r--r--drivers/gpu/drm/xe/xe_bo.c48
-rw-r--r--drivers/gpu/drm/xe/xe_device_sysfs.c2
-rw-r--r--drivers/gpu/drm/xe/xe_device_types.h4
-rw-r--r--drivers/gpu/drm/xe/xe_exec_queue.c15
-rw-r--r--drivers/gpu/drm/xe/xe_gpu_scheduler.h10
-rw-r--r--drivers/gpu/drm/xe/xe_gt_freq.c5
-rw-r--r--drivers/gpu/drm/xe/xe_guc_submit.c11
-rw-r--r--drivers/gpu/drm/xe/xe_hwmon.c384
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c23
-rw-r--r--drivers/gpu/drm/xe/xe_pci.c5
-rw-r--r--drivers/gpu/drm/xe/xe_pcode.c11
-rw-r--r--drivers/gpu/drm/xe/xe_pcode.h3
-rw-r--r--drivers/gpu/drm/xe/xe_pcode_api.h7
-rw-r--r--drivers/gpu/drm/xe/xe_pxp.c8
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c27
-rw-r--r--drivers/gpu/drm/xe/xe_vm.h69
-rw-r--r--drivers/gpu/drm/xe/xe_vm_types.h8
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/sbrmi.c357
-rw-r--r--drivers/hwtracing/coresight/Kconfig9
-rw-r--r--drivers/hwtracing/coresight/Makefile3
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.c39
-rw-r--r--drivers/hwtracing/coresight/coresight-catu.h1
-rw-r--r--drivers/hwtracing/coresight/coresight-config.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c131
-rw-r--r--drivers/hwtracing/coresight/coresight-cpu-debug.c3
-rw-r--r--drivers/hwtracing/coresight/coresight-cti-core.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-cti.h3
-rw-r--r--drivers/hwtracing/coresight/coresight-etb10.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c84
-rw-r--r--drivers/hwtracing/coresight/coresight-etm.h6
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-core.c28
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-sysfs.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c158
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-sysfs.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c4
-rw-r--r--drivers/hwtracing/coresight/coresight-kunit-tests.c74
-rw-r--r--drivers/hwtracing/coresight/coresight-platform.c26
-rw-r--r--drivers/hwtracing/coresight/coresight-priv.h22
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c6
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c8
-rw-r--r--drivers/hwtracing/coresight/coresight-syscfg-configfs.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-syscfg.c51
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c11
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etf.c20
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c26
-rw-r--r--drivers/hwtracing/coresight/coresight-tpiu.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-trbe.c18
-rw-r--r--drivers/iio/accel/adxl345.h4
-rw-r--r--drivers/iio/accel/adxl345_core.c600
-rw-r--r--drivers/iio/accel/adxl345_i2c.c2
-rw-r--r--drivers/iio/accel/adxl345_spi.c2
-rw-r--r--drivers/iio/accel/adxl355_core.c4
-rw-r--r--drivers/iio/accel/adxl367_i2c.c2
-rw-r--r--drivers/iio/accel/adxl367_spi.c4
-rw-r--r--drivers/iio/accel/adxl372_i2c.c2
-rw-r--r--drivers/iio/accel/adxl372_spi.c2
-rw-r--r--drivers/iio/accel/bma180.c2
-rw-r--r--drivers/iio/accel/bma220_spi.c8
-rw-r--r--drivers/iio/accel/bma400_core.c5
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c6
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c4
-rw-r--r--drivers/iio/accel/bmi088-accel-i2c.c4
-rw-r--r--drivers/iio/accel/bmi088-accel-spi.c4
-rw-r--r--drivers/iio/accel/da280.c4
-rw-r--r--drivers/iio/accel/da311.c2
-rw-r--r--drivers/iio/accel/dmard10.c2
-rw-r--r--drivers/iio/accel/fxls8962af-core.c19
-rw-r--r--drivers/iio/accel/fxls8962af-i2c.c4
-rw-r--r--drivers/iio/accel/fxls8962af-spi.c4
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c4
-rw-r--r--drivers/iio/accel/kxcjk-1013.c91
-rw-r--r--drivers/iio/accel/kxsd9-i2c.c2
-rw-r--r--drivers/iio/accel/kxsd9-spi.c2
-rw-r--r--drivers/iio/accel/kxsd9.c7
-rw-r--r--drivers/iio/accel/mma7455_core.c5
-rw-r--r--drivers/iio/accel/mma7660.c4
-rw-r--r--drivers/iio/accel/mma8452.c5
-rw-r--r--drivers/iio/accel/mma9551.c4
-rw-r--r--drivers/iio/accel/mma9553.c6
-rw-r--r--drivers/iio/accel/msa311.c4
-rw-r--r--drivers/iio/accel/mxc4005.c8
-rw-r--r--drivers/iio/accel/sca3000.c2
-rw-r--r--drivers/iio/accel/sca3300.c23
-rw-r--r--drivers/iio/accel/st_accel_i2c.c6
-rw-r--r--drivers/iio/accel/st_accel_spi.c4
-rw-r--r--drivers/iio/accel/stk8312.c6
-rw-r--r--drivers/iio/accel/stk8ba50.c8
-rw-r--r--drivers/iio/adc/Kconfig160
-rw-r--r--drivers/iio/adc/Makefile4
-rw-r--r--drivers/iio/adc/ad4000.c387
-rw-r--r--drivers/iio/adc/ad4030.c68
-rw-r--r--drivers/iio/adc/ad4130.c10
-rw-r--r--drivers/iio/adc/ad4695.c19
-rw-r--r--drivers/iio/adc/ad4851.c14
-rw-r--r--drivers/iio/adc/ad7091r-base.c9
-rw-r--r--drivers/iio/adc/ad7124.c210
-rw-r--r--drivers/iio/adc/ad7173.c15
-rw-r--r--drivers/iio/adc/ad7266.c7
-rw-r--r--drivers/iio/adc/ad7280a.c2
-rw-r--r--drivers/iio/adc/ad7298.c4
-rw-r--r--drivers/iio/adc/ad7380.c57
-rw-r--r--drivers/iio/adc/ad7476.c4
-rw-r--r--drivers/iio/adc/ad7606.c375
-rw-r--r--drivers/iio/adc/ad7606.h196
-rw-r--r--drivers/iio/adc/ad7606_par.c37
-rw-r--r--drivers/iio/adc/ad7606_spi.c296
-rw-r--r--drivers/iio/adc/ad7768-1.c247
-rw-r--r--drivers/iio/adc/ad7779.c3
-rw-r--r--drivers/iio/adc/ad7791.c2
-rw-r--r--drivers/iio/adc/ad7923.c4
-rw-r--r--drivers/iio/adc/ad7944.c13
-rw-r--r--drivers/iio/adc/ad799x.c2
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c4
-rw-r--r--drivers/iio/adc/adi-axi-adc.c2
-rw-r--r--drivers/iio/adc/at91-sama5d2_adc.c13
-rw-r--r--drivers/iio/adc/axp20x_adc.c8
-rw-r--r--drivers/iio/adc/axp288_adc.c4
-rw-r--r--drivers/iio/adc/cpcap-adc.c2
-rw-r--r--drivers/iio/adc/da9150-gpadc.c2
-rw-r--r--drivers/iio/adc/dln2-adc.c4
-rw-r--r--drivers/iio/adc/envelope-detector.c4
-rw-r--r--drivers/iio/adc/fsl-imx25-gcq.c2
-rw-r--r--drivers/iio/adc/hi8435.c2
-rw-r--r--drivers/iio/adc/hx711.c11
-rw-r--r--drivers/iio/adc/imx7d_adc.c2
-rw-r--r--drivers/iio/adc/imx8qxp-adc.c2
-rw-r--r--drivers/iio/adc/imx93_adc.c2
-rw-r--r--drivers/iio/adc/ina2xx-adc.c2
-rw-r--r--drivers/iio/adc/industrialio-adc.c82
-rw-r--r--drivers/iio/adc/intel_mrfld_adc.c4
-rw-r--r--drivers/iio/adc/lpc18xx_adc.c2
-rw-r--r--drivers/iio/adc/ltc2471.c2
-rw-r--r--drivers/iio/adc/max1118.c4
-rw-r--r--drivers/iio/adc/max11410.c4
-rw-r--r--drivers/iio/adc/max1363.c8
-rw-r--r--drivers/iio/adc/max77541-adc.c2
-rw-r--r--drivers/iio/adc/mcp3911.c62
-rw-r--r--drivers/iio/adc/meson_saradc.c36
-rw-r--r--drivers/iio/adc/mt6359-auxadc.c2
-rw-r--r--drivers/iio/adc/mt6360-adc.c4
-rw-r--r--drivers/iio/adc/mt6370-adc.c2
-rw-r--r--drivers/iio/adc/mxs-lradc-adc.c17
-rw-r--r--drivers/iio/adc/nct7201.c501
-rw-r--r--drivers/iio/adc/npcm_adc.c2
-rw-r--r--drivers/iio/adc/pac1921.c7
-rw-r--r--drivers/iio/adc/pac1934.c2
-rw-r--r--drivers/iio/adc/palmas_gpadc.c2
-rw-r--r--drivers/iio/adc/rcar-gyroadc.c11
-rw-r--r--drivers/iio/adc/rn5t618-adc.c2
-rw-r--r--drivers/iio/adc/rockchip_saradc.c3
-rw-r--r--drivers/iio/adc/rohm-bd79124.c1146
-rw-r--r--drivers/iio/adc/rtq6056.c3
-rw-r--r--drivers/iio/adc/rzg2l_adc.c41
-rw-r--r--drivers/iio/adc/spear_adc.c2
-rw-r--r--drivers/iio/adc/stm32-adc-core.h17
-rw-r--r--drivers/iio/adc/stm32-adc.c158
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c8
-rw-r--r--drivers/iio/adc/sun20i-gpadc-iio.c41
-rw-r--r--drivers/iio/adc/sun4i-gpadc-iio.c6
-rw-r--r--drivers/iio/adc/ti-adc081c.c4
-rw-r--r--drivers/iio/adc/ti-adc0832.c4
-rw-r--r--drivers/iio/adc/ti-adc084s021.c4
-rw-r--r--drivers/iio/adc/ti-adc12138.c4
-rw-r--r--drivers/iio/adc/ti-adc128s052.c98
-rw-r--r--drivers/iio/adc/ti-ads1015.c172
-rw-r--r--drivers/iio/adc/ti-ads1100.c44
-rw-r--r--drivers/iio/adc/ti-ads1119.c4
-rw-r--r--drivers/iio/adc/ti-ads124s08.c4
-rw-r--r--drivers/iio/adc/ti-ads131e08.c4
-rw-r--r--drivers/iio/adc/ti-ads7950.c17
-rw-r--r--drivers/iio/adc/ti-ads8688.c4
-rw-r--r--drivers/iio/adc/ti-lmp92064.c6
-rw-r--r--drivers/iio/adc/ti-tlc4541.c4
-rw-r--r--drivers/iio/adc/ti-tsc2046.c6
-rw-r--r--drivers/iio/adc/twl6030-gpadc.c2
-rw-r--r--drivers/iio/adc/vf610_adc.c46
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c2
-rw-r--r--drivers/iio/addac/ad74115.c25
-rw-r--r--drivers/iio/addac/ad74413r.c37
-rw-r--r--drivers/iio/afe/iio-rescale.c2
-rw-r--r--drivers/iio/amplifiers/ad8366.c2
-rw-r--r--drivers/iio/amplifiers/ada4250.c4
-rw-r--r--drivers/iio/amplifiers/hmc425a.c5
-rw-r--r--drivers/iio/cdc/ad7150.c4
-rw-r--r--drivers/iio/cdc/ad7746.c4
-rw-r--r--drivers/iio/chemical/Kconfig20
-rw-r--r--drivers/iio/chemical/Makefile2
-rw-r--r--drivers/iio/chemical/ags02ma.c4
-rw-r--r--drivers/iio/chemical/atlas-ezo-sensor.c4
-rw-r--r--drivers/iio/chemical/atlas-sensor.c14
-rw-r--r--drivers/iio/chemical/bme680_core.c4
-rw-r--r--drivers/iio/chemical/bme680_i2c.c4
-rw-r--r--drivers/iio/chemical/bme680_spi.c12
-rw-r--r--drivers/iio/chemical/ccs811.c83
-rw-r--r--drivers/iio/chemical/ens160_core.c4
-rw-r--r--drivers/iio/chemical/mhz19b.c316
-rw-r--r--drivers/iio/chemical/pms7003.c4
-rw-r--r--drivers/iio/chemical/scd30_core.c3
-rw-r--r--drivers/iio/chemical/scd4x.c10
-rw-r--r--drivers/iio/chemical/sen0322.c161
-rw-r--r--drivers/iio/chemical/sps30.c4
-rw-r--r--drivers/iio/chemical/sunrise_co2.c4
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c2
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c2
-rw-r--r--drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c78
-rw-r--r--drivers/iio/common/scmi_sensors/scmi_iio.c11
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_dev.c2
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_spi.c2
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c7
-rw-r--r--drivers/iio/dac/Kconfig11
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad3530r.c517
-rw-r--r--drivers/iio/dac/ad3552r-common.c4
-rw-r--r--drivers/iio/dac/ad3552r-hs.c182
-rw-r--r--drivers/iio/dac/ad3552r.h1
-rw-r--r--drivers/iio/dac/ad5064.c8
-rw-r--r--drivers/iio/dac/ad5360.c2
-rw-r--r--drivers/iio/dac/ad5380.c2
-rw-r--r--drivers/iio/dac/ad5446.c6
-rw-r--r--drivers/iio/dac/ad5449.c2
-rw-r--r--drivers/iio/dac/ad5504.c4
-rw-r--r--drivers/iio/dac/ad5592r-base.c156
-rw-r--r--drivers/iio/dac/ad5592r.c6
-rw-r--r--drivers/iio/dac/ad5593r.c6
-rw-r--r--drivers/iio/dac/ad5624r_spi.c4
-rw-r--r--drivers/iio/dac/ad5686-spi.c2
-rw-r--r--drivers/iio/dac/ad5686.c2
-rw-r--r--drivers/iio/dac/ad5696-i2c.c4
-rw-r--r--drivers/iio/dac/ad5755.c4
-rw-r--r--drivers/iio/dac/ad5758.c2
-rw-r--r--drivers/iio/dac/ad5761.c4
-rw-r--r--drivers/iio/dac/ad5766.c8
-rw-r--r--drivers/iio/dac/ad5770r.c4
-rw-r--r--drivers/iio/dac/ad5791.c4
-rw-r--r--drivers/iio/dac/ad7293.c17
-rw-r--r--drivers/iio/dac/ad7303.c6
-rw-r--r--drivers/iio/dac/ad8801.c2
-rw-r--r--drivers/iio/dac/ad9739a.c4
-rw-r--r--drivers/iio/dac/adi-axi-dac.c66
-rw-r--r--drivers/iio/dac/dpot-dac.c2
-rw-r--r--drivers/iio/dac/ds4424.c2
-rw-r--r--drivers/iio/dac/lpc18xx_dac.c2
-rw-r--r--drivers/iio/dac/ltc1660.c4
-rw-r--r--drivers/iio/dac/ltc2632.c6
-rw-r--r--drivers/iio/dac/ltc2688.c14
-rw-r--r--drivers/iio/dac/max5522.c4
-rw-r--r--drivers/iio/dac/max5821.c2
-rw-r--r--drivers/iio/dac/mcp4725.c4
-rw-r--r--drivers/iio/dac/mcp4728.c6
-rw-r--r--drivers/iio/dac/mcp4821.c4
-rw-r--r--drivers/iio/dac/mcp4922.c2
-rw-r--r--drivers/iio/dac/rohm-bd79703.c116
-rw-r--r--drivers/iio/dac/stm32-dac-core.c2
-rw-r--r--drivers/iio/dac/stm32-dac.c4
-rw-r--r--drivers/iio/dac/ti-dac082s085.c2
-rw-r--r--drivers/iio/dac/ti-dac5571.c6
-rw-r--r--drivers/iio/dac/ti-dac7311.c2
-rw-r--r--drivers/iio/dac/ti-dac7612.c4
-rw-r--r--drivers/iio/dac/vf610_dac.c4
-rw-r--r--drivers/iio/dummy/iio_simple_dummy_buffer.c27
-rw-r--r--drivers/iio/filter/admv8818.c230
-rw-r--r--drivers/iio/frequency/ad9523.c2
-rw-r--r--drivers/iio/frequency/adf4350.c6
-rw-r--r--drivers/iio/frequency/adf4371.c6
-rw-r--r--drivers/iio/frequency/adf4377.c4
-rw-r--r--drivers/iio/frequency/admv1013.c8
-rw-r--r--drivers/iio/frequency/admv1014.c4
-rw-r--r--drivers/iio/frequency/adrf6780.c4
-rw-r--r--drivers/iio/gyro/adis16080.c2
-rw-r--r--drivers/iio/gyro/adis16260.c2
-rw-r--r--drivers/iio/gyro/adxrs290.c14
-rw-r--r--drivers/iio/gyro/adxrs450.c7
-rw-r--r--drivers/iio/gyro/bmg160_i2c.c4
-rw-r--r--drivers/iio/gyro/bmg160_spi.c2
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c2
-rw-r--r--drivers/iio/gyro/mpu3050-core.c2
-rw-r--r--drivers/iio/gyro/mpu3050-i2c.c4
-rw-r--r--drivers/iio/gyro/st_gyro_i2c.c4
-rw-r--r--drivers/iio/gyro/st_gyro_spi.c4
-rw-r--r--drivers/iio/health/afe4403.c4
-rw-r--r--drivers/iio/health/afe4404.c4
-rw-r--r--drivers/iio/health/max30100.c2
-rw-r--r--drivers/iio/health/max30102.c6
-rw-r--r--drivers/iio/humidity/am2315.c2
-rw-r--r--drivers/iio/humidity/hdc100x.c68
-rw-r--r--drivers/iio/humidity/hdc2010.c14
-rw-r--r--drivers/iio/humidity/hid-sensor-humidity.c2
-rw-r--r--drivers/iio/humidity/hts221_core.c91
-rw-r--r--drivers/iio/humidity/hts221_i2c.c6
-rw-r--r--drivers/iio/humidity/hts221_spi.c4
-rw-r--r--drivers/iio/humidity/htu21.c4
-rw-r--r--drivers/iio/imu/adis.c9
-rw-r--r--drivers/iio/imu/adis16400.c2
-rw-r--r--drivers/iio/imu/adis16460.c4
-rw-r--r--drivers/iio/imu/adis16475.c2
-rw-r--r--drivers/iio/imu/adis16480.c2
-rw-r--r--drivers/iio/imu/adis_buffer.c3
-rw-r--r--drivers/iio/imu/bmi160/bmi160_i2c.c6
-rw-r--r--drivers/iio/imu/bmi160/bmi160_spi.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600.h2
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c23
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_core.c14
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c23
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c5
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c5
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c15
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c2
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c14
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c4
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c4
-rw-r--r--drivers/iio/imu/kmx61.c2
-rw-r--r--drivers/iio/imu/smi240.c7
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c16
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c6
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c2
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c73
-rw-r--r--drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c4
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c6
-rw-r--r--drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c4
-rw-r--r--drivers/iio/industrialio-backend.c28
-rw-r--r--drivers/iio/industrialio-core.c41
-rw-r--r--drivers/iio/light/acpi-als.c2
-rw-r--r--drivers/iio/light/adux1020.c2
-rw-r--r--drivers/iio/light/al3000a.c11
-rw-r--r--drivers/iio/light/al3010.c105
-rw-r--r--drivers/iio/light/al3320a.c116
-rw-r--r--drivers/iio/light/apds9306.c7
-rw-r--r--drivers/iio/light/apds9960.c2
-rw-r--r--drivers/iio/light/as73211.c42
-rw-r--r--drivers/iio/light/bh1750.c24
-rw-r--r--drivers/iio/light/bh1780.c2
-rw-r--r--drivers/iio/light/cm3232.c4
-rw-r--r--drivers/iio/light/cm3323.c4
-rw-r--r--drivers/iio/light/cm3605.c2
-rw-r--r--drivers/iio/light/cros_ec_light_prox.c2
-rw-r--r--drivers/iio/light/gp2ap002.c2
-rw-r--r--drivers/iio/light/gp2ap020a00f.c7
-rw-r--r--drivers/iio/light/hid-sensor-als.c2
-rw-r--r--drivers/iio/light/hid-sensor-prox.c5
-rw-r--r--drivers/iio/light/isl29018.c4
-rw-r--r--drivers/iio/light/isl29028.c4
-rw-r--r--drivers/iio/light/isl29125.c7
-rw-r--r--drivers/iio/light/jsa1212.c2
-rw-r--r--drivers/iio/light/ltr390.c4
-rw-r--r--drivers/iio/light/ltr501.c170
-rw-r--r--drivers/iio/light/ltrf216a.c4
-rw-r--r--drivers/iio/light/opt4001.c2
-rw-r--r--drivers/iio/light/opt4060.c5
-rw-r--r--drivers/iio/light/pa12203001.c4
-rw-r--r--drivers/iio/light/rohm-bu27034.c14
-rw-r--r--drivers/iio/light/rpr0521.c63
-rw-r--r--drivers/iio/light/si1145.c25
-rw-r--r--drivers/iio/light/st_uvis25_core.c7
-rw-r--r--drivers/iio/light/st_uvis25_i2c.c4
-rw-r--r--drivers/iio/light/st_uvis25_spi.c4
-rw-r--r--drivers/iio/light/stk3310.c8
-rw-r--r--drivers/iio/light/tcs3414.c9
-rw-r--r--drivers/iio/light/tcs3472.c9
-rw-r--r--drivers/iio/light/tsl2563.c4
-rw-r--r--drivers/iio/light/tsl2583.c4
-rw-r--r--drivers/iio/light/tsl2591.c2
-rw-r--r--drivers/iio/light/tsl2772.c4
-rw-r--r--drivers/iio/light/us5182d.c6
-rw-r--r--drivers/iio/light/vcnl4000.c82
-rw-r--r--drivers/iio/light/vcnl4035.c42
-rw-r--r--drivers/iio/light/veml6040.c4
-rw-r--r--drivers/iio/light/veml6075.c2
-rw-r--r--drivers/iio/light/vl6180.c2
-rw-r--r--drivers/iio/light/zopt2201.c42
-rw-r--r--drivers/iio/magnetometer/af8133j.c3
-rw-r--r--drivers/iio/magnetometer/ak8974.c10
-rw-r--r--drivers/iio/magnetometer/ak8975.c8
-rw-r--r--drivers/iio/magnetometer/als31300.c7
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c4
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_i2c.c2
-rw-r--r--drivers/iio/magnetometer/bmc150_magn_spi.c2
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c2
-rw-r--r--drivers/iio/magnetometer/hmc5843.h2
-rw-r--r--drivers/iio/magnetometer/hmc5843_core.c4
-rw-r--r--drivers/iio/magnetometer/hmc5843_i2c.c2
-rw-r--r--drivers/iio/magnetometer/hmc5843_spi.c1
-rw-r--r--drivers/iio/magnetometer/mag3110.c165
-rw-r--r--drivers/iio/magnetometer/mmc35240.c4
-rw-r--r--drivers/iio/magnetometer/rm3100-core.c11
-rw-r--r--drivers/iio/magnetometer/rm3100-spi.c1
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c4
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c4
-rw-r--r--drivers/iio/magnetometer/tmag5273.c4
-rw-r--r--drivers/iio/magnetometer/yamaha-yas530.c8
-rw-r--r--drivers/iio/multiplexer/iio-mux.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c2
-rw-r--r--drivers/iio/orientation/hid-sensor-rotation.c4
-rw-r--r--drivers/iio/position/hid-sensor-custom-intel-hinge.c2
-rw-r--r--drivers/iio/potentiometer/ad5272.c4
-rw-r--r--drivers/iio/potentiometer/ds1803.c4
-rw-r--r--drivers/iio/potentiometer/max5432.c2
-rw-r--r--drivers/iio/potentiometer/max5487.c2
-rw-r--r--drivers/iio/potentiometer/mcp4018.c4
-rw-r--r--drivers/iio/potentiometer/mcp41010.c4
-rw-r--r--drivers/iio/potentiometer/mcp4131.c4
-rw-r--r--drivers/iio/potentiometer/mcp4531.c4
-rw-r--r--drivers/iio/potentiometer/tpl0102.c2
-rw-r--r--drivers/iio/potentiostat/lmp91000.c4
-rw-r--r--drivers/iio/pressure/abp060mg.c2
-rw-r--r--drivers/iio/pressure/bmp280-core.c110
-rw-r--r--drivers/iio/pressure/bmp280-i2c.c4
-rw-r--r--drivers/iio/pressure/bmp280-spi.c10
-rw-r--r--drivers/iio/pressure/bmp280.h8
-rw-r--r--drivers/iio/pressure/cros_ec_baro.c2
-rw-r--r--drivers/iio/pressure/dlhl60d.c11
-rw-r--r--drivers/iio/pressure/dps310.c4
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c7
-rw-r--r--drivers/iio/pressure/hp03.c2
-rw-r--r--drivers/iio/pressure/hp206c.c4
-rw-r--r--drivers/iio/pressure/hsc030pa.c4
-rw-r--r--drivers/iio/pressure/hsc030pa_i2c.c4
-rw-r--r--drivers/iio/pressure/hsc030pa_spi.c4
-rw-r--r--drivers/iio/pressure/icp10100.c15
-rw-r--r--drivers/iio/pressure/mpl115_spi.c2
-rw-r--r--drivers/iio/pressure/mpl3115.c101
-rw-r--r--drivers/iio/pressure/mprls0025pa_i2c.c4
-rw-r--r--drivers/iio/pressure/mprls0025pa_spi.c4
-rw-r--r--drivers/iio/pressure/ms5611_core.c8
-rw-r--r--drivers/iio/pressure/ms5611_spi.c1
-rw-r--r--drivers/iio/pressure/ms5637.c4
-rw-r--r--drivers/iio/pressure/rohm-bm1390.c14
-rw-r--r--drivers/iio/pressure/st_pressure_i2c.c6
-rw-r--r--drivers/iio/pressure/st_pressure_spi.c4
-rw-r--r--drivers/iio/pressure/zpa2326.c21
-rw-r--r--drivers/iio/pressure/zpa2326_spi.c3
-rw-r--r--drivers/iio/proximity/as3935.c8
-rw-r--r--drivers/iio/proximity/cros_ec_mkbp_proximity.c17
-rw-r--r--drivers/iio/proximity/hx9023s.c15
-rw-r--r--drivers/iio/proximity/irsd200.c14
-rw-r--r--drivers/iio/proximity/isl29501.c4
-rw-r--r--drivers/iio/proximity/mb1232.c6
-rw-r--r--drivers/iio/proximity/ping.c2
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c9
-rw-r--r--drivers/iio/proximity/srf04.c2
-rw-r--r--drivers/iio/proximity/srf08.c6
-rw-r--r--drivers/iio/proximity/sx9310.c6
-rw-r--r--drivers/iio/proximity/sx9324.c2
-rw-r--r--drivers/iio/proximity/sx9500.c11
-rw-r--r--drivers/iio/proximity/sx_common.c4
-rw-r--r--drivers/iio/proximity/vcnl3020.c2
-rw-r--r--drivers/iio/proximity/vl53l0x-i2c.c4
-rw-r--r--drivers/iio/resolver/ad2s1200.c2
-rw-r--r--drivers/iio/resolver/ad2s1210.c5
-rw-r--r--drivers/iio/resolver/ad2s90.c4
-rw-r--r--drivers/iio/temperature/hid-sensor-temperature.c7
-rw-r--r--drivers/iio/temperature/ltc2983.c4
-rw-r--r--drivers/iio/temperature/maxim_thermocouple.c37
-rw-r--r--drivers/iio/temperature/mcp9600.c4
-rw-r--r--drivers/iio/temperature/tmp006.c4
-rw-r--r--drivers/iio/temperature/tmp007.c2
-rw-r--r--drivers/iio/temperature/tsys01.c4
-rw-r--r--drivers/iio/temperature/tsys02d.c2
-rw-r--r--drivers/iio/test/iio-test-format.c2
-rw-r--r--drivers/iio/test/iio-test-gts.c2
-rw-r--r--drivers/iio/test/iio-test-rescale.c2
-rw-r--r--drivers/iio/trigger/stm32-lptimer-trigger.c77
-rw-r--r--drivers/iio/trigger/stm32-timer-trigger.c4
-rw-r--r--drivers/interconnect/core.c82
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.c17
-rw-r--r--drivers/interconnect/qcom/icc-rpmh.h5
-rw-r--r--drivers/interconnect/qcom/osm-l3.c38
-rw-r--r--drivers/interconnect/qcom/sa8775p.c952
-rw-r--r--drivers/interconnect/qcom/sm8650.c344
-rw-r--r--drivers/interconnect/qcom/sm8650.h1
-rw-r--r--drivers/md/bcache/btree.c2
-rw-r--r--drivers/md/bcache/super.c55
-rw-r--r--drivers/md/dm-raid.c6
-rw-r--r--drivers/md/md-bitmap.c35
-rw-r--r--drivers/md/md-bitmap.h17
-rw-r--r--drivers/md/md.c14
-rw-r--r--drivers/md/raid1-10.c10
-rw-r--r--drivers/md/raid1.c19
-rw-r--r--drivers/md/raid10.c11
-rw-r--r--drivers/misc/Kconfig2
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/amd-sbi/Kconfig18
-rw-r--r--drivers/misc/amd-sbi/Makefile4
-rw-r--r--drivers/misc/amd-sbi/rmi-core.c474
-rw-r--r--drivers/misc/amd-sbi/rmi-core.h74
-rw-r--r--drivers/misc/amd-sbi/rmi-hwmon.c120
-rw-r--r--drivers/misc/amd-sbi/rmi-i2c.c133
-rw-r--r--drivers/misc/bcm-vk/bcm_vk.h1
-rw-r--r--drivers/misc/cardreader/alcor_pci.c13
-rw-r--r--drivers/misc/cardreader/rts5264.c17
-rw-r--r--drivers/misc/cardreader/rtsx_pcr.c46
-rw-r--r--drivers/misc/cardreader/rtsx_pcr.h2
-rw-r--r--drivers/misc/echo/Kconfig9
-rw-r--r--drivers/misc/echo/Makefile2
-rw-r--r--drivers/misc/echo/echo.c589
-rw-r--r--drivers/misc/echo/echo.h175
-rw-r--r--drivers/misc/echo/fir.h154
-rw-r--r--drivers/misc/echo/oslec.h81
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c75
-rw-r--r--drivers/misc/fastrpc.c16
-rw-r--r--drivers/misc/lis3lv02d/Kconfig4
-rw-r--r--drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c99
-rw-r--r--drivers/misc/mei/interrupt.c2
-rw-r--r--drivers/misc/mei/vsc-tp.c4
-rw-r--r--drivers/misc/tps6594-pfsm.c3
-rw-r--r--drivers/misc/vmw_vmci/vmci_host.c11
-rw-r--r--drivers/mux/adg792a.c2
-rw-r--r--drivers/mux/adgs1408.c4
-rw-r--r--drivers/mux/gpio.c5
-rw-r--r--drivers/mux/mmio.c15
-rw-r--r--drivers/net/can/kvaser_pciefd.c3
-rw-r--r--drivers/net/dsa/b53/b53_common.c58
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c2
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.h1
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe.c54
-rw-r--r--drivers/net/ethernet/airoha/airoha_regs.h10
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c2
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx_dqo.c3
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_main.c2
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h1
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c29
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c289
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c47
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c181
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c18
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c9
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c45
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.h8
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.h1
-rw-r--r--drivers/net/ethernet/mediatek/mtk_star_emac.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c2
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.c1
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_main.h1
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c1
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_est.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c2
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_stats.c8
-rw-r--r--drivers/net/hyperv/netvsc_bpf.c2
-rw-r--r--drivers/net/hyperv/netvsc_drv.c4
-rw-r--r--drivers/net/ovpn/io.c8
-rw-r--r--drivers/net/ovpn/netlink.c16
-rw-r--r--drivers/net/ovpn/peer.c4
-rw-r--r--drivers/net/ovpn/socket.c68
-rw-r--r--drivers/net/ovpn/socket.h4
-rw-r--r--drivers/net/ovpn/tcp.c73
-rw-r--r--drivers/net/ovpn/tcp.h3
-rw-r--r--drivers/net/ovpn/udp.c46
-rw-r--r--drivers/net/ovpn/udp.h4
-rw-r--r--drivers/net/usb/aqc111.c8
-rw-r--r--drivers/net/usb/ch9200.c7
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c26
-rw-r--r--drivers/net/wireguard/device.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/fw.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/mld.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c2
-rw-r--r--drivers/net/wwan/mhi_wwan_mbim.c9
-rw-r--r--drivers/net/wwan/t7xx/t7xx_netdev.c11
-rw-r--r--drivers/nvme/common/auth.c6
-rw-r--r--drivers/nvme/host/Kconfig2
-rw-r--r--drivers/nvme/host/constants.c2
-rw-r--r--drivers/nvme/host/core.c3
-rw-r--r--drivers/nvme/host/fabrics.c2
-rw-r--r--drivers/nvme/host/fabrics.h6
-rw-r--r--drivers/nvme/host/fc.c4
-rw-r--r--drivers/nvme/host/ioctl.c18
-rw-r--r--drivers/nvme/host/multipath.c2
-rw-r--r--drivers/nvme/host/nvme.h2
-rw-r--r--drivers/nvme/host/pci.c4
-rw-r--r--drivers/nvme/host/pr.c2
-rw-r--r--drivers/nvme/host/rdma.c4
-rw-r--r--drivers/nvme/host/tcp.c24
-rw-r--r--drivers/nvme/target/admin-cmd.c2
-rw-r--r--drivers/nvme/target/core.c11
-rw-r--r--drivers/nvme/target/fc.c2
-rw-r--r--drivers/nvme/target/io-cmd-bdev.c11
-rw-r--r--drivers/nvme/target/passthru.c2
-rw-r--r--drivers/nvmem/Kconfig14
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/apple-spmi-nvmem.c62
-rw-r--r--drivers/nvmem/core.c68
-rw-r--r--drivers/nvmem/zynqmp_nvmem.c1
-rw-r--r--drivers/pwm/pwm-axi-pwmgen.c23
-rw-r--r--drivers/regulator/max14577-regulator.c5
-rw-r--r--drivers/rtc/Kconfig25
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/class.c2
-rw-r--r--drivers/rtc/interface.c2
-rw-r--r--drivers/rtc/lib.c24
-rw-r--r--drivers/rtc/lib_test.c27
-rw-r--r--drivers/rtc/rtc-at91rm9200.c1
-rw-r--r--drivers/rtc/rtc-cpcap.c1
-rw-r--r--drivers/rtc/rtc-cv1800.c218
-rw-r--r--drivers/rtc/rtc-da9063.c31
-rw-r--r--drivers/rtc/rtc-jz4740.c1
-rw-r--r--drivers/rtc/rtc-loongson.c8
-rw-r--r--drivers/rtc/rtc-m41t80.c78
-rw-r--r--drivers/rtc/rtc-mt6397.c1
-rw-r--r--drivers/rtc/rtc-pcf8563.c2
-rw-r--r--drivers/rtc/rtc-pm8xxx.c18
-rw-r--r--drivers/rtc/rtc-rzn1.c71
-rw-r--r--drivers/rtc/rtc-s32g.c385
-rw-r--r--drivers/rtc/rtc-s3c.c1
-rw-r--r--drivers/rtc/rtc-sh.c285
-rw-r--r--drivers/rtc/rtc-stm32.c1
-rw-r--r--drivers/scsi/aacraid/aacraid.h1
-rw-r--r--drivers/scsi/aacraid/commsup.c10
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c2
-rw-r--r--drivers/spi/spi-bcm63xx.c2
-rw-r--r--drivers/spi/spi-pci1xxxx.c48
-rw-r--r--drivers/spi/spi-qpic-snand.c14
-rw-r--r--drivers/spmi/Kconfig9
-rw-r--r--drivers/spmi/Makefile1
-rw-r--r--drivers/spmi/spmi-apple-controller.c168
-rw-r--r--drivers/spmi/spmi-pmic-arb.c2
-rw-r--r--drivers/staging/fbtft/Kconfig35
-rw-r--r--drivers/staging/gpib/agilent_82350b/agilent_82350b.c86
-rw-r--r--drivers/staging/gpib/agilent_82350b/agilent_82350b.h28
-rw-r--r--drivers/staging/gpib/agilent_82357a/agilent_82357a.c76
-rw-r--r--drivers/staging/gpib/agilent_82357a/agilent_82357a.h4
-rw-r--r--drivers/staging/gpib/cb7210/cb7210.c74
-rw-r--r--drivers/staging/gpib/cb7210/cb7210.h26
-rw-r--r--drivers/staging/gpib/cec/cec_gpib.c26
-rw-r--r--drivers/staging/gpib/common/gpib_os.c316
-rw-r--r--drivers/staging/gpib/common/iblib.c60
-rw-r--r--drivers/staging/gpib/common/ibsys.h13
-rw-r--r--drivers/staging/gpib/eastwood/fluke_gpib.c107
-rw-r--r--drivers/staging/gpib/eastwood/fluke_gpib.h29
-rw-r--r--drivers/staging/gpib/fmh_gpib/fmh_gpib.c144
-rw-r--r--drivers/staging/gpib/fmh_gpib/fmh_gpib.h6
-rw-r--r--drivers/staging/gpib/gpio/gpib_bitbang.c142
-rw-r--r--drivers/staging/gpib/hp_82335/hp82335.c35
-rw-r--r--drivers/staging/gpib/hp_82341/hp_82341.c52
-rw-r--r--drivers/staging/gpib/include/gpibP.h14
-rw-r--r--drivers/staging/gpib/include/gpib_proto.h31
-rw-r--r--drivers/staging/gpib/include/gpib_types.h162
-rw-r--r--drivers/staging/gpib/include/nec7210.h40
-rw-r--r--drivers/staging/gpib/include/nec7210_registers.h3
-rw-r--r--drivers/staging/gpib/include/tms9914.h37
-rw-r--r--drivers/staging/gpib/ines/ines.h43
-rw-r--r--drivers/staging/gpib/ines/ines_gpib.c216
-rw-r--r--drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c145
-rw-r--r--drivers/staging/gpib/nec7210/nec7210.c72
-rw-r--r--drivers/staging/gpib/ni_usb/ni_usb_gpib.c70
-rw-r--r--drivers/staging/gpib/ni_usb/ni_usb_gpib.h32
-rw-r--r--drivers/staging/gpib/pc2/pc2_gpib.c46
-rw-r--r--drivers/staging/gpib/tms9914/tms9914.c69
-rw-r--r--drivers/staging/gpib/tnt4882/tnt4882_gpib.c106
-rw-r--r--drivers/staging/gpib/uapi/gpib.h (renamed from drivers/staging/gpib/uapi/gpib_user.h)226
-rw-r--r--drivers/staging/gpib/uapi/gpib_ioctl.h134
-rw-r--r--drivers/staging/greybus/camera.c4
-rw-r--r--drivers/staging/greybus/fw-management.c48
-rw-r--r--drivers/staging/greybus/gpio.c16
-rw-r--r--drivers/staging/iio/accel/adis16203.c2
-rw-r--r--drivers/staging/iio/adc/ad7816.c2
-rw-r--r--drivers/staging/iio/addac/adt7316-i2c.c2
-rw-r--r--drivers/staging/iio/addac/adt7316.c2
-rw-r--r--drivers/staging/iio/frequency/ad9832.c102
-rw-r--r--drivers/staging/iio/frequency/ad9832.h1
-rw-r--r--drivers/staging/iio/frequency/ad9834.c4
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c44
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ap.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_btcoex.c12
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_cmd.c11
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_ieee80211.c5
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme.c10
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_mlme_ext.c2
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_pwrctrl.c8
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_recv.c6
-rw-r--r--drivers/staging/rtl8723bs/core/rtw_xmit.c18
-rw-r--r--drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c68
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_btcoex.c22
-rw-r--r--drivers/staging/rtl8723bs/hal/hal_com.c11
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_CfoTracking.c4
-rw-r--r--drivers/staging/rtl8723bs/hal/odm_DIG.c2
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c81
-rw-r--r--drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c33
-rw-r--r--drivers/staging/rtl8723bs/include/hal_pwr_seq.h2
-rw-r--r--drivers/staging/rtl8723bs/include/sta_info.h2
-rw-r--r--drivers/staging/rtl8723bs/os_dep/recv_linux.c13
-rw-r--r--drivers/staging/sm750fb/Makefile3
-rw-r--r--drivers/staging/sm750fb/TODO3
-rw-r--r--drivers/staging/sm750fb/ddk750.h3
-rw-r--r--drivers/staging/sm750fb/ddk750_display.c1
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.c62
-rw-r--r--drivers/staging/sm750fb/ddk750_dvi.h57
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.c247
-rw-r--r--drivers/staging/sm750fb/ddk750_hwi2c.h12
-rw-r--r--drivers/staging/sm750fb/ddk750_power.h8
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.c408
-rw-r--r--drivers/staging/sm750fb/ddk750_sii164.h174
-rw-r--r--drivers/staging/sm750fb/sm750.c24
-rw-r--r--drivers/staging/sm750fb/sm750.h30
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.c14
-rw-r--r--drivers/staging/sm750fb/sm750_cursor.h12
-rw-r--r--drivers/staging/sm750fb/sm750_hw.c38
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c6
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/controls.c14
-rw-r--r--drivers/thunderbolt/ctl.c5
-rw-r--r--drivers/thunderbolt/domain.c2
-rw-r--r--drivers/thunderbolt/icm.c36
-rw-r--r--drivers/thunderbolt/switch.c1
-rw-r--r--drivers/thunderbolt/tb.c22
-rw-r--r--drivers/thunderbolt/tb.h14
-rw-r--r--drivers/thunderbolt/tb_msgs.h1
-rw-r--r--drivers/thunderbolt/tunnel.c92
-rw-r--r--drivers/thunderbolt/tunnel.h23
-rw-r--r--drivers/thunderbolt/usb4.c18
-rw-r--r--drivers/thunderbolt/usb4_port.c56
-rw-r--r--drivers/tty/mxser.c4
-rw-r--r--drivers/tty/serdev/core.c8
-rw-r--r--drivers/tty/serial/8250/8250.h6
-rw-r--r--drivers/tty/serial/8250/8250_core.c2
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_ni.c89
-rw-r--r--drivers/tty/serial/8250/8250_of.c15
-rw-r--r--drivers/tty/serial/8250/8250_omap.c25
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_port.c16
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig2
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/fsl_lpuart.c5
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/tty/serial/lantiq.c4
-rw-r--r--drivers/tty/serial/max3100.c3
-rw-r--r--drivers/tty/serial/max310x.c7
-rw-r--r--drivers/tty/serial/milbeaut_usio.c5
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c25
-rw-r--r--drivers/tty/serial/samsung_tty.c6
-rw-r--r--drivers/tty/serial/sc16is7xx.c7
-rw-r--r--drivers/tty/serial/serial_core.c97
-rw-r--r--drivers/tty/serial/sh-sci-common.h167
-rw-r--r--drivers/tty/serial/sh-sci.c630
-rw-r--r--drivers/tty/serial/sh-sci.h2
-rw-r--r--drivers/tty/serial/sifive.c88
-rw-r--r--drivers/tty/serial/tegra-utc.c2
-rw-r--r--drivers/tty/serial/uartlite.c25
-rw-r--r--drivers/tty/tty_io.c96
-rw-r--r--drivers/tty/tty_ioctl.c50
-rw-r--r--drivers/tty/tty_port.c20
-rw-r--r--drivers/tty/vt/.gitignore3
-rw-r--r--drivers/tty/vt/Makefile34
-rw-r--r--drivers/tty/vt/consolemap.c2
-rwxr-xr-xdrivers/tty/vt/gen_ucs_fallback_table.py360
-rwxr-xr-xdrivers/tty/vt/gen_ucs_recompose_table.py257
-rwxr-xr-xdrivers/tty/vt/gen_ucs_width_table.py307
-rw-r--r--drivers/tty/vt/keyboard.c37
-rw-r--r--drivers/tty/vt/selection.c31
-rw-r--r--drivers/tty/vt/ucs.c251
-rw-r--r--drivers/tty/vt/ucs_fallback_table.h_shipped3346
-rw-r--r--drivers/tty/vt/ucs_recompose_table.h_shipped102
-rw-r--r--drivers/tty/vt/ucs_width_table.h_shipped453
-rw-r--r--drivers/tty/vt/vt.c244
-rw-r--r--drivers/tty/vt/vt_ioctl.c18
-rw-r--r--drivers/ufs/core/ufshcd.c3
-rw-r--r--drivers/ufs/host/ufs-qcom.c141
-rw-r--r--drivers/uio/uio_hv_generic.c32
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.c21
-rw-r--r--drivers/usb/cdns3/cdnsp-gadget.h4
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c37
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c77
-rw-r--r--drivers/usb/class/cdc-wdm.c23
-rw-r--r--drivers/usb/class/usbtmc.c21
-rw-r--r--drivers/usb/common/usb-conn-gpio.c25
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/hub.c90
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--drivers/usb/core/usb-acpi.c2
-rw-r--r--drivers/usb/core/usb.c14
-rw-r--r--drivers/usb/dwc2/gadget.c8
-rw-r--r--drivers/usb/dwc3/Makefile1
-rw-r--r--drivers/usb/dwc3/core.c197
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c18
-rw-r--r--drivers/usb/dwc3/dwc3-qcom-legacy.c935
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c284
-rw-r--r--drivers/usb/dwc3/glue.h36
-rw-r--r--drivers/usb/dwc3/host.c3
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/function/f_hid.c138
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.h2
-rw-r--r--drivers/usb/gadget/function/f_serial.c7
-rw-r--r--drivers/usb/gadget/function/f_tcm.c4
-rw-r--r--drivers/usb/gadget/function/u_hid.h2
-rw-r--r--drivers/usb/gadget/function/u_serial.c50
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.h4
-rw-r--r--drivers/usb/gadget/legacy/g_ffs.c2
-rw-r--r--drivers/usb/gadget/legacy/inode.c2
-rw-r--r--drivers/usb/gadget/udc/Kconfig44
-rw-r--r--drivers/usb/gadget/udc/Makefile5
-rw-r--r--drivers/usb/gadget/udc/core.c2
-rw-r--r--drivers/usb/gadget/udc/fusb300_udc.c1516
-rw-r--r--drivers/usb/gadget/udc/fusb300_udc.h675
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c2
-rw-r--r--drivers/usb/gadget/udc/mv_u3d.h317
-rw-r--r--drivers/usb/gadget/udc/mv_u3d_core.c2062
-rw-r--r--drivers/usb/gadget/udc/mv_udc.h309
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2426
-rw-r--r--drivers/usb/gadget/udc/net2272.c2723
-rw-r--r--drivers/usb/gadget/udc/net2272.h584
-rw-r--r--drivers/usb/gadget/udc/renesas_usb3.c6
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c2
-rw-r--r--drivers/usb/host/Kconfig11
-rw-r--r--drivers/usb/host/Makefile4
-rw-r--r--drivers/usb/host/ehci-fsl.c25
-rw-r--r--drivers/usb/host/xhci-caps.h4
-rw-r--r--drivers/usb/host/xhci-debugfs.c108
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-mem.c245
-rw-r--r--drivers/usb/host/xhci-plat.c2
-rw-r--r--drivers/usb/host/xhci-ring.c74
-rw-r--r--drivers/usb/host/xhci-sideband.c457
-rw-r--r--drivers/usb/host/xhci.c209
-rw-r--r--drivers/usb/host/xhci.h112
-rw-r--r--drivers/usb/misc/onboard_usb_dev.c113
-rw-r--r--drivers/usb/misc/onboard_usb_dev.h19
-rw-r--r--drivers/usb/phy/Kconfig12
-rw-r--r--drivers/usb/phy/Makefile1
-rw-r--r--drivers/usb/phy/phy-mv-usb.c881
-rw-r--r--drivers/usb/renesas_usbhs/common.c54
-rw-r--r--drivers/usb/serial/bus.c2
-rw-r--r--drivers/usb/serial/pl2303.c2
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c5
-rw-r--r--drivers/usb/storage/unusual_uas.h7
-rw-r--r--drivers/usb/typec/altmodes/displayport.c4
-rw-r--r--drivers/usb/typec/bus.c2
-rw-r--r--drivers/usb/typec/mux.c4
-rw-r--r--drivers/usb/typec/mux/fsa4480.c5
-rw-r--r--drivers/usb/typec/port-mapper.c23
-rw-r--r--drivers/usb/typec/tcpm/tcpci.c5
-rw-r--r--drivers/usb/typec/tcpm/tcpci_maxim_core.c8
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c188
-rw-r--r--drivers/usb/typec/tipd/core.c2
-rw-r--r--drivers/usb/typec/tipd/tps6598x.h2
-rw-r--r--drivers/usb/typec/tipd/trace.h2
-rw-r--r--drivers/usb/typec/ucsi/Kconfig11
-rw-r--r--drivers/usb/typec/ucsi/Makefile1
-rw-r--r--drivers/usb/typec/ucsi/debugfs.c4
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h4
-rw-r--r--drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c526
-rw-r--r--drivers/video/console/dummycon.c18
-rw-r--r--drivers/video/screen_info_pci.c79
-rw-r--r--drivers/virt/acrn/irqfd.c2
-rw-r--r--drivers/w1/w1_netlink.c42
1007 files changed, 26617 insertions, 23207 deletions
diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c
index ccaaf6c100c0..9db741695401 100644
--- a/drivers/accel/ivpu/ivpu_fw.c
+++ b/drivers/accel/ivpu/ivpu_fw.c
@@ -55,18 +55,18 @@ static struct {
int gen;
const char *name;
} fw_names[] = {
- { IVPU_HW_IP_37XX, "vpu_37xx.bin" },
+ { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v1.bin" },
{ IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v0.0.bin" },
- { IVPU_HW_IP_40XX, "vpu_40xx.bin" },
+ { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v1.bin" },
{ IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v0.0.bin" },
- { IVPU_HW_IP_50XX, "vpu_50xx.bin" },
+ { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v1.bin" },
{ IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v0.0.bin" },
};
/* Production fw_names from the table above */
-MODULE_FIRMWARE("intel/vpu/vpu_37xx_v0.0.bin");
-MODULE_FIRMWARE("intel/vpu/vpu_40xx_v0.0.bin");
-MODULE_FIRMWARE("intel/vpu/vpu_50xx_v0.0.bin");
+MODULE_FIRMWARE("intel/vpu/vpu_37xx_v1.bin");
+MODULE_FIRMWARE("intel/vpu/vpu_40xx_v1.bin");
+MODULE_FIRMWARE("intel/vpu/vpu_50xx_v1.bin");
static int ivpu_fw_request(struct ivpu_device *vdev)
{
diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c
index e0d242d9f3e5..59cfcf3eaded 100644
--- a/drivers/accel/ivpu/ivpu_gem.c
+++ b/drivers/accel/ivpu/ivpu_gem.c
@@ -28,11 +28,21 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con
{
ivpu_dbg(vdev, BO,
"%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n",
- action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0,
+ action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx_id,
(bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc,
(bool)drm_gem_is_imported(&bo->base.base));
}
+static inline int ivpu_bo_lock(struct ivpu_bo *bo)
+{
+ return dma_resv_lock(bo->base.base.resv, NULL);
+}
+
+static inline void ivpu_bo_unlock(struct ivpu_bo *bo)
+{
+ dma_resv_unlock(bo->base.base.resv);
+}
+
/*
* ivpu_bo_pin() - pin the backing physical pages and map them to VPU.
*
@@ -43,22 +53,22 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con
int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
{
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
+ struct sg_table *sgt;
int ret = 0;
- mutex_lock(&bo->lock);
-
ivpu_dbg_bo(vdev, bo, "pin");
- drm_WARN_ON(&vdev->drm, !bo->ctx);
- if (!bo->mmu_mapped) {
- struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
+ sgt = drm_gem_shmem_get_pages_sgt(&bo->base);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret);
+ return ret;
+ }
- if (IS_ERR(sgt)) {
- ret = PTR_ERR(sgt);
- ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret);
- goto unlock;
- }
+ ivpu_bo_lock(bo);
+ if (!bo->mmu_mapped) {
+ drm_WARN_ON(&vdev->drm, !bo->ctx);
ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt,
ivpu_bo_is_snooped(bo));
if (ret) {
@@ -69,7 +79,7 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo)
}
unlock:
- mutex_unlock(&bo->lock);
+ ivpu_bo_unlock(bo);
return ret;
}
@@ -84,7 +94,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
if (!drm_dev_enter(&vdev->drm, &idx))
return -ENODEV;
- mutex_lock(&bo->lock);
+ ivpu_bo_lock(bo);
ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node);
if (!ret) {
@@ -94,9 +104,7 @@ ivpu_bo_alloc_vpu_addr(struct ivpu_bo *bo, struct ivpu_mmu_context *ctx,
ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret);
}
- ivpu_dbg_bo(vdev, bo, "alloc");
-
- mutex_unlock(&bo->lock);
+ ivpu_bo_unlock(bo);
drm_dev_exit(idx);
@@ -107,7 +115,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
{
struct ivpu_device *vdev = ivpu_bo_to_vdev(bo);
- lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount));
+ lockdep_assert(dma_resv_held(bo->base.base.resv) || !kref_read(&bo->base.base.refcount));
if (bo->mmu_mapped) {
drm_WARN_ON(&vdev->drm, !bo->ctx);
@@ -125,14 +133,12 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo)
if (drm_gem_is_imported(&bo->base.base))
return;
- dma_resv_lock(bo->base.base.resv, NULL);
if (bo->base.sgt) {
dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0);
sg_free_table(bo->base.sgt);
kfree(bo->base.sgt);
bo->base.sgt = NULL;
}
- dma_resv_unlock(bo->base.base.resv);
}
void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx)
@@ -144,12 +150,12 @@ void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_m
mutex_lock(&vdev->bo_list_lock);
list_for_each_entry(bo, &vdev->bo_list, bo_list_node) {
- mutex_lock(&bo->lock);
+ ivpu_bo_lock(bo);
if (bo->ctx == ctx) {
ivpu_dbg_bo(vdev, bo, "unbind");
ivpu_bo_unbind_locked(bo);
}
- mutex_unlock(&bo->lock);
+ ivpu_bo_unlock(bo);
}
mutex_unlock(&vdev->bo_list_lock);
}
@@ -169,7 +175,6 @@ struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t siz
bo->base.pages_mark_dirty_on_put = true; /* VPU can dirty a BO anytime */
INIT_LIST_HEAD(&bo->bo_list_node);
- mutex_init(&bo->lock);
return &bo->base.base;
}
@@ -215,7 +220,7 @@ fail_detach:
return ERR_PTR(ret);
}
-static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags)
+static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 flags, u32 ctx_id)
{
struct drm_gem_shmem_object *shmem;
struct ivpu_bo *bo;
@@ -233,6 +238,7 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla
return ERR_CAST(shmem);
bo = to_ivpu_bo(&shmem->base);
+ bo->ctx_id = ctx_id;
bo->base.map_wc = flags & DRM_IVPU_BO_WC;
bo->flags = flags;
@@ -240,6 +246,8 @@ static struct ivpu_bo *ivpu_bo_alloc(struct ivpu_device *vdev, u64 size, u32 fla
list_add_tail(&bo->bo_list_node, &vdev->bo_list);
mutex_unlock(&vdev->bo_list_lock);
+ ivpu_dbg_bo(vdev, bo, "alloc");
+
return bo;
}
@@ -277,10 +285,14 @@ static void ivpu_gem_bo_free(struct drm_gem_object *obj)
list_del(&bo->bo_list_node);
mutex_unlock(&vdev->bo_list_lock);
- drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
+ drm_WARN_ON(&vdev->drm, !drm_gem_is_imported(&bo->base.base) &&
+ !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ));
+ drm_WARN_ON(&vdev->drm, ivpu_bo_size(bo) == 0);
+ drm_WARN_ON(&vdev->drm, bo->base.vaddr);
ivpu_bo_unbind_locked(bo);
- mutex_destroy(&bo->lock);
+ drm_WARN_ON(&vdev->drm, bo->mmu_mapped);
+ drm_WARN_ON(&vdev->drm, bo->ctx);
drm_WARN_ON(obj->dev, refcount_read(&bo->base.pages_use_count) > 1);
drm_gem_shmem_free(&bo->base);
@@ -314,7 +326,7 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
if (size == 0)
return -EINVAL;
- bo = ivpu_bo_alloc(vdev, size, args->flags);
+ bo = ivpu_bo_alloc(vdev, size, args->flags, file_priv->ctx.id);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (ctx %u size %llu flags 0x%x)",
bo, file_priv->ctx.id, args->size, args->flags);
@@ -322,7 +334,10 @@ int ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
}
ret = drm_gem_handle_create(file, &bo->base.base, &args->handle);
- if (!ret)
+ if (ret)
+ ivpu_err(vdev, "Failed to create handle for BO: %pe (ctx %u size %llu flags 0x%x)",
+ bo, file_priv->ctx.id, args->size, args->flags);
+ else
args->vpu_addr = bo->vpu_addr;
drm_gem_object_put(&bo->base.base);
@@ -345,7 +360,7 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(range->end));
drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(size));
- bo = ivpu_bo_alloc(vdev, size, flags);
+ bo = ivpu_bo_alloc(vdev, size, flags, IVPU_GLOBAL_CONTEXT_MMU_SSID);
if (IS_ERR(bo)) {
ivpu_err(vdev, "Failed to allocate BO: %pe (vpu_addr 0x%llx size %llu flags 0x%x)",
bo, range->start, size, flags);
@@ -361,9 +376,9 @@ ivpu_bo_create(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx,
goto err_put;
if (flags & DRM_IVPU_BO_MAPPABLE) {
- dma_resv_lock(bo->base.base.resv, NULL);
+ ivpu_bo_lock(bo);
ret = drm_gem_shmem_vmap_locked(&bo->base, &map);
- dma_resv_unlock(bo->base.base.resv);
+ ivpu_bo_unlock(bo);
if (ret)
goto err_put;
@@ -386,9 +401,9 @@ void ivpu_bo_free(struct ivpu_bo *bo)
struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr);
if (bo->flags & DRM_IVPU_BO_MAPPABLE) {
- dma_resv_lock(bo->base.base.resv, NULL);
+ ivpu_bo_lock(bo);
drm_gem_shmem_vunmap_locked(&bo->base, &map);
- dma_resv_unlock(bo->base.base.resv);
+ ivpu_bo_unlock(bo);
}
drm_gem_object_put(&bo->base.base);
@@ -407,12 +422,12 @@ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file
bo = to_ivpu_bo(obj);
- mutex_lock(&bo->lock);
+ ivpu_bo_lock(bo);
args->flags = bo->flags;
args->mmap_offset = drm_vma_node_offset_addr(&obj->vma_node);
args->vpu_addr = bo->vpu_addr;
args->size = obj->size;
- mutex_unlock(&bo->lock);
+ ivpu_bo_unlock(bo);
drm_gem_object_put(obj);
return ret;
@@ -449,10 +464,10 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file
static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
{
- mutex_lock(&bo->lock);
+ ivpu_bo_lock(bo);
drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u",
- bo, bo->ctx ? bo->ctx->id : 0, bo->vpu_addr, bo->base.base.size,
+ bo, bo->ctx_id, bo->vpu_addr, bo->base.base.size,
bo->flags, kref_read(&bo->base.base.refcount));
if (bo->base.pages)
@@ -466,7 +481,7 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p)
drm_printf(p, "\n");
- mutex_unlock(&bo->lock);
+ ivpu_bo_unlock(bo);
}
void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p)
diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h
index a222a9ec9d61..aa8ff14f7aae 100644
--- a/drivers/accel/ivpu/ivpu_gem.h
+++ b/drivers/accel/ivpu/ivpu_gem.h
@@ -17,10 +17,10 @@ struct ivpu_bo {
struct list_head bo_list_node;
struct drm_mm_node mm_node;
- struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */
u64 vpu_addr;
u32 flags;
u32 job_status; /* Valid only for command buffer */
+ u32 ctx_id;
bool mmu_mapped;
};
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index b28da35c30b6..fae8351aa330 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -247,6 +247,10 @@ static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cm
if (!cmdq->db_id)
return 0;
+ ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id);
+ if (!ret)
+ ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id);
+
if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) {
ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id);
if (!ret)
@@ -254,10 +258,6 @@ static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cm
cmdq->id, file_priv->ctx.id);
}
- ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id);
- if (!ret)
- ivpu_dbg(vdev, JOB, "DB %d unregistered\n", cmdq->db_id);
-
xa_erase(&file_priv->vdev->db_xa, cmdq->db_id);
cmdq->db_id = 0;
@@ -986,7 +986,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work)
return;
if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
- ivpu_jsm_reset_engine(vdev, 0);
+ if (ivpu_jsm_reset_engine(vdev, 0))
+ return;
mutex_lock(&vdev->context_list_lock);
xa_for_each(&vdev->context_xa, ctx_id, file_priv) {
@@ -1009,7 +1010,8 @@ void ivpu_context_abort_work_fn(struct work_struct *work)
if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW)
goto runtime_put;
- ivpu_jsm_hws_resume_engine(vdev, 0);
+ if (ivpu_jsm_hws_resume_engine(vdev, 0))
+ return;
/*
* In hardware scheduling mode NPU already has stopped processing jobs
* and won't send us any further notifications, thus we have to free job related resources
diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c
index 219ab8afefab..0256b2dfefc1 100644
--- a/drivers/accel/ivpu/ivpu_jsm_msg.c
+++ b/drivers/accel/ivpu/ivpu_jsm_msg.c
@@ -7,6 +7,7 @@
#include "ivpu_hw.h"
#include "ivpu_ipc.h"
#include "ivpu_jsm_msg.h"
+#include "ivpu_pm.h"
#include "vpu_jsm_api.h"
const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type)
@@ -163,8 +164,10 @@ int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine)
ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_ENGINE_RESET_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
- if (ret)
+ if (ret) {
ivpu_err_ratelimited(vdev, "Failed to reset engine %d: %d\n", engine, ret);
+ ivpu_pm_trigger_recovery(vdev, "Engine reset failed");
+ }
return ret;
}
@@ -354,8 +357,10 @@ int ivpu_jsm_hws_resume_engine(struct ivpu_device *vdev, u32 engine)
ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE, &resp,
VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm);
- if (ret)
+ if (ret) {
ivpu_err_ratelimited(vdev, "Failed to resume engine %d: %d\n", engine, ret);
+ ivpu_pm_trigger_recovery(vdev, "Engine resume failed");
+ }
return ret;
}
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 5fc2c8ee61b1..c463ca4a8fff 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -79,6 +79,8 @@ static HLIST_HEAD(binder_deferred_list);
static DEFINE_MUTEX(binder_deferred_lock);
static HLIST_HEAD(binder_devices);
+static DEFINE_SPINLOCK(binder_devices_lock);
+
static HLIST_HEAD(binder_procs);
static DEFINE_MUTEX(binder_procs_lock);
@@ -3261,20 +3263,16 @@ static void binder_transaction(struct binder_proc *proc,
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld-%lld\n",
+ "%d:%d BC_REPLY %d -> %d:%d, data size %lld-%lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
- (u64)tr->data.ptr.buffer,
- (u64)tr->data.ptr.offsets,
(u64)tr->data_size, (u64)tr->offsets_size,
(u64)extra_buffers_size);
else
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld-%lld\n",
+ "%d:%d BC_TRANSACTION %d -> %d - node %d, data size %lld-%lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
- (u64)tr->data.ptr.buffer,
- (u64)tr->data.ptr.offsets,
(u64)tr->data_size, (u64)tr->offsets_size,
(u64)extra_buffers_size);
@@ -4223,20 +4221,21 @@ static int binder_thread_write(struct binder_proc *proc,
if (IS_ERR_OR_NULL(buffer)) {
if (PTR_ERR(buffer) == -EPERM) {
binder_user_error(
- "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n",
+ "%d:%d BC_FREE_BUFFER matched unreturned or currently freeing buffer at offset %lx\n",
proc->pid, thread->pid,
- (u64)data_ptr);
+ (unsigned long)data_ptr - proc->alloc.vm_start);
} else {
binder_user_error(
- "%d:%d BC_FREE_BUFFER u%016llx no match\n",
+ "%d:%d BC_FREE_BUFFER no match for buffer at offset %lx\n",
proc->pid, thread->pid,
- (u64)data_ptr);
+ (unsigned long)data_ptr - proc->alloc.vm_start);
}
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
- "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n",
- proc->pid, thread->pid, (u64)data_ptr,
+ "%d:%d BC_FREE_BUFFER at offset %lx found buffer %d for %s transaction\n",
+ proc->pid, thread->pid,
+ (unsigned long)data_ptr - proc->alloc.vm_start,
buffer->debug_id,
buffer->transaction ? "active" : "finished");
binder_free_buf(proc, thread, buffer, false);
@@ -5053,16 +5052,14 @@ retry:
trace_binder_transaction_received(t);
binder_stat_br(proc, thread, cmd);
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d %s %d %d:%d, cmd %u size %zd-%zd ptr %016llx-%016llx\n",
+ "%d:%d %s %d %d:%d, cmd %u size %zd-%zd\n",
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
(cmd == BR_TRANSACTION_SEC_CTX) ?
"BR_TRANSACTION_SEC_CTX" : "BR_REPLY",
t->debug_id, t_from ? t_from->proc->pid : 0,
t_from ? t_from->pid : 0, cmd,
- t->buffer->data_size, t->buffer->offsets_size,
- (u64)trd->data.ptr.buffer,
- (u64)trd->data.ptr.offsets);
+ t->buffer->data_size, t->buffer->offsets_size);
if (t_from)
binder_thread_dec_tmpref(t_from);
@@ -5244,6 +5241,7 @@ static void binder_free_proc(struct binder_proc *proc)
__func__, proc->outstanding_txns);
device = container_of(proc->context, struct binder_device, context);
if (refcount_dec_and_test(&device->ref)) {
+ binder_remove_device(device);
kfree(proc->context->name);
kfree(device);
}
@@ -6377,10 +6375,10 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
}
static void print_binder_work_ilocked(struct seq_file *m,
- struct binder_proc *proc,
- const char *prefix,
- const char *transaction_prefix,
- struct binder_work *w)
+ struct binder_proc *proc,
+ const char *prefix,
+ const char *transaction_prefix,
+ struct binder_work *w, bool hash_ptrs)
{
struct binder_node *node;
struct binder_transaction *t;
@@ -6403,9 +6401,15 @@ static void print_binder_work_ilocked(struct seq_file *m,
break;
case BINDER_WORK_NODE:
node = container_of(w, struct binder_node, work);
- seq_printf(m, "%snode work %d: u%016llx c%016llx\n",
- prefix, node->debug_id,
- (u64)node->ptr, (u64)node->cookie);
+ if (hash_ptrs)
+ seq_printf(m, "%snode work %d: u%p c%p\n",
+ prefix, node->debug_id,
+ (void *)(long)node->ptr,
+ (void *)(long)node->cookie);
+ else
+ seq_printf(m, "%snode work %d: u%016llx c%016llx\n",
+ prefix, node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
break;
case BINDER_WORK_DEAD_BINDER:
seq_printf(m, "%shas dead binder\n", prefix);
@@ -6430,7 +6434,7 @@ static void print_binder_work_ilocked(struct seq_file *m,
static void print_binder_thread_ilocked(struct seq_file *m,
struct binder_thread *thread,
- int print_always)
+ bool print_always, bool hash_ptrs)
{
struct binder_transaction *t;
struct binder_work *w;
@@ -6460,14 +6464,16 @@ static void print_binder_thread_ilocked(struct seq_file *m,
}
list_for_each_entry(w, &thread->todo, entry) {
print_binder_work_ilocked(m, thread->proc, " ",
- " pending transaction", w);
+ " pending transaction",
+ w, hash_ptrs);
}
if (!print_always && m->count == header_pos)
m->count = start_pos;
}
static void print_binder_node_nilocked(struct seq_file *m,
- struct binder_node *node)
+ struct binder_node *node,
+ bool hash_ptrs)
{
struct binder_ref *ref;
struct binder_work *w;
@@ -6475,8 +6481,13 @@ static void print_binder_node_nilocked(struct seq_file *m,
count = hlist_count_nodes(&node->refs);
- seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d",
- node->debug_id, (u64)node->ptr, (u64)node->cookie,
+ if (hash_ptrs)
+ seq_printf(m, " node %d: u%p c%p", node->debug_id,
+ (void *)(long)node->ptr, (void *)(long)node->cookie);
+ else
+ seq_printf(m, " node %d: u%016llx c%016llx", node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
+ seq_printf(m, " hs %d hw %d ls %d lw %d is %d iw %d tr %d",
node->has_strong_ref, node->has_weak_ref,
node->local_strong_refs, node->local_weak_refs,
node->internal_strong_refs, count, node->tmp_refs);
@@ -6489,7 +6500,8 @@ static void print_binder_node_nilocked(struct seq_file *m,
if (node->proc) {
list_for_each_entry(w, &node->async_todo, entry)
print_binder_work_ilocked(m, node->proc, " ",
- " pending async transaction", w);
+ " pending async transaction",
+ w, hash_ptrs);
}
}
@@ -6505,8 +6517,54 @@ static void print_binder_ref_olocked(struct seq_file *m,
binder_node_unlock(ref->node);
}
-static void print_binder_proc(struct seq_file *m,
- struct binder_proc *proc, int print_all)
+/**
+ * print_next_binder_node_ilocked() - Print binder_node from a locked list
+ * @m: struct seq_file for output via seq_printf()
+ * @proc: struct binder_proc we hold the inner_proc_lock to (if any)
+ * @node: struct binder_node to print fields of
+ * @prev_node: struct binder_node we hold a temporary reference to (if any)
+ * @hash_ptrs: whether to hash @node's binder_uintptr_t fields
+ *
+ * Helper function to handle synchronization around printing a struct
+ * binder_node while iterating through @proc->nodes or the dead nodes list.
+ * Caller must hold either @proc->inner_lock (for live nodes) or
+ * binder_dead_nodes_lock. This lock will be released during the body of this
+ * function, but it will be reacquired before returning to the caller.
+ *
+ * Return: pointer to the struct binder_node we hold a tmpref on
+ */
+static struct binder_node *
+print_next_binder_node_ilocked(struct seq_file *m, struct binder_proc *proc,
+ struct binder_node *node,
+ struct binder_node *prev_node, bool hash_ptrs)
+{
+ /*
+ * Take a temporary reference on the node so that isn't freed while
+ * we print it.
+ */
+ binder_inc_node_tmpref_ilocked(node);
+ /*
+ * Live nodes need to drop the inner proc lock and dead nodes need to
+ * drop the binder_dead_nodes_lock before trying to take the node lock.
+ */
+ if (proc)
+ binder_inner_proc_unlock(proc);
+ else
+ spin_unlock(&binder_dead_nodes_lock);
+ if (prev_node)
+ binder_put_node(prev_node);
+ binder_node_inner_lock(node);
+ print_binder_node_nilocked(m, node, hash_ptrs);
+ binder_node_inner_unlock(node);
+ if (proc)
+ binder_inner_proc_lock(proc);
+ else
+ spin_lock(&binder_dead_nodes_lock);
+ return node;
+}
+
+static void print_binder_proc(struct seq_file *m, struct binder_proc *proc,
+ bool print_all, bool hash_ptrs)
{
struct binder_work *w;
struct rb_node *n;
@@ -6519,31 +6577,19 @@ static void print_binder_proc(struct seq_file *m,
header_pos = m->count;
binder_inner_proc_lock(proc);
- for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
+ for (n = rb_first(&proc->threads); n; n = rb_next(n))
print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread,
- rb_node), print_all);
+ rb_node), print_all, hash_ptrs);
- for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) {
+ for (n = rb_first(&proc->nodes); n; n = rb_next(n)) {
struct binder_node *node = rb_entry(n, struct binder_node,
rb_node);
if (!print_all && !node->has_async_transaction)
continue;
- /*
- * take a temporary reference on the node so it
- * survives and isn't removed from the tree
- * while we print it.
- */
- binder_inc_node_tmpref_ilocked(node);
- /* Need to drop inner lock to take node lock */
- binder_inner_proc_unlock(proc);
- if (last_node)
- binder_put_node(last_node);
- binder_node_inner_lock(node);
- print_binder_node_nilocked(m, node);
- binder_node_inner_unlock(node);
- last_node = node;
- binder_inner_proc_lock(proc);
+ last_node = print_next_binder_node_ilocked(m, proc, node,
+ last_node,
+ hash_ptrs);
}
binder_inner_proc_unlock(proc);
if (last_node)
@@ -6551,19 +6597,18 @@ static void print_binder_proc(struct seq_file *m,
if (print_all) {
binder_proc_lock(proc);
- for (n = rb_first(&proc->refs_by_desc);
- n != NULL;
- n = rb_next(n))
+ for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n))
print_binder_ref_olocked(m, rb_entry(n,
- struct binder_ref,
- rb_node_desc));
+ struct binder_ref,
+ rb_node_desc));
binder_proc_unlock(proc);
}
binder_alloc_print_allocated(m, &proc->alloc);
binder_inner_proc_lock(proc);
list_for_each_entry(w, &proc->todo, entry)
print_binder_work_ilocked(m, proc, " ",
- " pending transaction", w);
+ " pending transaction", w,
+ hash_ptrs);
list_for_each_entry(w, &proc->delivered_death, entry) {
seq_puts(m, " has delivered dead binder\n");
break;
@@ -6696,7 +6741,7 @@ static void print_binder_proc_stats(struct seq_file *m,
count = 0;
ready_threads = 0;
binder_inner_proc_lock(proc);
- for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n))
+ for (n = rb_first(&proc->threads); n; n = rb_next(n))
count++;
list_for_each_entry(thread, &proc->waiting_threads, waiting_thread_node)
@@ -6710,7 +6755,7 @@ static void print_binder_proc_stats(struct seq_file *m,
ready_threads,
free_async_space);
count = 0;
- for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n))
+ for (n = rb_first(&proc->nodes); n; n = rb_next(n))
count++;
binder_inner_proc_unlock(proc);
seq_printf(m, " nodes: %d\n", count);
@@ -6718,7 +6763,7 @@ static void print_binder_proc_stats(struct seq_file *m,
strong = 0;
weak = 0;
binder_proc_lock(proc);
- for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
+ for (n = rb_first(&proc->refs_by_desc); n; n = rb_next(n)) {
struct binder_ref *ref = rb_entry(n, struct binder_ref,
rb_node_desc);
count++;
@@ -6745,7 +6790,7 @@ static void print_binder_proc_stats(struct seq_file *m,
print_binder_stats(m, " ", &proc->stats);
}
-static int state_show(struct seq_file *m, void *unused)
+static void print_binder_state(struct seq_file *m, bool hash_ptrs)
{
struct binder_proc *proc;
struct binder_node *node;
@@ -6756,31 +6801,40 @@ static int state_show(struct seq_file *m, void *unused)
spin_lock(&binder_dead_nodes_lock);
if (!hlist_empty(&binder_dead_nodes))
seq_puts(m, "dead nodes:\n");
- hlist_for_each_entry(node, &binder_dead_nodes, dead_node) {
- /*
- * take a temporary reference on the node so it
- * survives and isn't removed from the list
- * while we print it.
- */
- node->tmp_refs++;
- spin_unlock(&binder_dead_nodes_lock);
- if (last_node)
- binder_put_node(last_node);
- binder_node_lock(node);
- print_binder_node_nilocked(m, node);
- binder_node_unlock(node);
- last_node = node;
- spin_lock(&binder_dead_nodes_lock);
- }
+ hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
+ last_node = print_next_binder_node_ilocked(m, NULL, node,
+ last_node,
+ hash_ptrs);
spin_unlock(&binder_dead_nodes_lock);
if (last_node)
binder_put_node(last_node);
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(proc, &binder_procs, proc_node)
- print_binder_proc(m, proc, 1);
+ print_binder_proc(m, proc, true, hash_ptrs);
+ mutex_unlock(&binder_procs_lock);
+}
+
+static void print_binder_transactions(struct seq_file *m, bool hash_ptrs)
+{
+ struct binder_proc *proc;
+
+ seq_puts(m, "binder transactions:\n");
+ mutex_lock(&binder_procs_lock);
+ hlist_for_each_entry(proc, &binder_procs, proc_node)
+ print_binder_proc(m, proc, false, hash_ptrs);
mutex_unlock(&binder_procs_lock);
+}
+
+static int state_show(struct seq_file *m, void *unused)
+{
+ print_binder_state(m, false);
+ return 0;
+}
+static int state_hashed_show(struct seq_file *m, void *unused)
+{
+ print_binder_state(m, true);
return 0;
}
@@ -6802,14 +6856,13 @@ static int stats_show(struct seq_file *m, void *unused)
static int transactions_show(struct seq_file *m, void *unused)
{
- struct binder_proc *proc;
-
- seq_puts(m, "binder transactions:\n");
- mutex_lock(&binder_procs_lock);
- hlist_for_each_entry(proc, &binder_procs, proc_node)
- print_binder_proc(m, proc, 0);
- mutex_unlock(&binder_procs_lock);
+ print_binder_transactions(m, false);
+ return 0;
+}
+static int transactions_hashed_show(struct seq_file *m, void *unused)
+{
+ print_binder_transactions(m, true);
return 0;
}
@@ -6822,7 +6875,7 @@ static int proc_show(struct seq_file *m, void *unused)
hlist_for_each_entry(itr, &binder_procs, proc_node) {
if (itr->pid == pid) {
seq_puts(m, "binder proc state:\n");
- print_binder_proc(m, itr, 1);
+ print_binder_proc(m, itr, true, false);
}
}
mutex_unlock(&binder_procs_lock);
@@ -6889,8 +6942,10 @@ const struct file_operations binder_fops = {
};
DEFINE_SHOW_ATTRIBUTE(state);
+DEFINE_SHOW_ATTRIBUTE(state_hashed);
DEFINE_SHOW_ATTRIBUTE(stats);
DEFINE_SHOW_ATTRIBUTE(transactions);
+DEFINE_SHOW_ATTRIBUTE(transactions_hashed);
DEFINE_SHOW_ATTRIBUTE(transaction_log);
const struct binder_debugfs_entry binder_debugfs_entries[] = {
@@ -6901,6 +6956,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = {
.data = NULL,
},
{
+ .name = "state_hashed",
+ .mode = 0444,
+ .fops = &state_hashed_fops,
+ .data = NULL,
+ },
+ {
.name = "stats",
.mode = 0444,
.fops = &stats_fops,
@@ -6913,6 +6974,12 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = {
.data = NULL,
},
{
+ .name = "transactions_hashed",
+ .mode = 0444,
+ .fops = &transactions_hashed_fops,
+ .data = NULL,
+ },
+ {
.name = "transaction_log",
.mode = 0444,
.fops = &transaction_log_fops,
@@ -6929,7 +6996,16 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = {
void binder_add_device(struct binder_device *device)
{
+ spin_lock(&binder_devices_lock);
hlist_add_head(&device->hlist, &binder_devices);
+ spin_unlock(&binder_devices_lock);
+}
+
+void binder_remove_device(struct binder_device *device)
+{
+ spin_lock(&binder_devices_lock);
+ hlist_del_init(&device->hlist);
+ spin_unlock(&binder_devices_lock);
}
static int __init init_binder_device(const char *name)
@@ -6956,7 +7032,7 @@ static int __init init_binder_device(const char *name)
return ret;
}
- hlist_add_head(&binder_device->hlist, &binder_devices);
+ binder_add_device(binder_device);
return ret;
}
@@ -7018,7 +7094,7 @@ static int __init binder_init(void)
err_init_binder_device_failed:
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
misc_deregister(&device->miscdev);
- hlist_del(&device->hlist);
+ binder_remove_device(device);
kfree(device);
}
diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h
index 6a66c9769c6c..1ba5caf1d88d 100644
--- a/drivers/android/binder_internal.h
+++ b/drivers/android/binder_internal.h
@@ -583,9 +583,13 @@ struct binder_object {
/**
* Add a binder device to binder_devices
* @device: the new binder device to add to the global list
- *
- * Not reentrant as the list is not protected by any locks
*/
void binder_add_device(struct binder_device *device);
+/**
+ * Remove a binder device to binder_devices
+ * @device: the binder device to remove from the global list
+ */
+void binder_remove_device(struct binder_device *device);
+
#endif /* _LINUX_BINDER_INTERNAL_H */
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 98da8c4eea59..024275dbfdd8 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -274,7 +274,7 @@ static void binderfs_evict_inode(struct inode *inode)
mutex_unlock(&binderfs_minors_mutex);
if (refcount_dec_and_test(&device->ref)) {
- hlist_del_init(&device->hlist);
+ binder_remove_device(device);
kfree(device->context.name);
kfree(device);
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 19fd55b8ac77..77c7a99f0870 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -638,6 +638,13 @@ static int dpm_async_with_cleanup(struct device *dev, void *fn)
static void dpm_async_resume_children(struct device *dev, async_func_t func)
{
/*
+ * Prevent racing with dpm_clear_async_state() during initial list
+ * walks in dpm_noirq_resume_devices(), dpm_resume_early(), and
+ * dpm_resume().
+ */
+ guard(mutex)(&dpm_list_mtx);
+
+ /*
* Start processing "async" children of the device unless it's been
* started already for them.
*
@@ -985,6 +992,8 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
if (!dev->power.is_suspended)
goto Complete;
+ dev->power.is_suspended = false;
+
if (dev->power.direct_complete) {
/*
* Allow new children to be added under the device after this
@@ -1047,7 +1056,6 @@ static void device_resume(struct device *dev, pm_message_t state, bool async)
End:
error = dpm_run_callback(callback, dev, state, info);
- dev->power.is_suspended = false;
device_unlock(dev);
dpm_watchdog_clear(&wd);
@@ -1451,7 +1459,7 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_late_early_list, &dpm_noirq_list);
+ list_splice_init(&dpm_late_early_list, &dpm_noirq_list);
break;
}
}
@@ -1653,7 +1661,7 @@ int dpm_suspend_late(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_suspended_list, &dpm_late_early_list);
+ list_splice_init(&dpm_suspended_list, &dpm_late_early_list);
break;
}
}
@@ -1946,7 +1954,7 @@ int dpm_suspend(pm_message_t state)
* Move all devices to the target list to resume them
* properly.
*/
- list_splice(&dpm_prepared_list, &dpm_suspended_list);
+ list_splice_init(&dpm_prepared_list, &dpm_suspended_list);
break;
}
}
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 805f75b35115..f626d5bbe806 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -945,6 +945,33 @@ unsigned int fwnode_get_child_node_count(const struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_get_child_node_count);
+/**
+ * fwnode_get_named_child_node_count - number of child nodes with given name
+ * @fwnode: Node which child nodes are counted.
+ * @name: String to match child node name against.
+ *
+ * Scan child nodes and count all the nodes with a specific name. Potential
+ * 'number' -ending after the 'at sign' for scanned names is ignored.
+ * E.g.::
+ * fwnode_get_named_child_node_count(fwnode, "channel");
+ * would match all the nodes::
+ * channel { }, channel@0 {}, channel@0xabba {}...
+ *
+ * Return: the number of child nodes with a matching name for a given device.
+ */
+unsigned int fwnode_get_named_child_node_count(const struct fwnode_handle *fwnode,
+ const char *name)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ fwnode_for_each_named_child_node(fwnode, child, name)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_child_node_count);
+
bool device_dma_supported(const struct device *dev)
{
return fwnode_call_bool_op(dev_fwnode(dev), device_dma_supported);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e2b1f377f585..f8d136684109 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -308,11 +308,14 @@ end_io:
static void lo_rw_aio_do_completion(struct loop_cmd *cmd)
{
struct request *rq = blk_mq_rq_from_pdu(cmd);
+ struct loop_device *lo = rq->q->queuedata;
if (!atomic_dec_and_test(&cmd->ref))
return;
kfree(cmd->bvec);
cmd->bvec = NULL;
+ if (req_op(rq) == REQ_OP_WRITE)
+ file_end_write(lo->lo_backing_file);
if (likely(!blk_should_fake_timeout(rq->q)))
blk_mq_complete_request(rq);
}
@@ -387,9 +390,10 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
cmd->iocb.ki_flags = 0;
}
- if (rw == ITER_SOURCE)
+ if (rw == ITER_SOURCE) {
+ file_start_write(lo->lo_backing_file);
ret = file->f_op->write_iter(&cmd->iocb, &iter);
- else
+ } else
ret = file->f_op->read_iter(&cmd->iocb, &iter);
lo_rw_aio_do_completion(cmd);
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 6f51072776f1..c637ea010d34 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -69,7 +69,8 @@
| UBLK_F_USER_RECOVERY_FAIL_IO \
| UBLK_F_UPDATE_SIZE \
| UBLK_F_AUTO_BUF_REG \
- | UBLK_F_QUIESCE)
+ | UBLK_F_QUIESCE \
+ | UBLK_F_PER_IO_DAEMON)
#define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
| UBLK_F_USER_RECOVERY_REISSUE \
@@ -166,6 +167,8 @@ struct ublk_io {
/* valid if UBLK_IO_FLAG_OWNED_BY_SRV is set */
struct request *req;
};
+
+ struct task_struct *task;
};
struct ublk_queue {
@@ -173,11 +176,9 @@ struct ublk_queue {
int q_depth;
unsigned long flags;
- struct task_struct *ubq_daemon;
struct ublksrv_io_desc *io_cmd_buf;
bool force_abort;
- bool timeout;
bool canceling;
bool fail_io; /* copy of dev->state == UBLK_S_DEV_FAIL_IO */
unsigned short nr_io_ready; /* how many ios setup */
@@ -1099,11 +1100,6 @@ static inline struct ublk_uring_cmd_pdu *ublk_get_uring_cmd_pdu(
return io_uring_cmd_to_pdu(ioucmd, struct ublk_uring_cmd_pdu);
}
-static inline bool ubq_daemon_is_dying(struct ublk_queue *ubq)
-{
- return !ubq->ubq_daemon || ubq->ubq_daemon->flags & PF_EXITING;
-}
-
/* todo: handle partial completion */
static inline void __ublk_complete_rq(struct request *req)
{
@@ -1275,13 +1271,13 @@ static void ublk_dispatch_req(struct ublk_queue *ubq,
/*
* Task is exiting if either:
*
- * (1) current != ubq_daemon.
+ * (1) current != io->task.
* io_uring_cmd_complete_in_task() tries to run task_work
- * in a workqueue if ubq_daemon(cmd's task) is PF_EXITING.
+ * in a workqueue if cmd's task is PF_EXITING.
*
* (2) current->flags & PF_EXITING.
*/
- if (unlikely(current != ubq->ubq_daemon || current->flags & PF_EXITING)) {
+ if (unlikely(current != io->task || current->flags & PF_EXITING)) {
__ublk_abort_rq(ubq, req);
return;
}
@@ -1330,24 +1326,22 @@ static void ublk_cmd_list_tw_cb(struct io_uring_cmd *cmd,
{
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
struct request *rq = pdu->req_list;
- struct ublk_queue *ubq = pdu->ubq;
struct request *next;
do {
next = rq->rq_next;
rq->rq_next = NULL;
- ublk_dispatch_req(ubq, rq, issue_flags);
+ ublk_dispatch_req(rq->mq_hctx->driver_data, rq, issue_flags);
rq = next;
} while (rq);
}
-static void ublk_queue_cmd_list(struct ublk_queue *ubq, struct rq_list *l)
+static void ublk_queue_cmd_list(struct ublk_io *io, struct rq_list *l)
{
- struct request *rq = rq_list_peek(l);
- struct io_uring_cmd *cmd = ubq->ios[rq->tag].cmd;
+ struct io_uring_cmd *cmd = io->cmd;
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
- pdu->req_list = rq;
+ pdu->req_list = rq_list_peek(l);
rq_list_init(l);
io_uring_cmd_complete_in_task(cmd, ublk_cmd_list_tw_cb);
}
@@ -1355,13 +1349,10 @@ static void ublk_queue_cmd_list(struct ublk_queue *ubq, struct rq_list *l)
static enum blk_eh_timer_return ublk_timeout(struct request *rq)
{
struct ublk_queue *ubq = rq->mq_hctx->driver_data;
+ struct ublk_io *io = &ubq->ios[rq->tag];
if (ubq->flags & UBLK_F_UNPRIVILEGED_DEV) {
- if (!ubq->timeout) {
- send_sig(SIGKILL, ubq->ubq_daemon, 0);
- ubq->timeout = true;
- }
-
+ send_sig(SIGKILL, io->task, 0);
return BLK_EH_DONE;
}
@@ -1429,24 +1420,25 @@ static void ublk_queue_rqs(struct rq_list *rqlist)
{
struct rq_list requeue_list = { };
struct rq_list submit_list = { };
- struct ublk_queue *ubq = NULL;
+ struct ublk_io *io = NULL;
struct request *req;
while ((req = rq_list_pop(rqlist))) {
struct ublk_queue *this_q = req->mq_hctx->driver_data;
+ struct ublk_io *this_io = &this_q->ios[req->tag];
- if (ubq && ubq != this_q && !rq_list_empty(&submit_list))
- ublk_queue_cmd_list(ubq, &submit_list);
- ubq = this_q;
+ if (io && io->task != this_io->task && !rq_list_empty(&submit_list))
+ ublk_queue_cmd_list(io, &submit_list);
+ io = this_io;
- if (ublk_prep_req(ubq, req, true) == BLK_STS_OK)
+ if (ublk_prep_req(this_q, req, true) == BLK_STS_OK)
rq_list_add_tail(&submit_list, req);
else
rq_list_add_tail(&requeue_list, req);
}
- if (ubq && !rq_list_empty(&submit_list))
- ublk_queue_cmd_list(ubq, &submit_list);
+ if (!rq_list_empty(&submit_list))
+ ublk_queue_cmd_list(io, &submit_list);
*rqlist = requeue_list;
}
@@ -1474,17 +1466,6 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq)
/* All old ioucmds have to be completed */
ubq->nr_io_ready = 0;
- /*
- * old daemon is PF_EXITING, put it now
- *
- * It could be NULL in case of closing one quisced device.
- */
- if (ubq->ubq_daemon)
- put_task_struct(ubq->ubq_daemon);
- /* We have to reset it to NULL, otherwise ub won't accept new FETCH_REQ */
- ubq->ubq_daemon = NULL;
- ubq->timeout = false;
-
for (i = 0; i < ubq->q_depth; i++) {
struct ublk_io *io = &ubq->ios[i];
@@ -1495,6 +1476,17 @@ static void ublk_queue_reinit(struct ublk_device *ub, struct ublk_queue *ubq)
io->flags &= UBLK_IO_FLAG_CANCELED;
io->cmd = NULL;
io->addr = 0;
+
+ /*
+ * old task is PF_EXITING, put it now
+ *
+ * It could be NULL in case of closing one quiesced
+ * device.
+ */
+ if (io->task) {
+ put_task_struct(io->task);
+ io->task = NULL;
+ }
}
}
@@ -1516,7 +1508,7 @@ static void ublk_reset_ch_dev(struct ublk_device *ub)
for (i = 0; i < ub->dev_info.nr_hw_queues; i++)
ublk_queue_reinit(ub, ublk_get_queue(ub, i));
- /* set to NULL, otherwise new ubq_daemon cannot mmap the io_cmd_buf */
+ /* set to NULL, otherwise new tasks cannot mmap io_cmd_buf */
ub->mm = NULL;
ub->nr_queues_ready = 0;
ub->nr_privileged_daemon = 0;
@@ -1783,6 +1775,7 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd,
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
struct ublk_queue *ubq = pdu->ubq;
struct task_struct *task;
+ struct ublk_io *io;
if (WARN_ON_ONCE(!ubq))
return;
@@ -1791,13 +1784,14 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd,
return;
task = io_uring_cmd_get_task(cmd);
- if (WARN_ON_ONCE(task && task != ubq->ubq_daemon))
+ io = &ubq->ios[pdu->tag];
+ if (WARN_ON_ONCE(task && task != io->task))
return;
if (!ubq->canceling)
ublk_start_cancel(ubq);
- WARN_ON_ONCE(ubq->ios[pdu->tag].cmd != cmd);
+ WARN_ON_ONCE(io->cmd != cmd);
ublk_cancel_cmd(ubq, pdu->tag, issue_flags);
}
@@ -1930,8 +1924,6 @@ static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq)
{
ubq->nr_io_ready++;
if (ublk_queue_ready(ubq)) {
- ubq->ubq_daemon = current;
- get_task_struct(ubq->ubq_daemon);
ub->nr_queues_ready++;
if (capable(CAP_SYS_ADMIN))
@@ -2084,6 +2076,7 @@ static int ublk_fetch(struct io_uring_cmd *cmd, struct ublk_queue *ubq,
}
ublk_fill_io_cmd(io, cmd, buf_addr);
+ WRITE_ONCE(io->task, get_task_struct(current));
ublk_mark_io_ready(ub, ubq);
out:
mutex_unlock(&ub->mutex);
@@ -2179,6 +2172,7 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
const struct ublksrv_io_cmd *ub_cmd)
{
struct ublk_device *ub = cmd->file->private_data;
+ struct task_struct *task;
struct ublk_queue *ubq;
struct ublk_io *io;
u32 cmd_op = cmd->cmd_op;
@@ -2193,13 +2187,14 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
goto out;
ubq = ublk_get_queue(ub, ub_cmd->q_id);
- if (ubq->ubq_daemon && ubq->ubq_daemon != current)
- goto out;
if (tag >= ubq->q_depth)
goto out;
io = &ubq->ios[tag];
+ task = READ_ONCE(io->task);
+ if (task && task != current)
+ goto out;
/* there is pending io cmd, something must be wrong */
if (io->flags & UBLK_IO_FLAG_ACTIVE) {
@@ -2449,9 +2444,14 @@ static void ublk_deinit_queue(struct ublk_device *ub, int q_id)
{
int size = ublk_queue_cmd_buf_size(ub, q_id);
struct ublk_queue *ubq = ublk_get_queue(ub, q_id);
+ int i;
+
+ for (i = 0; i < ubq->q_depth; i++) {
+ struct ublk_io *io = &ubq->ios[i];
+ if (io->task)
+ put_task_struct(io->task);
+ }
- if (ubq->ubq_daemon)
- put_task_struct(ubq->ubq_daemon);
if (ubq->io_cmd_buf)
free_pages((unsigned long)ubq->io_cmd_buf, get_order(size));
}
@@ -2923,7 +2923,8 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
ub->dev_info.flags &= UBLK_F_ALL;
ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
- UBLK_F_URING_CMD_COMP_IN_TASK;
+ UBLK_F_URING_CMD_COMP_IN_TASK |
+ UBLK_F_PER_IO_DAEMON;
/* GET_DATA isn't needed any more with USER_COPY or ZERO COPY */
if (ub->dev_info.flags & (UBLK_F_USER_COPY | UBLK_F_SUPPORT_ZERO_COPY |
@@ -3188,14 +3189,14 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
int ublksrv_pid = (int)header->data[0];
int ret = -EINVAL;
- pr_devel("%s: Waiting for new ubq_daemons(nr: %d) are ready, dev id %d...\n",
- __func__, ub->dev_info.nr_hw_queues, header->dev_id);
- /* wait until new ubq_daemon sending all FETCH_REQ */
+ pr_devel("%s: Waiting for all FETCH_REQs, dev id %d...\n", __func__,
+ header->dev_id);
+
if (wait_for_completion_interruptible(&ub->completion))
return -EINTR;
- pr_devel("%s: All new ubq_daemons(nr: %d) are ready, dev id %d\n",
- __func__, ub->dev_info.nr_hw_queues, header->dev_id);
+ pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
+ header->dev_id);
mutex_lock(&ub->mutex);
if (ublk_nosrv_should_stop_dev(ub))
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index b34623a69b8a..6b13feed06df 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -533,6 +533,8 @@ static int ps_setup(struct hci_dev *hdev)
ps_host_wakeup_irq_handler,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
dev_name(&serdev->dev), nxpdev);
+ if (ret)
+ bt_dev_info(hdev, "error setting wakeup IRQ handler, ignoring\n");
disable_irq(psdata->irq_handler);
device_init_wakeup(&serdev->dev, true);
}
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index e00590ba24fd..a2dc39c005f4 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2415,14 +2415,14 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
- if (IS_ERR(qcadev->bt_en) &&
- (data->soc_type == QCA_WCN6750 ||
- data->soc_type == QCA_WCN6855)) {
- dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
- return PTR_ERR(qcadev->bt_en);
- }
+ if (IS_ERR(qcadev->bt_en))
+ return dev_err_probe(&serdev->dev,
+ PTR_ERR(qcadev->bt_en),
+ "failed to acquire BT_EN gpio\n");
- if (!qcadev->bt_en)
+ if (!qcadev->bt_en &&
+ (data->soc_type == QCA_WCN6750 ||
+ data->soc_type == QCA_WCN6855))
power_ctrl_enabled = false;
qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c
index aeb53b2c34a8..26357ee68dee 100644
--- a/drivers/bus/mhi/ep/ring.c
+++ b/drivers/bus/mhi/ep/ring.c
@@ -131,19 +131,23 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e
}
old_offset = ring->rd_offset;
- mhi_ep_ring_inc_index(ring);
dev_dbg(dev, "Adding an element to ring at offset (%zu)\n", ring->rd_offset);
+ buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el));
+ buf_info.dev_addr = el;
+ buf_info.size = sizeof(*el);
+
+ ret = mhi_cntrl->write_sync(mhi_cntrl, &buf_info);
+ if (ret)
+ return ret;
+
+ mhi_ep_ring_inc_index(ring);
/* Update rp in ring context */
rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase);
memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64));
- buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el));
- buf_info.dev_addr = el;
- buf_info.size = sizeof(*el);
-
- return mhi_cntrl->write_sync(mhi_cntrl, &buf_info);
+ return ret;
}
void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id)
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index 03aa88795209..a4a62429c784 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -782,6 +782,42 @@ static const struct mhi_pci_dev_info mhi_telit_fe990a_info = {
.mru_default = 32768,
};
+static const struct mhi_channel_config mhi_telit_fn920c04_channels[] = {
+ MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0),
+ MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0),
+ MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 1),
+ MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 1),
+ MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0),
+ MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0),
+ MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
+ MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
+ MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0),
+ MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
+ MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1),
+ MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1),
+ MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
+ MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
+};
+
+static const struct mhi_controller_config modem_telit_fn920c04_config = {
+ .max_channels = 128,
+ .timeout_ms = 50000,
+ .num_channels = ARRAY_SIZE(mhi_telit_fn920c04_channels),
+ .ch_cfg = mhi_telit_fn920c04_channels,
+ .num_events = ARRAY_SIZE(mhi_telit_fn990_events),
+ .event_cfg = mhi_telit_fn990_events,
+};
+
+static const struct mhi_pci_dev_info mhi_telit_fn920c04_info = {
+ .name = "telit-fn920c04",
+ .config = &modem_telit_fn920c04_config,
+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
+ .dma_data_width = 32,
+ .sideband_wake = false,
+ .mru_default = 32768,
+ .edl_trigger = true,
+};
+
static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = {
.name = "netprisma-lcur57",
.edl = "qcom/prog_firehose_sdx24.mbn",
@@ -806,6 +842,9 @@ static const struct mhi_pci_dev_info mhi_netprisma_fcun69_info = {
static const struct pci_device_id mhi_pci_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0116),
.driver_data = (kernel_ulong_t) &mhi_qcom_sa8775p_info },
+ /* Telit FN920C04 (sdx35) */
+ {PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x011a, 0x1c5d, 0x2020),
+ .driver_data = (kernel_ulong_t) &mhi_telit_fn920c04_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c),
@@ -996,10 +1035,6 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
int err;
- err = pci_assign_resource(pdev, bar_num);
- if (err)
- return err;
-
err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "failed to enable pci device: %d\n", err);
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index 2fb27e6f8f88..33d92bf2fc3e 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -602,6 +602,7 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
struct mhi_cmd *mhi_cmd;
struct mhi_event_ctxt *er_ctxt;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ bool reset_device = false;
int ret, i;
dev_dbg(dev, "Transitioning from PM state: %s to: %s\n",
@@ -630,8 +631,23 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
/* Wake up threads waiting for state transition */
wake_up_all(&mhi_cntrl->state_event);
- /* Trigger MHI RESET so that the device will not access host memory */
if (MHI_REG_ACCESS_VALID(prev_state)) {
+ /*
+ * If the device is in PBL or SBL, it will only respond to
+ * RESET if the device is in SYSERR state. SYSERR might
+ * already be cleared at this point.
+ */
+ enum mhi_state cur_state = mhi_get_mhi_state(mhi_cntrl);
+ enum mhi_ee_type cur_ee = mhi_get_exec_env(mhi_cntrl);
+
+ if (cur_state == MHI_STATE_SYS_ERR)
+ reset_device = true;
+ else if (cur_ee != MHI_EE_PBL && cur_ee != MHI_EE_SBL)
+ reset_device = true;
+ }
+
+ /* Trigger MHI RESET so that the device will not access host memory */
+ if (reset_device) {
u32 in_reset = -1;
unsigned long timeout = msecs_to_jiffies(mhi_cntrl->timeout_ms);
diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c
index 06d723978232..3388a5d1462c 100644
--- a/drivers/cdx/cdx_msi.c
+++ b/drivers/cdx/cdx_msi.c
@@ -165,7 +165,7 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev)
struct device_node *parent_node;
struct irq_domain *parent;
- fwnode_handle = of_node_to_fwnode(np);
+ fwnode_handle = of_fwnode_handle(np);
parent_node = of_parse_phandle(np, "msi-map", 1);
if (!parent_node) {
@@ -173,7 +173,7 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev)
return NULL;
}
- parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS);
+ parent = irq_find_matching_fwnode(of_fwnode_handle(parent_node), DOMAIN_BUS_NEXUS);
if (!parent || !msi_get_domain_info(parent)) {
dev_err(dev, "unable to locate ITS domain\n");
return NULL;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 8fb33c90482f..ae6196760556 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -404,7 +404,7 @@ config TELCLOCK
configuration of the telecom clock configuration settings. This
device is used for hardware synchronization across the ATCA backplane
fabric. Upon loading, the driver exports a sysfs directory,
- /sys/devices/platform/telco_clock, with a number of files for
+ /sys/devices/faux/telco_clock, with a number of files for
controlling the behavior of this hardware.
source "drivers/s390/char/Kconfig"
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index e795390b070f..53ce352f7197 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -141,9 +141,6 @@ static struct apm_queue kapmd_queue;
static DEFINE_MUTEX(state_lock);
-static const char driver_version[] = "1.13"; /* no spaces */
-
-
/*
* Compatibility cruft until the IPAQ people move over to the new
@@ -435,6 +432,8 @@ static struct miscdevice apm_device = {
*/
static int proc_apm_show(struct seq_file *m, void *v)
{
+ static const char driver_version[] = "1.13"; /* no spaces */
+
struct apm_power_info info;
char *units;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e110857824fc..0713ea2b2a51 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -1023,8 +1023,7 @@ static int __init hpet_init(void)
result = acpi_bus_register_driver(&hpet_acpi_driver);
if (result < 0) {
- if (sysctl_header)
- unregister_sysctl_table(sysctl_header);
+ unregister_sysctl_table(sysctl_header);
misc_deregister(&hpet_misc);
return result;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index dda466f9181a..d5accc10a110 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -58,9 +58,8 @@ static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);
/*
- * Assigned numbers, used for dynamic minors
+ * Assigned numbers.
*/
-#define DYNAMIC_MINORS 128 /* like dynamic majors */
static DEFINE_IDA(misc_minors_ida);
static int misc_minor_alloc(int minor)
@@ -69,34 +68,17 @@ static int misc_minor_alloc(int minor)
if (minor == MISC_DYNAMIC_MINOR) {
/* allocate free id */
- ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
- if (ret >= 0) {
- ret = DYNAMIC_MINORS - ret - 1;
- } else {
- ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
- MINORMASK, GFP_KERNEL);
- }
+ ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
+ MINORMASK, GFP_KERNEL);
} else {
- /* specific minor, check if it is in dynamic or misc dynamic range */
- if (minor < DYNAMIC_MINORS) {
- minor = DYNAMIC_MINORS - minor - 1;
- ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
- } else if (minor > MISC_DYNAMIC_MINOR) {
- ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
- } else {
- /* case of non-dynamic minors, no need to allocate id */
- ret = 0;
- }
+ ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
}
return ret;
}
static void misc_minor_free(int minor)
{
- if (minor < DYNAMIC_MINORS)
- ida_free(&misc_minors_ida, DYNAMIC_MINORS - minor - 1);
- else if (minor > MISC_DYNAMIC_MINOR)
- ida_free(&misc_minors_ida, minor);
+ ida_free(&misc_minors_ida, minor);
}
#ifdef CONFIG_PROC_FS
diff --git a/drivers/char/xillybus/xillybus_core.c b/drivers/char/xillybus/xillybus_core.c
index 11b7c4749274..efb1ae834265 100644
--- a/drivers/char/xillybus/xillybus_core.c
+++ b/drivers/char/xillybus/xillybus_core.c
@@ -1184,8 +1184,7 @@ static int xillybus_flush(struct file *filp, fl_owner_t id)
static void xillybus_autoflush(struct work_struct *work)
{
- struct delayed_work *workitem = container_of(
- work, struct delayed_work, work);
+ struct delayed_work *workitem = to_delayed_work(work);
struct xilly_channel *channel = container_of(
workitem, struct xilly_channel, rd_workitem);
int rc;
diff --git a/drivers/comedi/comedi_buf.c b/drivers/comedi/comedi_buf.c
index 393966c09740..002c0e76baff 100644
--- a/drivers/comedi/comedi_buf.c
+++ b/drivers/comedi/comedi_buf.c
@@ -27,14 +27,12 @@ static void comedi_buf_map_kref_release(struct kref *kref)
if (bm->page_list) {
if (bm->dma_dir != DMA_NONE) {
- /*
- * DMA buffer was allocated as a single block.
- * Address is in page_list[0].
- */
- buf = &bm->page_list[0];
- dma_free_coherent(bm->dma_hw_dev,
- PAGE_SIZE * bm->n_pages,
- buf->virt_addr, buf->dma_addr);
+ for (i = 0; i < bm->n_pages; i++) {
+ buf = &bm->page_list[i];
+ dma_free_coherent(bm->dma_hw_dev, PAGE_SIZE,
+ buf->virt_addr,
+ buf->dma_addr);
+ }
} else {
for (i = 0; i < bm->n_pages; i++) {
buf = &bm->page_list[i];
@@ -56,13 +54,7 @@ static void __comedi_buf_free(struct comedi_device *dev,
struct comedi_buf_map *bm;
unsigned long flags;
- if (async->prealloc_buf) {
- if (s->async_dma_dir == DMA_NONE)
- vunmap(async->prealloc_buf);
- async->prealloc_buf = NULL;
- async->prealloc_bufsz = 0;
- }
-
+ async->prealloc_bufsz = 0;
spin_lock_irqsave(&s->spin_lock, flags);
bm = async->buf_map;
async->buf_map = NULL;
@@ -94,26 +86,14 @@ comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
goto err;
if (bm->dma_dir != DMA_NONE) {
- void *virt_addr;
- dma_addr_t dma_addr;
-
- /*
- * Currently, the DMA buffer needs to be allocated as a
- * single block so that it can be mmap()'ed.
- */
- virt_addr = dma_alloc_coherent(bm->dma_hw_dev,
- PAGE_SIZE * n_pages, &dma_addr,
- GFP_KERNEL);
- if (!virt_addr)
- goto err;
-
for (i = 0; i < n_pages; i++) {
buf = &bm->page_list[i];
- buf->virt_addr = virt_addr + (i << PAGE_SHIFT);
- buf->dma_addr = dma_addr + (i << PAGE_SHIFT);
+ buf->virt_addr =
+ dma_alloc_coherent(bm->dma_hw_dev, PAGE_SIZE,
+ &buf->dma_addr, GFP_KERNEL);
+ if (!buf->virt_addr)
+ break;
}
-
- bm->n_pages = i;
} else {
for (i = 0; i < n_pages; i++) {
buf = &bm->page_list[i];
@@ -123,11 +103,10 @@ comedi_buf_map_alloc(struct comedi_device *dev, enum dma_data_direction dma_dir,
SetPageReserved(virt_to_page(buf->virt_addr));
}
-
- bm->n_pages = i;
- if (i < n_pages)
- goto err;
}
+ bm->n_pages = i;
+ if (i < n_pages)
+ goto err;
return bm;
@@ -141,11 +120,8 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
unsigned int n_pages)
{
struct comedi_async *async = s->async;
- struct page **pages = NULL;
struct comedi_buf_map *bm;
- struct comedi_buf_page *buf;
unsigned long flags;
- unsigned int i;
if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) {
dev_err(dev->class_dev,
@@ -160,30 +136,7 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
spin_lock_irqsave(&s->spin_lock, flags);
async->buf_map = bm;
spin_unlock_irqrestore(&s->spin_lock, flags);
-
- if (bm->dma_dir != DMA_NONE) {
- /*
- * DMA buffer was allocated as a single block.
- * Address is in page_list[0].
- */
- buf = &bm->page_list[0];
- async->prealloc_buf = buf->virt_addr;
- } else {
- pages = vmalloc(sizeof(struct page *) * n_pages);
- if (!pages)
- return;
-
- for (i = 0; i < n_pages; i++) {
- buf = &bm->page_list[i];
- pages[i] = virt_to_page(buf->virt_addr);
- }
-
- /* vmap the pages to prealloc_buf */
- async->prealloc_buf = vmap(pages, n_pages, VM_MAP,
- COMEDI_PAGE_PROTECTION);
-
- vfree(pages);
- }
+ async->prealloc_bufsz = n_pages << PAGE_SHIFT;
}
void comedi_buf_map_get(struct comedi_buf_map *bm)
@@ -264,7 +217,7 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
/* if no change is required, do nothing */
- if (async->prealloc_buf && async->prealloc_bufsz == new_size)
+ if (async->prealloc_bufsz == new_size)
return 0;
/* deallocate old buffer */
@@ -275,14 +228,9 @@ int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int n_pages = new_size >> PAGE_SHIFT;
__comedi_buf_alloc(dev, s, n_pages);
-
- if (!async->prealloc_buf) {
- /* allocation failed */
- __comedi_buf_free(dev, s);
+ if (!async->prealloc_bufsz)
return -ENOMEM;
- }
}
- async->prealloc_bufsz = new_size;
return 0;
}
@@ -365,6 +313,7 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
unsigned int num_bytes)
{
struct comedi_async *async = s->async;
+ struct comedi_buf_page *buf_page_list = async->buf_map->page_list;
unsigned int count = 0;
const unsigned int num_sample_bytes = comedi_bytes_per_sample(s);
@@ -376,15 +325,16 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
/* don't munge partial samples */
num_bytes -= num_bytes % num_sample_bytes;
while (count < num_bytes) {
- int block_size = num_bytes - count;
- unsigned int buf_end;
-
- buf_end = async->prealloc_bufsz - async->munge_ptr;
- if (block_size > buf_end)
- block_size = buf_end;
+ /*
+ * Do not munge beyond page boundary.
+ * Note: prealloc_bufsz is a multiple of PAGE_SIZE.
+ */
+ unsigned int page = async->munge_ptr >> PAGE_SHIFT;
+ unsigned int offset = offset_in_page(async->munge_ptr);
+ unsigned int block_size =
+ min(num_bytes - count, PAGE_SIZE - offset);
- s->munge(s->device, s,
- async->prealloc_buf + async->munge_ptr,
+ s->munge(s->device, s, buf_page_list[page].virt_addr + offset,
block_size, async->munge_chan);
/*
@@ -397,7 +347,8 @@ static unsigned int comedi_buf_munge(struct comedi_subdevice *s,
async->munge_chan %= async->cmd.chanlist_len;
async->munge_count += block_size;
async->munge_ptr += block_size;
- async->munge_ptr %= async->prealloc_bufsz;
+ if (async->munge_ptr == async->prealloc_bufsz)
+ async->munge_ptr = 0;
count += block_size;
}
@@ -558,46 +509,52 @@ static void comedi_buf_memcpy_to(struct comedi_subdevice *s,
const void *data, unsigned int num_bytes)
{
struct comedi_async *async = s->async;
+ struct comedi_buf_page *buf_page_list = async->buf_map->page_list;
unsigned int write_ptr = async->buf_write_ptr;
while (num_bytes) {
- unsigned int block_size;
-
- if (write_ptr + num_bytes > async->prealloc_bufsz)
- block_size = async->prealloc_bufsz - write_ptr;
- else
- block_size = num_bytes;
+ /*
+ * Do not copy beyond page boundary.
+ * Note: prealloc_bufsz is a multiple of PAGE_SIZE.
+ */
+ unsigned int page = write_ptr >> PAGE_SHIFT;
+ unsigned int offset = offset_in_page(write_ptr);
+ unsigned int block_size = min(num_bytes, PAGE_SIZE - offset);
- memcpy(async->prealloc_buf + write_ptr, data, block_size);
+ memcpy(buf_page_list[page].virt_addr + offset,
+ data, block_size);
data += block_size;
num_bytes -= block_size;
-
- write_ptr = 0;
+ write_ptr += block_size;
+ if (write_ptr == async->prealloc_bufsz)
+ write_ptr = 0;
}
}
static void comedi_buf_memcpy_from(struct comedi_subdevice *s,
void *dest, unsigned int nbytes)
{
- void *src;
struct comedi_async *async = s->async;
+ struct comedi_buf_page *buf_page_list = async->buf_map->page_list;
unsigned int read_ptr = async->buf_read_ptr;
while (nbytes) {
- unsigned int block_size;
-
- src = async->prealloc_buf + read_ptr;
-
- if (nbytes >= async->prealloc_bufsz - read_ptr)
- block_size = async->prealloc_bufsz - read_ptr;
- else
- block_size = nbytes;
+ /*
+ * Do not copy beyond page boundary.
+ * Note: prealloc_bufsz is a multiple of PAGE_SIZE.
+ */
+ unsigned int page = read_ptr >> PAGE_SHIFT;
+ unsigned int offset = offset_in_page(read_ptr);
+ unsigned int block_size = min(nbytes, PAGE_SIZE - offset);
- memcpy(dest, src, block_size);
+ memcpy(dest, buf_page_list[page].virt_addr + offset,
+ block_size);
nbytes -= block_size;
dest += block_size;
- read_ptr = 0;
+ read_ptr += block_size;
+ if (read_ptr == async->prealloc_bufsz)
+ read_ptr = 0;
}
}
diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c
index b9df9b19d4bd..3383a7ce27ff 100644
--- a/drivers/comedi/comedi_fops.c
+++ b/drivers/comedi/comedi_fops.c
@@ -2387,13 +2387,27 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
goto done;
}
if (bm->dma_dir != DMA_NONE) {
+ unsigned long vm_start = vma->vm_start;
+ unsigned long vm_end = vma->vm_end;
+
/*
- * DMA buffer was allocated as a single block.
- * Address is in page_list[0].
+ * Buffer pages are not contiguous, so temporarily modify VMA
+ * start and end addresses for each buffer page.
*/
- buf = &bm->page_list[0];
- retval = dma_mmap_coherent(bm->dma_hw_dev, vma, buf->virt_addr,
- buf->dma_addr, n_pages * PAGE_SIZE);
+ for (i = 0; i < n_pages; ++i) {
+ buf = &bm->page_list[i];
+ vma->vm_start = start;
+ vma->vm_end = start + PAGE_SIZE;
+ retval = dma_mmap_coherent(bm->dma_hw_dev, vma,
+ buf->virt_addr,
+ buf->dma_addr, PAGE_SIZE);
+ if (retval)
+ break;
+
+ start += PAGE_SIZE;
+ }
+ vma->vm_start = vm_start;
+ vma->vm_end = vm_end;
} else {
for (i = 0; i < n_pages; ++i) {
unsigned long pfn;
@@ -2407,19 +2421,18 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
start += PAGE_SIZE;
}
+ }
#ifdef CONFIG_MMU
- /*
- * Leaving behind a partial mapping of a buffer we're about to
- * drop is unsafe, see remap_pfn_range_notrack().
- * We need to zap the range here ourselves instead of relying
- * on the automatic zapping in remap_pfn_range() because we call
- * remap_pfn_range() in a loop.
- */
- if (retval)
- zap_vma_ptes(vma, vma->vm_start, size);
+ /*
+ * Leaving behind a partial mapping of a buffer we're about to drop is
+ * unsafe, see remap_pfn_range_notrack(). We need to zap the range
+ * here ourselves instead of relying on the automatic zapping in
+ * remap_pfn_range() because we call remap_pfn_range() in a loop.
+ */
+ if (retval)
+ zap_vma_ptes(vma, vma->vm_start, size);
#endif
- }
if (retval == 0) {
vma->vm_ops = &comedi_vm_ops;
@@ -2475,6 +2488,62 @@ done:
return mask;
}
+static unsigned int comedi_buf_copy_to_user(struct comedi_subdevice *s,
+ void __user *dest, unsigned int src_offset, unsigned int n)
+{
+ struct comedi_buf_map *bm = s->async->buf_map;
+ struct comedi_buf_page *buf_page_list = bm->page_list;
+ unsigned int page = src_offset >> PAGE_SHIFT;
+ unsigned int offset = offset_in_page(src_offset);
+
+ while (n) {
+ unsigned int copy_amount = min(n, PAGE_SIZE - offset);
+ unsigned int uncopied;
+
+ uncopied = copy_to_user(dest, buf_page_list[page].virt_addr +
+ offset, copy_amount);
+ copy_amount -= uncopied;
+ n -= copy_amount;
+ if (uncopied)
+ break;
+
+ dest += copy_amount;
+ page++;
+ if (page == bm->n_pages)
+ page = 0; /* buffer wraparound */
+ offset = 0;
+ }
+ return n;
+}
+
+static unsigned int comedi_buf_copy_from_user(struct comedi_subdevice *s,
+ unsigned int dst_offset, const void __user *src, unsigned int n)
+{
+ struct comedi_buf_map *bm = s->async->buf_map;
+ struct comedi_buf_page *buf_page_list = bm->page_list;
+ unsigned int page = dst_offset >> PAGE_SHIFT;
+ unsigned int offset = offset_in_page(dst_offset);
+
+ while (n) {
+ unsigned int copy_amount = min(n, PAGE_SIZE - offset);
+ unsigned int uncopied;
+
+ uncopied = copy_from_user(buf_page_list[page].virt_addr +
+ offset, src, copy_amount);
+ copy_amount -= uncopied;
+ n -= copy_amount;
+ if (uncopied)
+ break;
+
+ src += copy_amount;
+ page++;
+ if (page == bm->n_pages)
+ page = 0; /* buffer wraparound */
+ offset = 0;
+ }
+ return n;
+}
+
static ssize_t comedi_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *offset)
{
@@ -2516,7 +2585,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
add_wait_queue(&async->wait_head, &wait);
while (count == 0 && !retval) {
unsigned int runflags;
- unsigned int wp, n1, n2;
set_current_state(TASK_INTERRUPTIBLE);
@@ -2555,14 +2623,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
}
set_current_state(TASK_RUNNING);
- wp = async->buf_write_ptr;
- n1 = min(n, async->prealloc_bufsz - wp);
- n2 = n - n1;
- m = copy_from_user(async->prealloc_buf + wp, buf, n1);
- if (m)
- m += n2;
- else if (n2)
- m = copy_from_user(async->prealloc_buf, buf + n1, n2);
+ m = comedi_buf_copy_from_user(s, async->buf_write_ptr, buf, n);
if (m) {
n -= m;
retval = -EFAULT;
@@ -2651,8 +2712,6 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
add_wait_queue(&async->wait_head, &wait);
while (count == 0 && !retval) {
- unsigned int rp, n1, n2;
-
set_current_state(TASK_INTERRUPTIBLE);
m = comedi_buf_read_n_available(s);
@@ -2689,14 +2748,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
}
set_current_state(TASK_RUNNING);
- rp = async->buf_read_ptr;
- n1 = min(n, async->prealloc_bufsz - rp);
- n2 = n - n1;
- m = copy_to_user(buf, async->prealloc_buf + rp, n1);
- if (m)
- m += n2;
- else if (n2)
- m = copy_to_user(buf + n1, async->prealloc_buf, n2);
+ m = comedi_buf_copy_to_user(s, buf, async->buf_read_ptr, n);
if (m) {
n -= m;
retval = -EFAULT;
diff --git a/drivers/comedi/drivers/adl_pci9118.c b/drivers/comedi/drivers/adl_pci9118.c
index a76e2666d583..67c663892e48 100644
--- a/drivers/comedi/drivers/adl_pci9118.c
+++ b/drivers/comedi/drivers/adl_pci9118.c
@@ -32,7 +32,7 @@
* ranges).
*
* There are some hardware limitations:
- * a) You cann't use mixture of unipolar/bipoar ranges or differencial/single
+ * a) You can't use mixture of unipolar/bipolar ranges or differential/single
* ended inputs.
* b) DMA transfers must have the length aligned to two samples (32 bit),
* so there is some problems if cmd->chanlist_len is odd. This driver tries
@@ -227,7 +227,7 @@ struct pci9118_private {
struct pci9118_dmabuf dmabuf[2];
int softsshdelay; /*
* >0 use software S&H,
- * numer is requested delay in ns
+ * number is requested delay in ns
*/
unsigned char softsshsample; /*
* polarity of S&H signal
diff --git a/drivers/comedi/drivers/ni_atmio.c b/drivers/comedi/drivers/ni_atmio.c
index 330ae1c58800..b4e759e5703f 100644
--- a/drivers/comedi/drivers/ni_atmio.c
+++ b/drivers/comedi/drivers/ni_atmio.c
@@ -215,7 +215,7 @@ static const int ni_irqpin[] = {
#include "ni_mio_common.c"
-static const struct pnp_device_id device_ids[] = {
+static const struct pnp_device_id __maybe_unused device_ids[] = {
{.id = "NIC1900", .driver_data = 0},
{.id = "NIC2400", .driver_data = 0},
{.id = "NIC2500", .driver_data = 0},
diff --git a/drivers/comedi/drivers/ni_pcidio.c b/drivers/comedi/drivers/ni_pcidio.c
index 2d58e83420e8..2c7bb9c1ea5b 100644
--- a/drivers/comedi/drivers/ni_pcidio.c
+++ b/drivers/comedi/drivers/ni_pcidio.c
@@ -747,8 +747,6 @@ static int ni_pcidio_change(struct comedi_device *dev,
if (ret < 0)
return ret;
- memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz);
-
return 0;
}
diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c
index 949598d51575..6c0c1d2d7027 100644
--- a/drivers/counter/interrupt-cnt.c
+++ b/drivers/counter/interrupt-cnt.c
@@ -3,22 +3,25 @@
* Copyright (c) 2021 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/
+#include <linux/cleanup.h>
#include <linux/counter.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#define INTERRUPT_CNT_NAME "interrupt-cnt"
struct interrupt_cnt_priv {
- atomic_t count;
+ atomic_long_t count;
struct gpio_desc *gpio;
int irq;
bool enabled;
+ struct mutex lock;
struct counter_signal signals;
struct counter_synapse synapses;
struct counter_count cnts;
@@ -29,7 +32,7 @@ static irqreturn_t interrupt_cnt_isr(int irq, void *dev_id)
struct counter_device *counter = dev_id;
struct interrupt_cnt_priv *priv = counter_priv(counter);
- atomic_inc(&priv->count);
+ atomic_long_inc(&priv->count);
counter_push_event(counter, COUNTER_EVENT_CHANGE_OF_STATE, 0);
@@ -41,6 +44,8 @@ static int interrupt_cnt_enable_read(struct counter_device *counter,
{
struct interrupt_cnt_priv *priv = counter_priv(counter);
+ guard(mutex)(&priv->lock);
+
*enable = priv->enabled;
return 0;
@@ -51,6 +56,8 @@ static int interrupt_cnt_enable_write(struct counter_device *counter,
{
struct interrupt_cnt_priv *priv = counter_priv(counter);
+ guard(mutex)(&priv->lock);
+
if (priv->enabled == enable)
return 0;
@@ -89,7 +96,7 @@ static int interrupt_cnt_read(struct counter_device *counter,
{
struct interrupt_cnt_priv *priv = counter_priv(counter);
- *val = atomic_read(&priv->count);
+ *val = atomic_long_read(&priv->count);
return 0;
}
@@ -102,7 +109,7 @@ static int interrupt_cnt_write(struct counter_device *counter,
if (val != (typeof(priv->count.counter))val)
return -ERANGE;
- atomic_set(&priv->count, val);
+ atomic_long_set(&priv->count, val);
return 0;
}
@@ -227,6 +234,8 @@ static int interrupt_cnt_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mutex_init(&priv->lock);
+
ret = devm_counter_add(dev, counter);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to add counter\n");
diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c
index 1de3c50b9804..1a299d1f350b 100644
--- a/drivers/counter/microchip-tcb-capture.c
+++ b/drivers/counter/microchip-tcb-capture.c
@@ -337,6 +337,28 @@ static struct counter_comp mchp_tc_count_ext[] = {
COUNTER_COMP_COMPARE(mchp_tc_count_compare_read, mchp_tc_count_compare_write),
};
+static int mchp_tc_watch_validate(struct counter_device *counter,
+ const struct counter_watch *watch)
+{
+ if (watch->channel == COUNTER_MCHP_EVCHN_CV || watch->channel == COUNTER_MCHP_EVCHN_RA)
+ switch (watch->event) {
+ case COUNTER_EVENT_CHANGE_OF_STATE:
+ case COUNTER_EVENT_OVERFLOW:
+ case COUNTER_EVENT_CAPTURE:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ if (watch->channel == COUNTER_MCHP_EVCHN_RB && watch->event == COUNTER_EVENT_CAPTURE)
+ return 0;
+
+ if (watch->channel == COUNTER_MCHP_EVCHN_RC && watch->event == COUNTER_EVENT_THRESHOLD)
+ return 0;
+
+ return -EINVAL;
+}
+
static struct counter_count mchp_tc_counts[] = {
{
.id = 0,
@@ -356,7 +378,8 @@ static const struct counter_ops mchp_tc_ops = {
.function_read = mchp_tc_count_function_read,
.function_write = mchp_tc_count_function_write,
.action_read = mchp_tc_count_action_read,
- .action_write = mchp_tc_count_action_write
+ .action_write = mchp_tc_count_action_write,
+ .watch_validate = mchp_tc_watch_validate,
};
static const struct atmel_tcb_config tcb_rm9200_config = {
diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c
index e75b69476a00..3d3384cbea87 100644
--- a/drivers/counter/stm32-timer-cnt.c
+++ b/drivers/counter/stm32-timer-cnt.c
@@ -669,12 +669,14 @@ static void stm32_timer_cnt_detect_channels(struct device *dev,
dev_dbg(dev, "has %d cc channels\n", priv->nchannels);
}
-/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */
-#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7))
+/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 TIM20 */
+#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7) | \
+ BIT(19))
static const char * const stm32_timer_trigger_compat[] = {
"st,stm32-timer-trigger",
"st,stm32h7-timer-trigger",
+ "st,stm32mp25-timer-trigger",
};
static int stm32_timer_cnt_probe_encoder(struct device *dev,
@@ -846,6 +848,7 @@ static SIMPLE_DEV_PM_OPS(stm32_timer_cnt_pm_ops, stm32_timer_cnt_suspend,
static const struct of_device_id stm32_timer_cnt_of_match[] = {
{ .compatible = "st,stm32-timer-counter", },
+ { .compatible = "st,stm32mp25-timer-counter", },
{},
};
MODULE_DEVICE_TABLE(of, stm32_timer_cnt_of_match);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 5686369779be..9f8a3a5bed7e 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -180,6 +180,7 @@ config CRYPTO_PAES_S390
depends on PKEY
select CRYPTO_ALGAPI
select CRYPTO_SKCIPHER
+ select CRYPTO_ENGINE
help
This is the s390 hardware accelerated implementation of the
AES cipher algorithms for use with protected key.
diff --git a/drivers/eisa/Makefile b/drivers/eisa/Makefile
index a1dd0eaec2d4..552bd9478340 100644
--- a/drivers/eisa/Makefile
+++ b/drivers/eisa/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for the Linux device tree
+always-$(CONFIG_EISA) += devlist.h
obj-$(CONFIG_EISA) += eisa-bus.o
obj-${CONFIG_EISA_PCI_EISA} += pci_eisa.o
@@ -9,14 +10,11 @@ obj-${CONFIG_EISA_PCI_EISA} += pci_eisa.o
obj-${CONFIG_EISA_VIRTUAL_ROOT} += virtual_root.o
-# Ugly hack to get DEVICE_NAME_SIZE value...
-DEVICE_NAME_SIZE = 50
-
$(obj)/eisa-bus.o: $(obj)/devlist.h
quiet_cmd_eisaid = GEN $@
- cmd_eisaid = sed -e '/^\#/D' -e 's/^\([[:alnum:]]\{7\}\) \+"\([^"]\{1,$(DEVICE_NAME_SIZE)\}\).*"/EISA_DEVINFO ("\1", "\2"),/' $< > $@
+ cmd_eisaid = sed -e '/^\#/D' -e 's/^\([[:alnum:]]\{7\}\) \+"\([^"]*\)"/EISA_DEVINFO ("\1", "\2"),/' $< > $@
clean-files := devlist.h
-$(obj)/devlist.h: $(src)/eisa.ids include/linux/device.h
- $(call cmd,eisaid)
+$(obj)/devlist.h: $(src)/eisa.ids include/linux/device.h FORCE
+ $(call if_changed,eisaid)
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index cb586a362944..edceea083b98 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -21,7 +21,7 @@
struct eisa_device_info {
struct eisa_device_id id;
- char name[50];
+ char name[EISA_DEVICE_INFO_NAME_SIZE];
};
#ifdef CONFIG_EISA_NAMES
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 7c5c03f274b9..889e5b05c739 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -143,6 +143,7 @@ static __init int sysfb_init(void)
{
struct screen_info *si = &screen_info;
struct device *parent;
+ unsigned int type;
struct simplefb_platform_data mode;
const char *name;
bool compatible;
@@ -170,17 +171,26 @@ static __init int sysfb_init(void)
goto put_device;
}
+ type = screen_info_video_type(si);
+
/* if the FB is incompatible, create a legacy framebuffer device */
- if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
- name = "efi-framebuffer";
- else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
- name = "vesa-framebuffer";
- else if (si->orig_video_isVGA == VIDEO_TYPE_VGAC)
- name = "vga-framebuffer";
- else if (si->orig_video_isVGA == VIDEO_TYPE_EGAC)
+ switch (type) {
+ case VIDEO_TYPE_EGAC:
name = "ega-framebuffer";
- else
+ break;
+ case VIDEO_TYPE_VGAC:
+ name = "vga-framebuffer";
+ break;
+ case VIDEO_TYPE_VLFB:
+ name = "vesa-framebuffer";
+ break;
+ case VIDEO_TYPE_EFI:
+ name = "efi-framebuffer";
+ break;
+ default:
name = "platform-framebuffer";
+ break;
+ }
pd = platform_device_alloc(name, 0);
if (!pd) {
diff --git a/drivers/fpga/tests/fpga-mgr-test.c b/drivers/fpga/tests/fpga-mgr-test.c
index 8748babb0504..62975a39ee14 100644
--- a/drivers/fpga/tests/fpga-mgr-test.c
+++ b/drivers/fpga/tests/fpga-mgr-test.c
@@ -263,6 +263,7 @@ static void fpga_mgr_test_img_load_sgt(struct kunit *test)
img_buf = init_test_buffer(test, IMAGE_SIZE);
sgt = kunit_kzalloc(test, sizeof(*sgt), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt);
ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
KUNIT_ASSERT_EQ(test, ret, 0);
sg_init_one(sgt->sgl, img_buf, IMAGE_SIZE);
diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig
index 058e3b3ad520..1acfed2f92ef 100644
--- a/drivers/gpu/drm/amd/amdgpu/Kconfig
+++ b/drivers/gpu/drm/amd/amdgpu/Kconfig
@@ -76,7 +76,7 @@ config DRM_AMDGPU_USERPTR
config DRM_AMD_ISP
bool "Enable AMD Image Signal Processor IP support"
- depends on DRM_AMDGPU
+ depends on DRM_AMDGPU && ACPI
select MFD_CORE
select PM_GENERIC_DOMAINS if PM
help
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 836ea081088a..a5ccd0ada16a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -1713,6 +1713,10 @@ static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { retu
static inline bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) { return false; }
#endif
+#if defined(CONFIG_DRM_AMD_ISP)
+int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN]);
+#endif
+
void amdgpu_register_gpu_instance(struct amdgpu_device *adev);
void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
index 707e131f89d2..f5466c592d94 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
@@ -1532,5 +1532,35 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
return true;
#endif /* CONFIG_AMD_PMC */
}
-
#endif /* CONFIG_SUSPEND */
+
+#if IS_ENABLED(CONFIG_DRM_AMD_ISP)
+static const struct acpi_device_id isp_sensor_ids[] = {
+ { "OMNI5C10" },
+ { }
+};
+
+static int isp_match_acpi_device_ids(struct device *dev, const void *data)
+{
+ return acpi_match_device(data, dev) ? 1 : 0;
+}
+
+int amdgpu_acpi_get_isp4_dev_hid(u8 (*hid)[ACPI_ID_LEN])
+{
+ struct device *pdev __free(put_device) = NULL;
+ struct acpi_device *acpi_pdev;
+
+ pdev = bus_find_device(&platform_bus_type, NULL, isp_sensor_ids,
+ isp_match_acpi_device_ids);
+ if (!pdev)
+ return -EINVAL;
+
+ acpi_pdev = ACPI_COMPANION(pdev);
+ if (!acpi_pdev)
+ return -ENODEV;
+
+ strscpy(*hid, acpi_device_hid(acpi_pdev));
+
+ return 0;
+}
+#endif /* CONFIG_DRM_AMD_ISP */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 4cec3a873995..d8ac4b1051a8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -368,6 +368,9 @@ void amdgpu_amdkfd_free_gtt_mem(struct amdgpu_device *adev, void **mem_obj)
{
struct amdgpu_bo **bo = (struct amdgpu_bo **) mem_obj;
+ if (!bo || !*bo)
+ return;
+
(void)amdgpu_bo_reserve(*bo, true);
amdgpu_bo_kunmap(*bo);
amdgpu_bo_unpin(*bo);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index c43d1b6e5d66..85567d0d9545 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -919,7 +919,7 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
return timeout;
}
-void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
+static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
{
struct amdgpu_ctx *ctx;
struct idr *idp;
@@ -949,19 +949,7 @@ void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
{
- struct amdgpu_ctx *ctx;
- struct idr *idp;
- uint32_t id;
-
amdgpu_ctx_mgr_entity_fini(mgr);
-
- idp = &mgr->ctx_handles;
-
- idr_for_each_entry(idp, ctx, id) {
- if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1)
- DRM_ERROR("ctx %p is still alive\n", ctx);
- }
-
idr_destroy(&mgr->ctx_handles);
mutex_destroy(&mgr->lock);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
index 85376baaa92f..090dfe86f75b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h
@@ -92,7 +92,6 @@ int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx,
void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr,
struct amdgpu_device *adev);
-void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr);
long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout);
void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr);
void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 4d1b54f58495..e1bab6a96cb6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -512,12 +512,13 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
break;
case CHIP_VEGA10:
/* enable BACO as runpm mode if noretry=0 */
- if (!adev->gmc.noretry)
+ if (!adev->gmc.noretry && !amdgpu_passthrough(adev))
adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
break;
default:
/* enable BACO as runpm mode on CI+ */
- adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
+ if (!amdgpu_passthrough(adev))
+ adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
break;
}
@@ -4728,7 +4729,7 @@ fence_driver_init:
amdgpu_fru_sysfs_init(adev);
amdgpu_reg_state_sysfs_init(adev);
- amdgpu_xcp_cfg_sysfs_init(adev);
+ amdgpu_xcp_sysfs_init(adev);
if (IS_ENABLED(CONFIG_PERF_EVENTS))
r = amdgpu_pmu_init(adev);
@@ -4858,7 +4859,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
amdgpu_fru_sysfs_fini(adev);
amdgpu_reg_state_sysfs_fini(adev);
- amdgpu_xcp_cfg_sysfs_fini(adev);
+ amdgpu_xcp_sysfs_fini(adev);
/* disable ras feature must before hw fini */
amdgpu_ras_pre_fini(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 9e738fae2b74..a0e9bf9b2710 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -270,9 +270,10 @@ static int amdgpu_discovery_read_binary_from_sysmem(struct amdgpu_device *adev,
static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
uint8_t *binary)
{
+ bool sz_valid = true;
uint64_t vram_size;
- u32 msg;
int i, ret = 0;
+ u32 msg;
if (!amdgpu_sriov_vf(adev)) {
/* It can take up to a second for IFWI init to complete on some dGPUs,
@@ -291,9 +292,13 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
}
}
- vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20;
+ vram_size = RREG32(mmRCC_CONFIG_MEMSIZE);
+ if (!vram_size || vram_size == U32_MAX)
+ sz_valid = false;
+ else
+ vram_size <<= 20;
- if (vram_size) {
+ if (sz_valid) {
uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET;
amdgpu_device_vram_access(adev, pos, (uint32_t *)binary,
adev->mman.discovery_tmr_size, false);
@@ -301,6 +306,11 @@ static int amdgpu_discovery_read_binary_from_mem(struct amdgpu_device *adev,
ret = amdgpu_discovery_read_binary_from_sysmem(adev, binary);
}
+ if (ret)
+ dev_err(adev->dev,
+ "failed to read discovery info from memory, vram size read: %llx",
+ vram_size);
+
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 4ddd08ce8885..4db92e0a60da 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2913,8 +2913,8 @@ static int amdgpu_drm_release(struct inode *inode, struct file *filp)
if (fpriv) {
fpriv->evf_mgr.fd_closing = true;
- amdgpu_userq_mgr_fini(&fpriv->userq_mgr);
amdgpu_eviction_fence_destroy(&fpriv->evf_mgr);
+ amdgpu_userq_mgr_fini(&fpriv->userq_mgr);
}
return drm_release(inode, filp);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
index 73b629b5f56f..8b919ad3af29 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c
@@ -108,13 +108,22 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
struct amdgpu_eviction_fence *ev_fence;
mutex_lock(&uq_mgr->userq_mutex);
+ spin_lock(&evf_mgr->ev_fence_lock);
ev_fence = evf_mgr->ev_fence;
- if (!ev_fence)
+ if (ev_fence)
+ dma_fence_get(&ev_fence->base);
+ else
goto unlock;
+ spin_unlock(&evf_mgr->ev_fence_lock);
amdgpu_userq_evict(uq_mgr, ev_fence);
+ mutex_unlock(&uq_mgr->userq_mutex);
+ dma_fence_put(&ev_fence->base);
+ return;
+
unlock:
+ spin_unlock(&evf_mgr->ev_fence_lock);
mutex_unlock(&uq_mgr->userq_mutex);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 2c68118fe9fd..0ecc88df7208 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -58,7 +58,7 @@ amdgpu_gem_add_input_fence(struct drm_file *filp,
return 0;
syncobj_handles = memdup_user(u64_to_user_ptr(syncobj_handles_array),
- sizeof(uint32_t) * num_syncobj_handles);
+ size_mul(sizeof(uint32_t), num_syncobj_handles));
if (IS_ERR(syncobj_handles))
return PTR_ERR(syncobj_handles);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 1db1e6ec0184..c5646af055ab 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -2228,6 +2228,9 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring)
enum PP_SMC_POWER_PROFILE profile;
int r;
+ if (amdgpu_dpm_is_overdrive_enabled(adev))
+ return;
+
if (adev->gfx.num_gfx_rings)
profile = PP_SMC_POWER_PROFILE_FULLSCREEN3D;
else
@@ -2258,6 +2261,11 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring)
void amdgpu_gfx_profile_ring_end_use(struct amdgpu_ring *ring)
{
+ struct amdgpu_device *adev = ring->adev;
+
+ if (amdgpu_dpm_is_overdrive_enabled(adev))
+ return;
+
atomic_dec(&ring->adev->gfx.total_submission_cnt);
schedule_delayed_work(&ring->adev->gfx.idle_work, GFX_PROFILE_IDLE_TIMEOUT);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 9fbb04aee97b..d2ce7d86dbc8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1502,11 +1502,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
amdgpu_bo_unreserve(pd);
}
- if (!fpriv->evf_mgr.fd_closing) {
- fpriv->evf_mgr.fd_closing = true;
- amdgpu_userq_mgr_fini(&fpriv->userq_mgr);
- amdgpu_eviction_fence_destroy(&fpriv->evf_mgr);
- }
amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr);
amdgpu_vm_fini(adev, &fpriv->vm);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
index 2febb63ab232..6fa9fa11c8f3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
@@ -300,7 +300,9 @@ int amdgpu_mes_map_legacy_queue(struct amdgpu_device *adev,
queue_input.mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj);
queue_input.wptr_addr = ring->wptr_gpu_addr;
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->map_legacy_queue(&adev->mes, &queue_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
DRM_ERROR("failed to map legacy queue\n");
@@ -323,7 +325,9 @@ int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev,
queue_input.trail_fence_addr = gpu_addr;
queue_input.trail_fence_data = seq;
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->unmap_legacy_queue(&adev->mes, &queue_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
DRM_ERROR("failed to unmap legacy queue\n");
@@ -353,7 +357,9 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev,
if (ring->funcs->type == AMDGPU_RING_TYPE_GFX)
queue_input.legacy_gfx = true;
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
DRM_ERROR("failed to reset legacy queue\n");
@@ -383,7 +389,9 @@ uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg)
goto error;
}
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to read reg (0x%x)\n", reg);
else
@@ -411,7 +419,9 @@ int amdgpu_mes_wreg(struct amdgpu_device *adev,
goto error;
}
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to write reg (0x%x)\n", reg);
@@ -438,32 +448,9 @@ int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev,
goto error;
}
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
- if (r)
- dev_err(adev->dev, "failed to reg_write_reg_wait\n");
-
-error:
- return r;
-}
-
-int amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg,
- uint32_t val, uint32_t mask)
-{
- struct mes_misc_op_input op_input;
- int r;
-
- op_input.op = MES_MISC_OP_WRM_REG_WAIT;
- op_input.wrm_reg.reg0 = reg;
- op_input.wrm_reg.ref = val;
- op_input.wrm_reg.mask = mask;
-
- if (!adev->mes.funcs->misc_op) {
- dev_err(adev->dev, "mes reg wait is not supported!\n");
- r = -EINVAL;
- goto error;
- }
-
- r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to reg_write_reg_wait\n");
@@ -539,42 +526,6 @@ int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev,
return r;
}
-#define DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(_eng) \
-do { \
- if (id_offs < AMDGPU_MES_CTX_MAX_OFFS) \
- return offsetof(struct amdgpu_mes_ctx_meta_data, \
- _eng[ring->idx].slots[id_offs]); \
- else if (id_offs == AMDGPU_MES_CTX_RING_OFFS) \
- return offsetof(struct amdgpu_mes_ctx_meta_data, \
- _eng[ring->idx].ring); \
- else if (id_offs == AMDGPU_MES_CTX_IB_OFFS) \
- return offsetof(struct amdgpu_mes_ctx_meta_data, \
- _eng[ring->idx].ib); \
- else if (id_offs == AMDGPU_MES_CTX_PADDING_OFFS) \
- return offsetof(struct amdgpu_mes_ctx_meta_data, \
- _eng[ring->idx].padding); \
-} while(0)
-
-int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs)
-{
- switch (ring->funcs->type) {
- case AMDGPU_RING_TYPE_GFX:
- DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(gfx);
- break;
- case AMDGPU_RING_TYPE_COMPUTE:
- DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(compute);
- break;
- case AMDGPU_RING_TYPE_SDMA:
- DEFINE_AMDGPU_MES_CTX_GET_OFFS_ENG(sdma);
- break;
- default:
- break;
- }
-
- WARN_ON(1);
- return -EINVAL;
-}
-
uint32_t amdgpu_mes_get_aggregated_doorbell_index(struct amdgpu_device *adev,
enum amdgpu_mes_priority_level prio)
{
@@ -694,7 +645,9 @@ static int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev,
goto error;
}
+ amdgpu_mes_lock(&adev->mes);
r = adev->mes.funcs->misc_op(&adev->mes, &op_input);
+ amdgpu_mes_unlock(&adev->mes);
if (r)
dev_err(adev->dev, "failed to change_config.\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
index a41f65b4f733..c0d2c195fe2e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h
@@ -372,8 +372,6 @@ struct amdgpu_mes_funcs {
#define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev))
#define amdgpu_mes_kiq_hw_fini(adev) (adev)->mes.kiq_hw_fini((adev))
-int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs);
-
int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe);
int amdgpu_mes_init(struct amdgpu_device *adev);
void amdgpu_mes_fini(struct amdgpu_device *adev);
@@ -395,8 +393,6 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev,
uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg);
int amdgpu_mes_wreg(struct amdgpu_device *adev,
uint32_t reg, uint32_t val);
-int amdgpu_mes_reg_wait(struct amdgpu_device *adev, uint32_t reg,
- uint32_t val, uint32_t mask);
int amdgpu_mes_reg_write_reg_wait(struct amdgpu_device *adev,
uint32_t reg0, uint32_t reg1,
uint32_t ref, uint32_t mask);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
index dc07936d2fcb..de0944947eaf 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
@@ -2859,6 +2859,15 @@ static int __amdgpu_ras_convert_rec_array_from_rom(struct amdgpu_device *adev,
return -EINVAL;
}
} else {
+ if (bps[0].address == 0) {
+ /* for specific old eeprom data, mca address is not stored,
+ * calc it from pa
+ */
+ if (amdgpu_umc_pa2mca(adev, bps[0].retired_page << AMDGPU_GPU_PAGE_SHIFT,
+ &(bps[0].address), AMDGPU_NPS1_PARTITION_MODE))
+ return -EINVAL;
+ }
+
if (amdgpu_ras_mca2pa(adev, &bps[0], err_data)) {
if (nps == AMDGPU_NPS1_PARTITION_MODE)
memcpy(err_data->err_addr, bps,
@@ -2886,8 +2895,20 @@ static int __amdgpu_ras_convert_rec_from_rom(struct amdgpu_device *adev,
bps->retired_page << AMDGPU_GPU_PAGE_SHIFT))
return -EINVAL;
} else {
- if (amdgpu_ras_mca2pa_by_idx(adev, bps, err_data))
- return -EINVAL;
+ if (bps->address) {
+ if (amdgpu_ras_mca2pa_by_idx(adev, bps, err_data))
+ return -EINVAL;
+ } else {
+ /* for specific old eeprom data, mca address is not stored,
+ * calc it from pa
+ */
+ if (amdgpu_umc_pa2mca(adev, bps->retired_page << AMDGPU_GPU_PAGE_SHIFT,
+ &(bps->address), AMDGPU_NPS1_PARTITION_MODE))
+ return -EINVAL;
+
+ if (amdgpu_ras_mca2pa(adev, bps, err_data))
+ return -EOPNOTSUPP;
+ }
}
return __amdgpu_ras_restore_bad_pages(adev, err_data->err_addr,
@@ -3708,7 +3729,8 @@ static void amdgpu_ras_query_ras_capablity_from_vbios(struct amdgpu_device *adev
*/
if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(2, 6, 0) ||
amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 0) ||
- amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 3))
+ amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 3) ||
+ amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(5, 0, 1))
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__VCN |
1 << AMDGPU_RAS_BLOCK__JPEG);
else
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
index 5605921212f0..e5f8951bbb6f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h
@@ -113,6 +113,7 @@ struct amdgpu_sdma {
struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES];
struct amdgpu_irq_src trap_irq;
struct amdgpu_irq_src illegal_inst_irq;
+ struct amdgpu_irq_src fence_irq;
struct amdgpu_irq_src ecc_irq;
struct amdgpu_irq_src vm_hole_irq;
struct amdgpu_irq_src doorbell_invalid_irq;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
index 3939761be31c..d45ebfb642ca 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c
@@ -139,7 +139,7 @@ void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv)
vm = &fpriv->vm;
- drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0);
+ drm_exec_init(&exec, 0, 0);
drm_exec_until_all_locked(&exec) {
r = amdgpu_vm_lock_pd(vm, &exec, 0);
if (likely(!r))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
index 4a72c2bbd49e..2505c46a9c3d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c
@@ -765,6 +765,7 @@ FW_VERSION_ATTR(sdma_fw_version, 0444, sdma.instance[0].fw_version);
FW_VERSION_ATTR(sdma2_fw_version, 0444, sdma.instance[1].fw_version);
FW_VERSION_ATTR(vcn_fw_version, 0444, vcn.fw_version);
FW_VERSION_ATTR(dmcu_fw_version, 0444, dm.dmcu_fw_version);
+FW_VERSION_ATTR(dmcub_fw_version, 0444, dm.dmcub_fw_version);
FW_VERSION_ATTR(mes_fw_version, 0444, mes.sched_version & AMDGPU_MES_VERSION_MASK);
FW_VERSION_ATTR(mes_kiq_fw_version, 0444, mes.kiq_version & AMDGPU_MES_VERSION_MASK);
FW_VERSION_ATTR(pldm_fw_version, 0444, firmware.pldm_version);
@@ -780,9 +781,10 @@ static struct attribute *fw_attrs[] = {
&dev_attr_ta_ras_fw_version.attr, &dev_attr_ta_xgmi_fw_version.attr,
&dev_attr_smc_fw_version.attr, &dev_attr_sdma_fw_version.attr,
&dev_attr_sdma2_fw_version.attr, &dev_attr_vcn_fw_version.attr,
- &dev_attr_dmcu_fw_version.attr, &dev_attr_imu_fw_version.attr,
- &dev_attr_mes_fw_version.attr, &dev_attr_mes_kiq_fw_version.attr,
- &dev_attr_pldm_fw_version.attr, NULL
+ &dev_attr_dmcu_fw_version.attr, &dev_attr_dmcub_fw_version.attr,
+ &dev_attr_imu_fw_version.attr, &dev_attr_mes_fw_version.attr,
+ &dev_attr_mes_kiq_fw_version.attr, &dev_attr_pldm_fw_version.attr,
+ NULL
};
#define to_dev_attr(x) container_of(x, struct device_attribute, attr)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
index 8c6e55b5b967..c92b8794aa73 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c
@@ -562,3 +562,26 @@ int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev,
return 0;
}
+
+int amdgpu_umc_pa2mca(struct amdgpu_device *adev,
+ uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps)
+{
+ struct ta_ras_query_address_input addr_in;
+ struct ta_ras_query_address_output addr_out;
+ int ret;
+
+ /* nps: the pa belongs to */
+ addr_in.pa.pa = pa | ((uint64_t)nps << 58);
+ addr_in.addr_type = TA_RAS_PA_TO_MCA;
+ ret = psp_ras_query_address(&adev->psp, &addr_in, &addr_out);
+ if (ret) {
+ dev_warn(adev->dev, "Failed to query RAS MCA address for 0x%llx",
+ pa);
+
+ return ret;
+ }
+
+ *mca = addr_out.ma.err_addr;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
index 29ce6b1d214a..ec203f9e5ffa 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h
@@ -189,4 +189,6 @@ int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev,
uint64_t err_addr, uint32_t ch, uint32_t umc,
uint32_t node, uint32_t socket,
struct ta_ras_query_address_output *addr_out, bool dump_addr);
+int amdgpu_umc_pa2mca(struct amdgpu_device *adev,
+ uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps);
#endif
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
index fc4d0d42e223..a86616c6deef 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
@@ -430,7 +430,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
num_syncobj_handles = args->num_syncobj_handles;
syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles),
- sizeof(u32) * num_syncobj_handles);
+ size_mul(sizeof(u32), num_syncobj_handles));
if (IS_ERR(syncobj_handles))
return PTR_ERR(syncobj_handles);
@@ -612,13 +612,13 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
num_read_bo_handles = wait_info->num_bo_read_handles;
bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles),
- sizeof(u32) * num_read_bo_handles);
+ size_mul(sizeof(u32), num_read_bo_handles));
if (IS_ERR(bo_handles_read))
return PTR_ERR(bo_handles_read);
num_write_bo_handles = wait_info->num_bo_write_handles;
bo_handles_write = memdup_user(u64_to_user_ptr(wait_info->bo_write_handles),
- sizeof(u32) * num_write_bo_handles);
+ size_mul(sizeof(u32), num_write_bo_handles));
if (IS_ERR(bo_handles_write)) {
r = PTR_ERR(bo_handles_write);
goto free_bo_handles_read;
@@ -626,7 +626,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
num_syncobj = wait_info->num_syncobj_handles;
syncobj_handles = memdup_user(u64_to_user_ptr(wait_info->syncobj_handles),
- sizeof(u32) * num_syncobj);
+ size_mul(sizeof(u32), num_syncobj));
if (IS_ERR(syncobj_handles)) {
r = PTR_ERR(syncobj_handles);
goto free_bo_handles_write;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
index 2d7f82e98df9..abdc52b0895a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
@@ -463,7 +463,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
int r;
lpfn = (u64)place->lpfn << PAGE_SHIFT;
- if (!lpfn)
+ if (!lpfn || lpfn > man->size)
lpfn = man->size;
fpfn = (u64)place->fpfn << PAGE_SHIFT;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
index b03c3895897b..322816805bfb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
@@ -27,6 +27,9 @@
#include <drm/drm_drv.h>
#include "../amdxcp/amdgpu_xcp_drv.h"
+static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr);
+static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr);
+
static int __amdgpu_xcp_run(struct amdgpu_xcp_mgr *xcp_mgr,
struct amdgpu_xcp_ip *xcp_ip, int xcp_state)
{
@@ -189,7 +192,7 @@ static int __amdgpu_xcp_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr,
goto out;
}
-
+ amdgpu_xcp_sysfs_entries_update(xcp_mgr);
out:
mutex_unlock(&xcp_mgr->xcp_lock);
@@ -263,9 +266,10 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev)
if (ret == -ENOSPC) {
dev_warn(adev->dev,
"Skip xcp node #%d when out of drm node resource.", i);
- return 0;
+ ret = 0;
+ goto out;
} else if (ret) {
- return ret;
+ goto out;
}
/* Redirect all IOCTLs to the primary device */
@@ -278,9 +282,14 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev)
p_ddev->vma_offset_manager = ddev->vma_offset_manager;
p_ddev->driver = &amdgpu_partition_driver;
adev->xcp_mgr->xcp[i].ddev = p_ddev;
+
+ dev_set_drvdata(p_ddev->dev, &adev->xcp_mgr->xcp[i]);
}
+ ret = 0;
+out:
+ amdgpu_xcp_sysfs_entries_init(adev->xcp_mgr);
- return 0;
+ return ret;
}
int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode,
@@ -288,6 +297,7 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode,
struct amdgpu_xcp_mgr_funcs *xcp_funcs)
{
struct amdgpu_xcp_mgr *xcp_mgr;
+ int i;
if (!xcp_funcs || !xcp_funcs->get_ip_details)
return -EINVAL;
@@ -306,6 +316,8 @@ int amdgpu_xcp_mgr_init(struct amdgpu_device *adev, int init_mode,
amdgpu_xcp_init(xcp_mgr, init_num_xcps, init_mode);
adev->xcp_mgr = xcp_mgr;
+ for (i = 0; i < MAX_XCP; ++i)
+ xcp_mgr->xcp[i].xcp_mgr = xcp_mgr;
return amdgpu_xcp_dev_alloc(adev);
}
@@ -433,6 +445,7 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev,
}
}
+/*====================== xcp sysfs - configuration ======================*/
#define XCP_CFG_SYSFS_RES_ATTR_SHOW(_name) \
static ssize_t amdgpu_xcp_res_sysfs_##_name##_show( \
struct amdgpu_xcp_res_details *xcp_res, char *buf) \
@@ -635,7 +648,7 @@ static const struct attribute *xcp_attrs[] = {
NULL,
};
-void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev)
+static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev)
{
struct amdgpu_xcp_res_details *xcp_res;
struct amdgpu_xcp_cfg *xcp_cfg;
@@ -703,7 +716,7 @@ err1:
kobject_put(&xcp_cfg->kobj);
}
-void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev)
+static void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev)
{
struct amdgpu_xcp_res_details *xcp_res;
struct amdgpu_xcp_cfg *xcp_cfg;
@@ -722,3 +735,124 @@ void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev)
sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs);
kobject_put(&xcp_cfg->kobj);
}
+
+/*====================== xcp sysfs - data entries ======================*/
+
+#define to_xcp(x) container_of(x, struct amdgpu_xcp, kobj)
+
+static ssize_t xcp_metrics_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct amdgpu_xcp *xcp = to_xcp(kobj);
+ struct amdgpu_xcp_mgr *xcp_mgr;
+ ssize_t size;
+
+ xcp_mgr = xcp->xcp_mgr;
+ size = amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, NULL);
+ if (size <= 0)
+ return size;
+
+ if (size > PAGE_SIZE)
+ return -ENOSPC;
+
+ return amdgpu_dpm_get_xcp_metrics(xcp_mgr->adev, xcp->id, buf);
+}
+
+static umode_t amdgpu_xcp_attrs_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct amdgpu_xcp *xcp = to_xcp(kobj);
+
+ if (!xcp || !xcp->valid)
+ return 0;
+
+ return attr->mode;
+}
+
+static struct kobj_attribute xcp_sysfs_metrics = __ATTR_RO(xcp_metrics);
+
+static struct attribute *amdgpu_xcp_attrs[] = {
+ &xcp_sysfs_metrics.attr,
+ NULL,
+};
+
+static const struct attribute_group amdgpu_xcp_attrs_group = {
+ .attrs = amdgpu_xcp_attrs,
+ .is_visible = amdgpu_xcp_attrs_is_visible
+};
+
+static const struct kobj_type xcp_sysfs_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+};
+
+static void amdgpu_xcp_sysfs_entries_fini(struct amdgpu_xcp_mgr *xcp_mgr, int n)
+{
+ struct amdgpu_xcp *xcp;
+
+ for (n--; n >= 0; n--) {
+ xcp = &xcp_mgr->xcp[n];
+ if (!xcp->ddev || !xcp->valid)
+ continue;
+ sysfs_remove_group(&xcp->kobj, &amdgpu_xcp_attrs_group);
+ kobject_put(&xcp->kobj);
+ }
+}
+
+static void amdgpu_xcp_sysfs_entries_init(struct amdgpu_xcp_mgr *xcp_mgr)
+{
+ struct amdgpu_xcp *xcp;
+ int i, r;
+
+ for (i = 0; i < MAX_XCP; i++) {
+ /* Redirect all IOCTLs to the primary device */
+ xcp = &xcp_mgr->xcp[i];
+ if (!xcp->ddev)
+ break;
+ r = kobject_init_and_add(&xcp->kobj, &xcp_sysfs_ktype,
+ &xcp->ddev->dev->kobj, "xcp");
+ if (r)
+ goto out;
+
+ r = sysfs_create_group(&xcp->kobj, &amdgpu_xcp_attrs_group);
+ if (r)
+ goto out;
+ }
+
+ return;
+out:
+ kobject_put(&xcp->kobj);
+}
+
+static void amdgpu_xcp_sysfs_entries_update(struct amdgpu_xcp_mgr *xcp_mgr)
+{
+ struct amdgpu_xcp *xcp;
+ int i;
+
+ for (i = 0; i < MAX_XCP; i++) {
+ /* Redirect all IOCTLs to the primary device */
+ xcp = &xcp_mgr->xcp[i];
+ if (!xcp->ddev)
+ continue;
+ sysfs_update_group(&xcp->kobj, &amdgpu_xcp_attrs_group);
+ }
+
+ return;
+}
+
+void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev)
+{
+ if (!adev->xcp_mgr)
+ return;
+
+ amdgpu_xcp_cfg_sysfs_init(adev);
+
+ return;
+}
+
+void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev)
+{
+ if (!adev->xcp_mgr)
+ return;
+ amdgpu_xcp_sysfs_entries_fini(adev->xcp_mgr, MAX_XCP);
+ amdgpu_xcp_cfg_sysfs_fini(adev);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
index b63f53242c57..454b33f889fb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h
@@ -108,6 +108,8 @@ struct amdgpu_xcp {
struct drm_driver *driver;
struct drm_vma_offset_manager *vma_offset_manager;
struct amdgpu_sched gpu_sched[AMDGPU_HW_IP_NUM][AMDGPU_RING_PRIO_MAX];
+ struct amdgpu_xcp_mgr *xcp_mgr;
+ struct kobject kobj;
};
struct amdgpu_xcp_mgr {
@@ -175,8 +177,8 @@ int amdgpu_xcp_open_device(struct amdgpu_device *adev,
void amdgpu_xcp_release_sched(struct amdgpu_device *adev,
struct amdgpu_ctx_entity *entity);
-void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev);
-void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev);
+void amdgpu_xcp_sysfs_init(struct amdgpu_device *adev);
+void amdgpu_xcp_sysfs_fini(struct amdgpu_device *adev);
#define amdgpu_xcp_select_scheds(adev, e, c, d, x, y) \
((adev)->xcp_mgr && (adev)->xcp_mgr->funcs && \
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
index f51ef4cf16e0..d9ad37711c3e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
@@ -294,6 +294,23 @@ static const struct amdgpu_pcs_ras_field xgmi3x16_pcs_ras_fields[] = {
SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxCMDPktErr)},
};
+int amdgpu_xgmi_get_ext_link(struct amdgpu_device *adev, int link_num)
+{
+ int link_map_6_4_x[8] = { 0, 3, 1, 2, 7, 6, 4, 5 };
+
+ switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) {
+ case IP_VERSION(6, 4, 0):
+ case IP_VERSION(6, 4, 1):
+ if (link_num < ARRAY_SIZE(link_map_6_4_x))
+ return link_map_6_4_x[link_num];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
static u32 xgmi_v6_4_get_link_status(struct amdgpu_device *adev, int global_link_num)
{
const u32 smn_xgmi_6_4_pcs_state_hist1[2] = { 0x11a00070, 0x11b00070 };
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
index 32dabba4062f..f994be985f42 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h
@@ -125,6 +125,7 @@ int amdgpu_xgmi_request_nps_change(struct amdgpu_device *adev,
int req_nps_mode);
int amdgpu_get_xgmi_link_status(struct amdgpu_device *adev,
int global_link_num);
+int amdgpu_xgmi_get_ext_link(struct amdgpu_device *adev, int link_num);
void amdgpu_xgmi_early_init(struct amdgpu_device *adev);
uint32_t amdgpu_xgmi_get_max_bandwidth(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
index 5255378af53c..f67569ccf9f6 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0_cleaner_shader.h
@@ -43,9 +43,9 @@ static const u32 gfx_10_1_10_cleaner_shader_hex[] = {
0xd70f6a01, 0x000202ff,
0x00000400, 0x80828102,
0xbf84fff7, 0xbefc03ff,
- 0x00000068, 0xbe803080,
- 0xbe813080, 0xbe823080,
- 0xbe833080, 0x80fc847c,
+ 0x00000068, 0xbe803000,
+ 0xbe813000, 0xbe823000,
+ 0xbe833000, 0x80fc847c,
0xbf84fffa, 0xbeea0480,
0xbeec0480, 0xbeee0480,
0xbef00480, 0xbef20480,
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
index 9ba3359253c9..54f7ed9e2801 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_1_10_cleaner_shader.asm
@@ -40,7 +40,6 @@ shader main
type(CS)
wave_size(32)
// Note: original source code from SQ team
-
//
// Create 32 waves in a threadgroup (CS waves)
// Each allocates 64 VGPRs
@@ -71,8 +70,8 @@ label_0005:
s_sub_u32 s2, s2, 8
s_cbranch_scc0 label_0005
//
- s_mov_b32 s2, 0x80000000 // Bit31 is first_wave
- s_and_b32 s2, s2, s0 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set
+ s_mov_b32 s2, 0x80000000 // Bit31 is first_wave
+ s_and_b32 s2, s2, s1 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set
s_cbranch_scc0 label_0023 // Clean LDS if its first wave of ThreadGroup/WorkGroup
// CLEAR LDS
//
@@ -99,10 +98,10 @@ label_001F:
label_0023:
s_mov_b32 m0, 0x00000068 // Loop 108/4=27 times (loop unrolled for performance)
label_sgpr_loop:
- s_movreld_b32 s0, 0
- s_movreld_b32 s1, 0
- s_movreld_b32 s2, 0
- s_movreld_b32 s3, 0
+ s_movreld_b32 s0, s0
+ s_movreld_b32 s1, s0
+ s_movreld_b32 s2, s0
+ s_movreld_b32 s3, s0
s_sub_u32 m0, m0, 4
s_cbranch_scc0 label_sgpr_loop
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index f09d96bfee16..1234c8d64e20 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -36,7 +36,7 @@
#include "gc/gc_12_0_0_offset.h"
#include "gc/gc_12_0_0_sh_mask.h"
#include "soc24_enum.h"
-#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h"
+#include "ivsrcid/gfx/irqsrcs_gfx_12_0_0.h"
#include "soc15.h"
#include "clearstate_gfx12.h"
@@ -1453,28 +1453,28 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
/* EOP Event */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP,
- GFX_11_0_0__SRCID__CP_EOP_INTERRUPT,
+ GFX_12_0_0__SRCID__CP_EOP_INTERRUPT,
&adev->gfx.eop_irq);
if (r)
return r;
/* Bad opcode Event */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP,
- GFX_11_0_0__SRCID__CP_BAD_OPCODE_ERROR,
+ GFX_12_0_0__SRCID__CP_BAD_OPCODE_ERROR,
&adev->gfx.bad_op_irq);
if (r)
return r;
/* Privileged reg */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP,
- GFX_11_0_0__SRCID__CP_PRIV_REG_FAULT,
+ GFX_12_0_0__SRCID__CP_PRIV_REG_FAULT,
&adev->gfx.priv_reg_irq);
if (r)
return r;
/* Privileged inst */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP,
- GFX_11_0_0__SRCID__CP_PRIV_INSTR_FAULT,
+ GFX_12_0_0__SRCID__CP_PRIV_INSTR_FAULT,
&adev->gfx.priv_inst_irq);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
index 69dd92f6e86d..574880d67009 100644
--- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
@@ -25,6 +25,7 @@
*
*/
+#include <linux/gpio/machine.h>
#include "amdgpu.h"
#include "isp_v4_1_1.h"
@@ -39,15 +40,45 @@ static const unsigned int isp_4_1_1_int_srcid[MAX_ISP411_INT_SRC] = {
ISP_4_1__SRCID__ISP_RINGBUFFER_WPT16
};
+static struct gpiod_lookup_table isp_gpio_table = {
+ .dev_id = "amd_isp_capture",
+ .table = {
+ GPIO_LOOKUP("AMDI0030:00", 85, "enable_isp", GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static struct gpiod_lookup_table isp_sensor_gpio_table = {
+ .dev_id = "i2c-ov05c10",
+ .table = {
+ GPIO_LOOKUP("amdisp-pinctrl", 0, "enable", GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
static int isp_v4_1_1_hw_init(struct amdgpu_isp *isp)
{
struct amdgpu_device *adev = isp->adev;
int idx, int_idx, num_res, r;
+ u8 isp_dev_hid[ACPI_ID_LEN];
u64 isp_base;
if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289)
return -EINVAL;
+ r = amdgpu_acpi_get_isp4_dev_hid(&isp_dev_hid);
+ if (r) {
+ drm_dbg(&adev->ddev, "Invalid isp platform detected (%d)", r);
+ /* allow GPU init to progress */
+ return 0;
+ }
+
+ /* add GPIO resources required for OMNI5C10 sensor */
+ if (!strcmp("OMNI5C10", isp_dev_hid)) {
+ gpiod_add_lookup_table(&isp_gpio_table);
+ gpiod_add_lookup_table(&isp_sensor_gpio_table);
+ }
+
isp_base = adev->rmmio_base;
isp->isp_cell = kcalloc(3, sizeof(struct mfd_cell), GFP_KERNEL);
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
index a8ccae361ec7..79e342d5ab28 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c
@@ -149,6 +149,18 @@ static int jpeg_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block)
return r;
}
+ /* JPEG DJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
+ if (r)
+ return r;
+
+ /* JPEG EJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
+ if (r)
+ return r;
+
r = amdgpu_jpeg_sw_init(adev);
if (r)
return r;
@@ -434,6 +446,9 @@ static int jpeg_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
ret = jpeg_v4_0_3_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
}
+ if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
+ amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0);
+
return ret;
}
@@ -1041,6 +1056,14 @@ static int jpeg_v4_0_3_set_interrupt_state(struct amdgpu_device *adev,
return 0;
}
+static int jpeg_v4_0_3_set_ras_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned int type,
+ enum amdgpu_interrupt_state state)
+{
+ return 0;
+}
+
static int jpeg_v4_0_3_process_interrupt(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
@@ -1200,6 +1223,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v4_0_3_irq_funcs = {
.process = jpeg_v4_0_3_process_interrupt,
};
+static const struct amdgpu_irq_src_funcs jpeg_v4_0_3_ras_irq_funcs = {
+ .set = jpeg_v4_0_3_set_ras_interrupt_state,
+ .process = amdgpu_jpeg_process_poison_irq,
+};
+
static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev)
{
int i;
@@ -1208,6 +1236,9 @@ static void jpeg_v4_0_3_set_irq_funcs(struct amdgpu_device *adev)
adev->jpeg.inst->irq.num_types += adev->jpeg.num_jpeg_rings;
}
adev->jpeg.inst->irq.funcs = &jpeg_v4_0_3_irq_funcs;
+
+ adev->jpeg.inst->ras_poison_irq.num_types = 1;
+ adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v4_0_3_ras_irq_funcs;
}
const struct amdgpu_ip_block_version jpeg_v4_0_3_ip_block = {
@@ -1304,9 +1335,47 @@ static void jpeg_v4_0_3_reset_ras_error_count(struct amdgpu_device *adev)
jpeg_v4_0_3_inst_reset_ras_error_count(adev, i);
}
+static uint32_t jpeg_v4_0_3_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_JPEG_V4_0_3_JPEG0:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG0_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG0_STATUS, POISONED_PF);
+ break;
+ case AMDGPU_JPEG_V4_0_3_JPEG1:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG1_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG1_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in JPEG%d sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool jpeg_v4_0_3_query_ras_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst = 0, sub = 0, poison_stat = 0;
+
+ for (inst = 0; inst < adev->jpeg.num_jpeg_inst; inst++)
+ for (sub = 0; sub < AMDGPU_JPEG_V4_0_3_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ jpeg_v4_0_3_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
static const struct amdgpu_ras_block_hw_ops jpeg_v4_0_3_ras_hw_ops = {
.query_ras_error_count = jpeg_v4_0_3_query_ras_error_count,
.reset_ras_error_count = jpeg_v4_0_3_reset_ras_error_count,
+ .query_poison_status = jpeg_v4_0_3_query_ras_poison_status,
};
static int jpeg_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
@@ -1383,6 +1452,13 @@ static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_comm
if (r)
return r;
+ if (amdgpu_ras_is_supported(adev, ras_block->block) &&
+ adev->jpeg.inst->ras_poison_irq.funcs) {
+ r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0);
+ if (r)
+ goto late_fini;
+ }
+
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG,
&jpeg_v4_0_3_aca_info, NULL);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
index a90bf370a002..2e110d04af84 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.h
@@ -46,6 +46,13 @@
#define JRBC_DEC_EXTERNAL_REG_WRITE_ADDR 0x18000
+enum amdgpu_jpeg_v4_0_3_sub_block {
+ AMDGPU_JPEG_V4_0_3_JPEG0 = 0,
+ AMDGPU_JPEG_V4_0_3_JPEG1,
+
+ AMDGPU_JPEG_V4_0_3_MAX_SUB_BLOCK,
+};
+
extern const struct amdgpu_ip_block_version jpeg_v4_0_3_ip_block;
void jpeg_v4_0_3_dec_ring_emit_ib(struct amdgpu_ring *ring,
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
index cb94bd71300f..3b6f65a25646 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c
@@ -39,6 +39,7 @@ static void jpeg_v5_0_1_set_dec_ring_funcs(struct amdgpu_device *adev);
static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev);
static int jpeg_v5_0_1_set_powergating_state(struct amdgpu_ip_block *ip_block,
enum amd_powergating_state state);
+static void jpeg_v5_0_1_set_ras_funcs(struct amdgpu_device *adev);
static void jpeg_v5_0_1_dec_ring_set_wptr(struct amdgpu_ring *ring);
static int amdgpu_ih_srcid_jpeg[] = {
@@ -120,6 +121,7 @@ static int jpeg_v5_0_1_early_init(struct amdgpu_ip_block *ip_block)
adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS;
jpeg_v5_0_1_set_dec_ring_funcs(adev);
jpeg_v5_0_1_set_irq_funcs(adev);
+ jpeg_v5_0_1_set_ras_funcs(adev);
return 0;
}
@@ -144,6 +146,17 @@ static int jpeg_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
}
+ /* JPEG DJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_5_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
+ if (r)
+ return r;
+
+ /* JPEG EJPEG POISON EVENT */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_5_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
+ if (r)
+ return r;
r = amdgpu_jpeg_sw_init(adev);
if (r)
@@ -296,6 +309,9 @@ static int jpeg_v5_0_1_hw_fini(struct amdgpu_ip_block *ip_block)
ret = jpeg_v5_0_1_set_powergating_state(ip_block, AMD_PG_STATE_GATE);
}
+ if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
+ amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0);
+
return ret;
}
@@ -723,6 +739,16 @@ static int jpeg_v5_0_1_set_interrupt_state(struct amdgpu_device *adev,
return 0;
}
+static int jpeg_v5_0_1_set_ras_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned int type,
+ enum amdgpu_interrupt_state state)
+{
+ return 0;
+}
+
+
+
static int jpeg_v5_0_1_process_interrupt(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
@@ -892,6 +918,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v5_0_1_irq_funcs = {
.process = jpeg_v5_0_1_process_interrupt,
};
+static const struct amdgpu_irq_src_funcs jpeg_v5_0_1_ras_irq_funcs = {
+ .set = jpeg_v5_0_1_set_ras_interrupt_state,
+ .process = amdgpu_jpeg_process_poison_irq,
+};
+
static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev)
{
int i;
@@ -900,6 +931,10 @@ static void jpeg_v5_0_1_set_irq_funcs(struct amdgpu_device *adev)
adev->jpeg.inst->irq.num_types += adev->jpeg.num_jpeg_rings;
adev->jpeg.inst->irq.funcs = &jpeg_v5_0_1_irq_funcs;
+
+ adev->jpeg.inst->ras_poison_irq.num_types = 1;
+ adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v5_0_1_ras_irq_funcs;
+
}
const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block = {
@@ -909,3 +944,150 @@ const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block = {
.rev = 1,
.funcs = &jpeg_v5_0_1_ip_funcs,
};
+
+static uint32_t jpeg_v5_0_1_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_JPEG_V5_0_1_JPEG0:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG0_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG0_STATUS, POISONED_PF);
+ break;
+ case AMDGPU_JPEG_V5_0_1_JPEG1:
+ reg_value = RREG32_SOC15(JPEG, instance, regUVD_RAS_JPEG1_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_JPEG1_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in JPEG%d sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool jpeg_v5_0_1_query_ras_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst = 0, sub = 0, poison_stat = 0;
+
+ for (inst = 0; inst < adev->jpeg.num_jpeg_inst; inst++)
+ for (sub = 0; sub < AMDGPU_JPEG_V5_0_1_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ jpeg_v5_0_1_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
+static const struct amdgpu_ras_block_hw_ops jpeg_v5_0_1_ras_hw_ops = {
+ .query_poison_status = jpeg_v5_0_1_query_ras_poison_status,
+};
+
+static int jpeg_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
+ enum aca_smu_type type, void *data)
+{
+ struct aca_bank_info info;
+ u64 misc0;
+ int ret;
+
+ ret = aca_bank_info_decode(bank, &info);
+ if (ret)
+ return ret;
+
+ misc0 = bank->regs[ACA_REG_IDX_MISC0];
+ switch (type) {
+ case ACA_SMU_TYPE_UE:
+ bank->aca_err_type = ACA_ERROR_TYPE_UE;
+ ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
+ 1ULL);
+ break;
+ case ACA_SMU_TYPE_CE:
+ bank->aca_err_type = ACA_ERROR_TYPE_CE;
+ ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
+ ACA_REG__MISC0__ERRCNT(misc0));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/* reference to smu driver if header file */
+static int jpeg_v5_0_1_err_codes[] = {
+ 16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-7][S|D] */
+ 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+static bool jpeg_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
+ enum aca_smu_type type, void *data)
+{
+ u32 instlo;
+
+ instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
+ instlo &= GENMASK(31, 1);
+
+ if (instlo != mmSMNAID_AID0_MCA_SMU)
+ return false;
+
+ if (aca_bank_check_error_codes(handle->adev, bank,
+ jpeg_v5_0_1_err_codes,
+ ARRAY_SIZE(jpeg_v5_0_1_err_codes)))
+ return false;
+
+ return true;
+}
+
+static const struct aca_bank_ops jpeg_v5_0_1_aca_bank_ops = {
+ .aca_bank_parser = jpeg_v5_0_1_aca_bank_parser,
+ .aca_bank_is_valid = jpeg_v5_0_1_aca_bank_is_valid,
+};
+
+static const struct aca_info jpeg_v5_0_1_aca_info = {
+ .hwip = ACA_HWIP_TYPE_SMU,
+ .mask = ACA_ERROR_UE_MASK,
+ .bank_ops = &jpeg_v5_0_1_aca_bank_ops,
+};
+
+static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
+{
+ int r;
+
+ r = amdgpu_ras_block_late_init(adev, ras_block);
+ if (r)
+ return r;
+
+ if (amdgpu_ras_is_supported(adev, ras_block->block) &&
+ adev->jpeg.inst->ras_poison_irq.funcs) {
+ r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0);
+ if (r)
+ goto late_fini;
+ }
+
+ r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG,
+ &jpeg_v5_0_1_aca_info, NULL);
+ if (r)
+ goto late_fini;
+
+ return 0;
+
+late_fini:
+ amdgpu_ras_block_late_fini(adev, ras_block);
+
+ return r;
+}
+
+static struct amdgpu_jpeg_ras jpeg_v5_0_1_ras = {
+ .ras_block = {
+ .hw_ops = &jpeg_v5_0_1_ras_hw_ops,
+ .ras_late_init = jpeg_v5_0_1_ras_late_init,
+ },
+};
+
+static void jpeg_v5_0_1_set_ras_funcs(struct amdgpu_device *adev)
+{
+ adev->jpeg.ras = &jpeg_v5_0_1_ras;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h
index efdab57324e4..a7e58d5fb246 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.h
@@ -26,6 +26,9 @@
extern const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block;
+#define regUVD_JRBC0_UVD_JRBC_SCRATCH0_INTERNAL_OFFSET 0x4094
+#define regUVD_JRBC_EXTERNAL_MCM_ADDR_INTERNAL_OFFSET 0x1bffe
+
#define regUVD_JRBC0_UVD_JRBC_RB_WPTR 0x0640
#define regUVD_JRBC0_UVD_JRBC_RB_WPTR_BASE_IDX 1
#define regUVD_JRBC0_UVD_JRBC_STATUS 0x0649
@@ -98,4 +101,11 @@ extern const struct amdgpu_ip_block_version jpeg_v5_0_1_ip_block;
#define regVCN_RRMT_CNTL 0x0940
#define regVCN_RRMT_CNTL_BASE_IDX 1
+enum amdgpu_jpeg_v5_0_1_sub_block {
+ AMDGPU_JPEG_V5_0_1_JPEG0 = 0,
+ AMDGPU_JPEG_V5_0_1_JPEG1,
+
+ AMDGPU_JPEG_V5_0_1_MAX_SUB_BLOCK,
+};
+
#endif /* __JPEG_V5_0_1_H__ */
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
index da5b5d64f137..5a70ae17be04 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
@@ -44,6 +44,7 @@
#include "sdma_v6_0.h"
#include "v11_structs.h"
#include "mes_userqueue.h"
+#include "amdgpu_userq_fence.h"
MODULE_FIRMWARE("amdgpu/sdma_6_0_0.bin");
MODULE_FIRMWARE("amdgpu/sdma_6_0_1.bin");
@@ -893,6 +894,9 @@ static int sdma_v6_0_mqd_init(struct amdgpu_device *adev, void *mqd,
m->sdmax_rlcx_csa_addr_lo = lower_32_bits(prop->csa_addr);
m->sdmax_rlcx_csa_addr_hi = upper_32_bits(prop->csa_addr);
+ m->sdmax_rlcx_f32_dbg0 = lower_32_bits(prop->fence_address);
+ m->sdmax_rlcx_f32_dbg1 = upper_32_bits(prop->fence_address);
+
return 0;
}
@@ -1315,6 +1319,13 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
+ /* SDMA user fence event */
+ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX,
+ GFX_11_0_0__SRCID__SDMA_FENCE,
+ &adev->sdma.fence_irq);
+ if (r)
+ return r;
+
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
ring->ring_obj = NULL;
@@ -1575,25 +1586,9 @@ static int sdma_v6_0_process_trap_irq(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
int instances, queue;
- uint32_t mes_queue_id = entry->src_data[0];
DRM_DEBUG("IH: SDMA trap\n");
- if (adev->enable_mes && (mes_queue_id & AMDGPU_FENCE_MES_QUEUE_FLAG)) {
- struct amdgpu_mes_queue *queue;
-
- mes_queue_id &= AMDGPU_FENCE_MES_QUEUE_ID_MASK;
-
- spin_lock(&adev->mes.queue_id_lock);
- queue = idr_find(&adev->mes.queue_id_idr, mes_queue_id);
- if (queue) {
- DRM_DEBUG("process smda queue id = %d\n", mes_queue_id);
- amdgpu_fence_process(queue->ring);
- }
- spin_unlock(&adev->mes.queue_id_lock);
- return 0;
- }
-
queue = entry->ring_id & 0xf;
instances = (entry->ring_id & 0xf0) >> 4;
if (instances > 1) {
@@ -1615,6 +1610,29 @@ static int sdma_v6_0_process_trap_irq(struct amdgpu_device *adev,
return 0;
}
+static int sdma_v6_0_process_fence_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ u32 doorbell_offset = entry->src_data[0];
+
+ if (adev->enable_mes && doorbell_offset) {
+ struct amdgpu_userq_fence_driver *fence_drv = NULL;
+ struct xarray *xa = &adev->userq_xa;
+ unsigned long flags;
+
+ doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ xa_lock_irqsave(xa, flags);
+ fence_drv = xa_load(xa, doorbell_offset);
+ if (fence_drv)
+ amdgpu_userq_fence_driver_process(fence_drv);
+ xa_unlock_irqrestore(xa, flags);
+ }
+
+ return 0;
+}
+
static int sdma_v6_0_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
@@ -1751,6 +1769,10 @@ static const struct amdgpu_irq_src_funcs sdma_v6_0_trap_irq_funcs = {
.process = sdma_v6_0_process_trap_irq,
};
+static const struct amdgpu_irq_src_funcs sdma_v6_0_fence_irq_funcs = {
+ .process = sdma_v6_0_process_fence_irq,
+};
+
static const struct amdgpu_irq_src_funcs sdma_v6_0_illegal_inst_irq_funcs = {
.process = sdma_v6_0_process_illegal_inst_irq,
};
@@ -1760,6 +1782,7 @@ static void sdma_v6_0_set_irq_funcs(struct amdgpu_device *adev)
adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_INSTANCE0 +
adev->sdma.num_instances;
adev->sdma.trap_irq.funcs = &sdma_v6_0_trap_irq_funcs;
+ adev->sdma.fence_irq.funcs = &sdma_v6_0_fence_irq_funcs;
adev->sdma.illegal_inst_irq.funcs = &sdma_v6_0_illegal_inst_irq_funcs;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
index befe013b11a7..ad47d0bdf777 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c
@@ -33,7 +33,7 @@
#include "gc/gc_12_0_0_offset.h"
#include "gc/gc_12_0_0_sh_mask.h"
#include "hdp/hdp_6_0_0_offset.h"
-#include "ivsrcid/gfx/irqsrcs_gfx_11_0_0.h"
+#include "ivsrcid/gfx/irqsrcs_gfx_12_0_0.h"
#include "soc15_common.h"
#include "soc15.h"
@@ -43,6 +43,7 @@
#include "sdma_v7_0.h"
#include "v12_structs.h"
#include "mes_userqueue.h"
+#include "amdgpu_userq_fence.h"
MODULE_FIRMWARE("amdgpu/sdma_7_0_0.bin");
MODULE_FIRMWARE("amdgpu/sdma_7_0_1.bin");
@@ -910,6 +911,9 @@ static int sdma_v7_0_mqd_init(struct amdgpu_device *adev, void *mqd,
m->sdmax_rlcx_csa_addr_lo = lower_32_bits(prop->csa_addr);
m->sdmax_rlcx_csa_addr_hi = upper_32_bits(prop->csa_addr);
+ m->sdmax_rlcx_mcu_dbg0 = lower_32_bits(prop->fence_address);
+ m->sdmax_rlcx_mcu_dbg1 = upper_32_bits(prop->fence_address);
+
return 0;
}
@@ -1296,11 +1300,18 @@ static int sdma_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
/* SDMA trap event */
r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX,
- GFX_11_0_0__SRCID__SDMA_TRAP,
+ GFX_12_0_0__SRCID__SDMA_TRAP,
&adev->sdma.trap_irq);
if (r)
return r;
+ /* SDMA user fence event */
+ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GFX,
+ GFX_12_0_0__SRCID__SDMA_FENCE,
+ &adev->sdma.fence_irq);
+ if (r)
+ return r;
+
for (i = 0; i < adev->sdma.num_instances; i++) {
ring = &adev->sdma.instance[i].ring;
ring->ring_obj = NULL;
@@ -1526,25 +1537,9 @@ static int sdma_v7_0_process_trap_irq(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
int instances, queue;
- uint32_t mes_queue_id = entry->src_data[0];
DRM_DEBUG("IH: SDMA trap\n");
- if (adev->enable_mes && (mes_queue_id & AMDGPU_FENCE_MES_QUEUE_FLAG)) {
- struct amdgpu_mes_queue *queue;
-
- mes_queue_id &= AMDGPU_FENCE_MES_QUEUE_ID_MASK;
-
- spin_lock(&adev->mes.queue_id_lock);
- queue = idr_find(&adev->mes.queue_id_idr, mes_queue_id);
- if (queue) {
- DRM_DEBUG("process smda queue id = %d\n", mes_queue_id);
- amdgpu_fence_process(queue->ring);
- }
- spin_unlock(&adev->mes.queue_id_lock);
- return 0;
- }
-
queue = entry->ring_id & 0xf;
instances = (entry->ring_id & 0xf0) >> 4;
if (instances > 1) {
@@ -1566,6 +1561,29 @@ static int sdma_v7_0_process_trap_irq(struct amdgpu_device *adev,
return 0;
}
+static int sdma_v7_0_process_fence_irq(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ struct amdgpu_iv_entry *entry)
+{
+ u32 doorbell_offset = entry->src_data[0];
+
+ if (adev->enable_mes && doorbell_offset) {
+ struct amdgpu_userq_fence_driver *fence_drv = NULL;
+ struct xarray *xa = &adev->userq_xa;
+ unsigned long flags;
+
+ doorbell_offset >>= SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ xa_lock_irqsave(xa, flags);
+ fence_drv = xa_load(xa, doorbell_offset);
+ if (fence_drv)
+ amdgpu_userq_fence_driver_process(fence_drv);
+ xa_unlock_irqrestore(xa, flags);
+ }
+
+ return 0;
+}
+
static int sdma_v7_0_process_illegal_inst_irq(struct amdgpu_device *adev,
struct amdgpu_irq_src *source,
struct amdgpu_iv_entry *entry)
@@ -1703,6 +1721,10 @@ static const struct amdgpu_irq_src_funcs sdma_v7_0_trap_irq_funcs = {
.process = sdma_v7_0_process_trap_irq,
};
+static const struct amdgpu_irq_src_funcs sdma_v7_0_fence_irq_funcs = {
+ .process = sdma_v7_0_process_fence_irq,
+};
+
static const struct amdgpu_irq_src_funcs sdma_v7_0_illegal_inst_irq_funcs = {
.process = sdma_v7_0_process_illegal_inst_irq,
};
@@ -1712,6 +1734,7 @@ static void sdma_v7_0_set_irq_funcs(struct amdgpu_device *adev)
adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_INSTANCE0 +
adev->sdma.num_instances;
adev->sdma.trap_irq.funcs = &sdma_v7_0_trap_irq_funcs;
+ adev->sdma.fence_irq.funcs = &sdma_v7_0_fence_irq_funcs;
adev->sdma.illegal_inst_irq.funcs = &sdma_v7_0_illegal_inst_irq_funcs;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
index 21b57c29bf7d..c74947705d77 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
@@ -1009,6 +1009,11 @@ static int vcn_v1_0_start_spg_mode(struct amdgpu_vcn_inst *vinst)
jpeg_v1_0_start(adev, 0);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1154,6 +1159,11 @@ static int vcn_v1_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst)
jpeg_v1_0_start(adev, 1);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1216,6 +1226,12 @@ static int vcn_v1_0_stop_spg_mode(struct amdgpu_vcn_inst *vinst)
vcn_v1_0_enable_clock_gating(vinst);
vcn_1_0_enable_static_power_gating(vinst);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1250,6 +1266,11 @@ static int vcn_v1_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
index b8d835c9e17e..148b651be7ca 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
@@ -978,6 +978,12 @@ static int vcn_v2_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect)
/* Unstall DPG */
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS),
0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1152,6 +1158,11 @@ static int vcn_v2_0_start(struct amdgpu_vcn_inst *vinst)
WREG32_SOC15(UVD, 0, mmUVD_RB_SIZE2, ring->ring_size / 4);
fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1183,6 +1194,11 @@ static int vcn_v2_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
WREG32_P(SOC15_REG_OFFSET(UVD, 0, mmUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(UVD, 0, mmUVD_STATUS);
+
return 0;
}
@@ -1248,6 +1264,11 @@ static int vcn_v2_0_stop(struct amdgpu_vcn_inst *vinst)
vcn_v2_0_enable_clock_gating(vinst);
vcn_v2_0_enable_static_power_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, 0, mmUVD_STATUS);
+
power_off:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, 0);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
index 3eec1b8feaee..58b527a6b795 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
@@ -1158,6 +1158,11 @@ static int vcn_v2_5_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect)
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS);
+
return 0;
}
@@ -1343,6 +1348,11 @@ static int vcn_v2_5_start(struct amdgpu_vcn_inst *vinst)
WREG32_SOC15(VCN, i, mmUVD_RB_SIZE2, ring->ring_size / 4);
fw_shared->multi_queue.encode_lowlatency_queue_mode &= ~FW_QUEUE_RING_RESET;
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, mmUVD_STATUS);
+
return 0;
}
@@ -1569,6 +1579,11 @@ static int vcn_v2_5_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS);
+
return 0;
}
@@ -1635,6 +1650,10 @@ static int vcn_v2_5_stop(struct amdgpu_vcn_inst *vinst)
UVD_POWER_STATUS__UVD_POWER_STATUS_MASK,
~UVD_POWER_STATUS__UVD_POWER_STATUS_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, mmUVD_STATUS);
done:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, i);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
index 0b19f0ab4480..9fb0d5380589 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
@@ -1173,6 +1173,11 @@ static int vcn_v3_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect)
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS),
0, ~UVD_POWER_STATUS__STALL_DPG_POWER_UP_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS);
+
return 0;
}
@@ -1360,6 +1365,11 @@ static int vcn_v3_0_start(struct amdgpu_vcn_inst *vinst)
fw_shared->multi_queue.encode_lowlatency_queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
}
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, mmUVD_STATUS);
+
return 0;
}
@@ -1602,6 +1612,11 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, mmUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, mmUVD_STATUS);
+
return 0;
}
@@ -1674,6 +1689,11 @@ static int vcn_v3_0_stop(struct amdgpu_vcn_inst *vinst)
/* enable VCN power gating */
vcn_v3_0_enable_static_power_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, mmUVD_STATUS);
+
done:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, i);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
index 8fff470bce87..b5071f77f78d 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
@@ -1122,6 +1122,11 @@ static int vcn_v4_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst, bool indirect)
ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
VCN_RB1_DB_CTRL__EN_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, regUVD_STATUS);
+
return 0;
}
@@ -1303,6 +1308,11 @@ static int vcn_v4_0_start(struct amdgpu_vcn_inst *vinst)
WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, regUVD_STATUS);
+
return 0;
}
@@ -1583,6 +1593,11 @@ static void vcn_v4_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
/* disable dynamic power gating mode */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, regUVD_STATUS);
}
/**
@@ -1666,6 +1681,11 @@ static int vcn_v4_0_stop(struct amdgpu_vcn_inst *vinst)
/* enable VCN power gating */
vcn_v4_0_enable_static_power_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, regUVD_STATUS);
+
done:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, i);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
index 712e1fba33ce..5a33140f5723 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
@@ -169,6 +169,10 @@ static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
+ /* VCN POISON TRAP */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst->ras_poison_irq);
+
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
r = amdgpu_vcn_sw_init(adev, i);
@@ -387,6 +391,9 @@ static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block)
vinst->set_pg_state(vinst, AMD_PG_STATE_GATE);
}
+ if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+ amdgpu_irq_put(adev, &adev->vcn.inst->ras_poison_irq, 0);
+
return 0;
}
@@ -970,6 +977,11 @@ static int vcn_v4_0_3_start_dpg_mode(struct amdgpu_vcn_inst *vinst,
/*resetting done, fw can check RB ring */
fw_shared->sq.queue_mode &= cpu_to_le32(~FW_QUEUE_RING_RESET);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
+
return 0;
}
@@ -1363,6 +1375,12 @@ static int vcn_v4_0_3_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
/* disable dynamic power gating mode */
WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
+
return 0;
}
@@ -1446,6 +1464,11 @@ static int vcn_v4_0_3_stop(struct amdgpu_vcn_inst *vinst)
/* apply HW clock gating */
vcn_v4_0_3_enable_clock_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
+
Done:
return 0;
}
@@ -1814,11 +1837,24 @@ static int vcn_v4_0_3_process_interrupt(struct amdgpu_device *adev,
return 0;
}
+static int vcn_v4_0_3_set_ras_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned int type,
+ enum amdgpu_interrupt_state state)
+{
+ return 0;
+}
+
static const struct amdgpu_irq_src_funcs vcn_v4_0_3_irq_funcs = {
.set = vcn_v4_0_3_set_interrupt_state,
.process = vcn_v4_0_3_process_interrupt,
};
+static const struct amdgpu_irq_src_funcs vcn_v4_0_3_ras_irq_funcs = {
+ .set = vcn_v4_0_3_set_ras_interrupt_state,
+ .process = amdgpu_vcn_process_poison_irq,
+};
+
/**
* vcn_v4_0_3_set_irq_funcs - set VCN block interrupt irq functions
*
@@ -1834,6 +1870,9 @@ static void vcn_v4_0_3_set_irq_funcs(struct amdgpu_device *adev)
adev->vcn.inst->irq.num_types++;
}
adev->vcn.inst->irq.funcs = &vcn_v4_0_3_irq_funcs;
+
+ adev->vcn.inst->ras_poison_irq.num_types = 1;
+ adev->vcn.inst->ras_poison_irq.funcs = &vcn_v4_0_3_ras_irq_funcs;
}
static void vcn_v4_0_3_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p)
@@ -1981,9 +2020,44 @@ static void vcn_v4_0_3_reset_ras_error_count(struct amdgpu_device *adev)
vcn_v4_0_3_inst_reset_ras_error_count(adev, i);
}
+static uint32_t vcn_v4_0_3_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_VCN_V4_0_3_VCPU_VCODEC:
+ reg_value = RREG32_SOC15(VCN, instance, regUVD_RAS_VCPU_VCODEC_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_VCPU_VCODEC_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in VCN%d, sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool vcn_v4_0_3_query_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst, sub;
+ uint32_t poison_stat = 0;
+
+ for (inst = 0; inst < adev->vcn.num_vcn_inst; inst++)
+ for (sub = 0; sub < AMDGPU_VCN_V4_0_3_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ vcn_v4_0_3_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
static const struct amdgpu_ras_block_hw_ops vcn_v4_0_3_ras_hw_ops = {
.query_ras_error_count = vcn_v4_0_3_query_ras_error_count,
.reset_ras_error_count = vcn_v4_0_3_reset_ras_error_count,
+ .query_poison_status = vcn_v4_0_3_query_poison_status,
};
static int vcn_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
@@ -2059,6 +2133,13 @@ static int vcn_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_commo
if (r)
return r;
+ if (amdgpu_ras_is_supported(adev, ras_block->block) &&
+ adev->vcn.inst->ras_poison_irq.funcs) {
+ r = amdgpu_irq_get(adev, &adev->vcn.inst->ras_poison_irq, 0);
+ if (r)
+ goto late_fini;
+ }
+
r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN,
&vcn_v4_0_3_aca_info, NULL);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
index 03572a1d0c9c..aeab89853a92 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.h
@@ -24,6 +24,12 @@
#ifndef __VCN_V4_0_3_H__
#define __VCN_V4_0_3_H__
+enum amdgpu_vcn_v4_0_3_sub_block {
+ AMDGPU_VCN_V4_0_3_VCPU_VCODEC = 0,
+
+ AMDGPU_VCN_V4_0_3_MAX_SUB_BLOCK,
+};
+
extern const struct amdgpu_ip_block_version vcn_v4_0_3_ip_block;
void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg,
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
index a09f9a2dd471..16ade84facc7 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
@@ -1254,6 +1254,11 @@ static void vcn_v4_0_5_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
/* disable dynamic power gating mode */
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, regUVD_STATUS);
}
/**
@@ -1337,6 +1342,11 @@ static int vcn_v4_0_5_stop(struct amdgpu_vcn_inst *vinst)
/* enable VCN power gating */
vcn_v4_0_5_enable_static_power_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, regUVD_STATUS);
+
done:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, i);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
index 27dcc6f37a73..f8e3f0b882da 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
@@ -794,6 +794,11 @@ static int vcn_v5_0_0_start_dpg_mode(struct amdgpu_vcn_inst *vinst,
ring->doorbell_index << VCN_RB1_DB_CTRL__OFFSET__SHIFT |
VCN_RB1_DB_CTRL__EN_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, regUVD_STATUS);
+
return 0;
}
@@ -946,6 +951,11 @@ static int vcn_v5_0_0_start(struct amdgpu_vcn_inst *vinst)
WREG32_SOC15(VCN, i, regVCN_RB_ENABLE, tmp);
fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, regUVD_STATUS);
+
return 0;
}
@@ -977,6 +987,11 @@ static void vcn_v5_0_0_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
WREG32_P(SOC15_REG_OFFSET(VCN, inst_idx, regUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, inst_idx, regUVD_STATUS);
+
return;
}
@@ -1058,6 +1073,11 @@ static int vcn_v5_0_0_stop(struct amdgpu_vcn_inst *vinst)
/* enable VCN power gating */
vcn_v5_0_0_enable_static_power_gating(vinst);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, i, regUVD_STATUS);
+
done:
if (adev->pm.dpm_enabled)
amdgpu_dpm_enable_vcn(adev, false, i);
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
index 8e843011703c..338cf43c45fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c
@@ -46,7 +46,7 @@ static void vcn_v5_0_1_set_irq_funcs(struct amdgpu_device *adev);
static int vcn_v5_0_1_set_pg_state(struct amdgpu_vcn_inst *vinst,
enum amd_powergating_state state);
static void vcn_v5_0_1_unified_ring_set_wptr(struct amdgpu_ring *ring);
-
+static void vcn_v5_0_1_set_ras_funcs(struct amdgpu_device *adev);
/**
* vcn_v5_0_1_early_init - set function pointers and load microcode
*
@@ -66,6 +66,7 @@ static int vcn_v5_0_1_early_init(struct amdgpu_ip_block *ip_block)
vcn_v5_0_1_set_unified_ring_funcs(adev);
vcn_v5_0_1_set_irq_funcs(adev);
+ vcn_v5_0_1_set_ras_funcs(adev);
for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
adev->vcn.inst[i].set_pg_state = vcn_v5_0_1_set_pg_state;
@@ -113,6 +114,10 @@ static int vcn_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block)
if (r)
return r;
+ /* VCN POISON TRAP */
+ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
+ VCN_5_0__SRCID_UVD_POISON, &adev->vcn.inst->ras_poison_irq);
+
for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
vcn_inst = GET_INST(VCN, i);
@@ -279,6 +284,9 @@ static int vcn_v5_0_1_hw_fini(struct amdgpu_ip_block *ip_block)
vinst->set_pg_state(vinst, AMD_PG_STATE_GATE);
}
+ if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+ amdgpu_irq_put(adev, &adev->vcn.inst->ras_poison_irq, 0);
+
return 0;
}
@@ -1030,6 +1038,11 @@ static int vcn_v5_0_1_start(struct amdgpu_vcn_inst *vinst)
WREG32_SOC15(VCN, vcn_inst, regVCN_RB_ENABLE, tmp);
fw_shared->sq.queue_mode &= ~(FW_QUEUE_RING_RESET | FW_QUEUE_DPG_HOLD_OFF);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
+
return 0;
}
@@ -1064,6 +1077,11 @@ static void vcn_v5_0_1_stop_dpg_mode(struct amdgpu_vcn_inst *vinst)
/* disable dynamic power gating mode */
WREG32_P(SOC15_REG_OFFSET(VCN, vcn_inst, regUVD_POWER_STATUS), 0,
~UVD_POWER_STATUS__UVD_PG_MODE_MASK);
+
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
}
/**
@@ -1139,6 +1157,11 @@ static int vcn_v5_0_1_stop(struct amdgpu_vcn_inst *vinst)
/* clear status */
WREG32_SOC15(VCN, vcn_inst, regUVD_STATUS, 0);
+ /* Keeping one read-back to ensure all register writes are done,
+ * otherwise it may introduce race conditions.
+ */
+ RREG32_SOC15(VCN, vcn_inst, regUVD_STATUS);
+
return 0;
}
@@ -1391,10 +1414,24 @@ static int vcn_v5_0_1_process_interrupt(struct amdgpu_device *adev, struct amdgp
return 0;
}
+static int vcn_v5_0_1_set_ras_interrupt_state(struct amdgpu_device *adev,
+ struct amdgpu_irq_src *source,
+ unsigned int type,
+ enum amdgpu_interrupt_state state)
+{
+ return 0;
+}
+
static const struct amdgpu_irq_src_funcs vcn_v5_0_1_irq_funcs = {
.process = vcn_v5_0_1_process_interrupt,
};
+static const struct amdgpu_irq_src_funcs vcn_v5_0_1_ras_irq_funcs = {
+ .set = vcn_v5_0_1_set_ras_interrupt_state,
+ .process = amdgpu_vcn_process_poison_irq,
+};
+
+
/**
* vcn_v5_0_1_set_irq_funcs - set VCN block interrupt irq functions
*
@@ -1408,7 +1445,12 @@ static void vcn_v5_0_1_set_irq_funcs(struct amdgpu_device *adev)
for (i = 0; i < adev->vcn.num_vcn_inst; ++i)
adev->vcn.inst->irq.num_types++;
+
adev->vcn.inst->irq.funcs = &vcn_v5_0_1_irq_funcs;
+
+ adev->vcn.inst->ras_poison_irq.num_types = 1;
+ adev->vcn.inst->ras_poison_irq.funcs = &vcn_v5_0_1_ras_irq_funcs;
+
}
static const struct amd_ip_funcs vcn_v5_0_1_ip_funcs = {
@@ -1440,3 +1482,139 @@ const struct amdgpu_ip_block_version vcn_v5_0_1_ip_block = {
.rev = 1,
.funcs = &vcn_v5_0_1_ip_funcs,
};
+
+static uint32_t vcn_v5_0_1_query_poison_by_instance(struct amdgpu_device *adev,
+ uint32_t instance, uint32_t sub_block)
+{
+ uint32_t poison_stat = 0, reg_value = 0;
+
+ switch (sub_block) {
+ case AMDGPU_VCN_V5_0_1_VCPU_VCODEC:
+ reg_value = RREG32_SOC15(VCN, instance, regUVD_RAS_VCPU_VCODEC_STATUS);
+ poison_stat = REG_GET_FIELD(reg_value, UVD_RAS_VCPU_VCODEC_STATUS, POISONED_PF);
+ break;
+ default:
+ break;
+ }
+
+ if (poison_stat)
+ dev_info(adev->dev, "Poison detected in VCN%d, sub_block%d\n",
+ instance, sub_block);
+
+ return poison_stat;
+}
+
+static bool vcn_v5_0_1_query_poison_status(struct amdgpu_device *adev)
+{
+ uint32_t inst, sub;
+ uint32_t poison_stat = 0;
+
+ for (inst = 0; inst < adev->vcn.num_vcn_inst; inst++)
+ for (sub = 0; sub < AMDGPU_VCN_V5_0_1_MAX_SUB_BLOCK; sub++)
+ poison_stat +=
+ vcn_v5_0_1_query_poison_by_instance(adev, inst, sub);
+
+ return !!poison_stat;
+}
+
+static const struct amdgpu_ras_block_hw_ops vcn_v5_0_1_ras_hw_ops = {
+ .query_poison_status = vcn_v5_0_1_query_poison_status,
+};
+
+static int vcn_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank,
+ enum aca_smu_type type, void *data)
+{
+ struct aca_bank_info info;
+ u64 misc0;
+ int ret;
+
+ ret = aca_bank_info_decode(bank, &info);
+ if (ret)
+ return ret;
+
+ misc0 = bank->regs[ACA_REG_IDX_MISC0];
+ switch (type) {
+ case ACA_SMU_TYPE_UE:
+ bank->aca_err_type = ACA_ERROR_TYPE_UE;
+ ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE,
+ 1ULL);
+ break;
+ case ACA_SMU_TYPE_CE:
+ bank->aca_err_type = ACA_ERROR_TYPE_CE;
+ ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type,
+ ACA_REG__MISC0__ERRCNT(misc0));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/* reference to smu driver if header file */
+static int vcn_v5_0_1_err_codes[] = {
+ 14, 15, /* VCN */
+};
+
+static bool vcn_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank,
+ enum aca_smu_type type, void *data)
+{
+ u32 instlo;
+
+ instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]);
+ instlo &= GENMASK(31, 1);
+
+ if (instlo != mmSMNAID_AID0_MCA_SMU)
+ return false;
+
+ if (aca_bank_check_error_codes(handle->adev, bank,
+ vcn_v5_0_1_err_codes,
+ ARRAY_SIZE(vcn_v5_0_1_err_codes)))
+ return false;
+
+ return true;
+}
+
+static const struct aca_bank_ops vcn_v5_0_1_aca_bank_ops = {
+ .aca_bank_parser = vcn_v5_0_1_aca_bank_parser,
+ .aca_bank_is_valid = vcn_v5_0_1_aca_bank_is_valid,
+};
+
+static const struct aca_info vcn_v5_0_1_aca_info = {
+ .hwip = ACA_HWIP_TYPE_SMU,
+ .mask = ACA_ERROR_UE_MASK,
+ .bank_ops = &vcn_v5_0_1_aca_bank_ops,
+};
+
+static int vcn_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
+{
+ int r;
+
+ r = amdgpu_ras_block_late_init(adev, ras_block);
+ if (r)
+ return r;
+
+ r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN,
+ &vcn_v5_0_1_aca_info, NULL);
+ if (r)
+ goto late_fini;
+
+ return 0;
+
+late_fini:
+ amdgpu_ras_block_late_fini(adev, ras_block);
+
+ return r;
+}
+
+static struct amdgpu_vcn_ras vcn_v5_0_1_ras = {
+ .ras_block = {
+ .hw_ops = &vcn_v5_0_1_ras_hw_ops,
+ .ras_late_init = vcn_v5_0_1_ras_late_init,
+ },
+};
+
+static void vcn_v5_0_1_set_ras_funcs(struct amdgpu_device *adev)
+{
+ adev->vcn.ras = &vcn_v5_0_1_ras;
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h
index 8fd90bd10807..b72e4da68317 100644
--- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h
+++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.h
@@ -27,6 +27,13 @@
#define regVCN_RRMT_CNTL 0x0940
#define regVCN_RRMT_CNTL_BASE_IDX 1
+
+enum amdgpu_vcn_v5_0_1_sub_block {
+ AMDGPU_VCN_V5_0_1_VCPU_VCODEC = 0,
+
+ AMDGPU_VCN_V5_0_1_MAX_SUB_BLOCK,
+};
+
extern const struct amdgpu_ip_block_version vcn_v5_0_1_ip_block;
#endif /* __VCN_v5_0_1_H__ */
diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig
index d3c3d3ab7225..62e88e5362e9 100644
--- a/drivers/gpu/drm/amd/amdkfd/Kconfig
+++ b/drivers/gpu/drm/amd/amdkfd/Kconfig
@@ -5,7 +5,7 @@
config HSA_AMD
bool "HSA kernel driver for AMD GPU devices"
- depends on DRM_AMDGPU && (X86_64 || ARM64 || PPC64)
+ depends on DRM_AMDGPU && (X86_64 || ARM64 || PPC64 || (RISCV && 64BIT))
select HMM_MIRROR
select MMU_NOTIFIER
select DRM_AMDGPU_USERPTR
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
index 981d9adcc5e1..73acbe0b7c21 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
+++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c
@@ -91,7 +91,6 @@ static void cik_event_interrupt_wq(struct kfd_node *dev,
const struct cik_ih_ring_entry *ihre =
(const struct cik_ih_ring_entry *)ih_ring_entry;
uint32_t context_id = ihre->data & 0xfffffff;
- unsigned int vmid = (ihre->ring_id & 0x0000ff00) >> 8;
u32 pasid = (ihre->ring_id & 0xffff0000) >> 16;
if (pasid == 0)
@@ -125,11 +124,7 @@ static void cik_event_interrupt_wq(struct kfd_node *dev,
return;
}
- if (info.vmid == vmid)
- kfd_signal_vm_fault_event(pdd, &info, NULL);
- else
- kfd_signal_vm_fault_event(pdd, &info, NULL);
-
+ kfd_signal_vm_fault_event(pdd, &info, NULL);
kfd_unref_process(p);
}
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 1e9dd00620bf..a2149afa5803 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -2039,9 +2039,7 @@ static int criu_get_process_object_info(struct kfd_process *p,
num_events = kfd_get_num_events(p);
- ret = svm_range_get_info(p, &num_svm_ranges, &svm_priv_data_size);
- if (ret)
- return ret;
+ svm_range_get_info(p, &num_svm_ranges, &svm_priv_data_size);
*num_objects = num_queues + num_events + num_svm_ranges;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
index e54e708ed82d..2b294ada3ec0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
@@ -1350,6 +1350,7 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid)
user_gpu_id = kfd_process_get_user_gpu_id(p, dev->id);
if (unlikely(user_gpu_id == -EINVAL)) {
WARN_ONCE(1, "Could not get user_gpu_id from dev->id:%x\n", dev->id);
+ kfd_unref_process(p);
return;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index 6d5fa57d4a23..c643e0ccec52 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -279,20 +279,17 @@ static int init_user_queue(struct process_queue_manager *pqm,
/* Starting with GFX11, wptr BOs must be mapped to GART for MES to determine work
* on unmapped queues for usermode queue oversubscription (no aggregated doorbell)
*/
- if (((dev->adev->mes.sched_version & AMDGPU_MES_API_VERSION_MASK)
- >> AMDGPU_MES_API_VERSION_SHIFT) >= 2) {
- if (dev->adev != amdgpu_ttm_adev(q_properties->wptr_bo->tbo.bdev)) {
- pr_err("Queue memory allocated to wrong device\n");
- retval = -EINVAL;
- goto free_gang_ctx_bo;
- }
+ if (dev->adev != amdgpu_ttm_adev(q_properties->wptr_bo->tbo.bdev)) {
+ pr_err("Queue memory allocated to wrong device\n");
+ retval = -EINVAL;
+ goto free_gang_ctx_bo;
+ }
- retval = amdgpu_amdkfd_map_gtt_bo_to_gart(q_properties->wptr_bo,
- &(*q)->wptr_bo_gart);
- if (retval) {
- pr_err("Failed to map wptr bo to GART\n");
- goto free_gang_ctx_bo;
- }
+ retval = amdgpu_amdkfd_map_gtt_bo_to_gart(q_properties->wptr_bo,
+ &(*q)->wptr_bo_gart);
+ if (retval) {
+ pr_err("Failed to map wptr bo to GART\n");
+ goto free_gang_ctx_bo;
}
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 72be6e152e88..865dca2547de 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -4075,8 +4075,8 @@ exit:
return ret;
}
-int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
- uint64_t *svm_priv_data_size)
+void svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
+ uint64_t *svm_priv_data_size)
{
uint64_t total_size, accessibility_size, common_attr_size;
int nattr_common = 4, nattr_accessibility = 1;
@@ -4088,8 +4088,6 @@ int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
*svm_priv_data_size = 0;
svms = &p->svms;
- if (!svms)
- return -EINVAL;
mutex_lock(&svms->lock);
list_for_each_entry(prange, &svms->list, list) {
@@ -4131,7 +4129,6 @@ int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
pr_debug("num_svm_ranges %u total_priv_size %llu\n", *num_svm_ranges,
*svm_priv_data_size);
- return 0;
}
int kfd_criu_checkpoint_svm(struct kfd_process *p,
@@ -4148,8 +4145,6 @@ int kfd_criu_checkpoint_svm(struct kfd_process *p,
struct mm_struct *mm;
svms = &p->svms;
- if (!svms)
- return -EINVAL;
mm = get_task_mm(p->lead_thread);
if (!mm) {
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
index 6ea23c78009c..01c7a4877904 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h
@@ -184,8 +184,8 @@ void schedule_deferred_list_work(struct svm_range_list *svms);
void svm_range_dma_unmap_dev(struct device *dev, dma_addr_t *dma_addr,
unsigned long offset, unsigned long npages);
void svm_range_dma_unmap(struct svm_range *prange);
-int svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
- uint64_t *svm_priv_data_size);
+void svm_range_get_info(struct kfd_process *p, uint32_t *num_svm_ranges,
+ uint64_t *svm_priv_data_size);
int kfd_criu_checkpoint_svm(struct kfd_process *p,
uint8_t __user *user_priv_data,
uint64_t *priv_offset);
@@ -237,13 +237,12 @@ static inline int svm_range_schedule_evict_svm_bo(
return -EINVAL;
}
-static inline int svm_range_get_info(struct kfd_process *p,
- uint32_t *num_svm_ranges,
- uint64_t *svm_priv_data_size)
+static inline void svm_range_get_info(struct kfd_process *p,
+ uint32_t *num_svm_ranges,
+ uint64_t *svm_priv_data_size)
{
*num_svm_ranges = 0;
*svm_priv_data_size = 0;
- return 0;
}
static inline int kfd_criu_checkpoint_svm(struct kfd_process *p,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 742b10881112..d3100f641ac6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -676,21 +676,15 @@ static void dm_crtc_high_irq(void *interrupt_params)
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
if (acrtc->dm_irq_params.stream &&
- acrtc->dm_irq_params.vrr_params.supported) {
- bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled;
- bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled;
- bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE;
-
+ acrtc->dm_irq_params.vrr_params.supported &&
+ acrtc->dm_irq_params.freesync_config.state ==
+ VRR_STATE_ACTIVE_VARIABLE) {
mod_freesync_handle_v_update(adev->dm.freesync_module,
acrtc->dm_irq_params.stream,
&acrtc->dm_irq_params.vrr_params);
- /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */
- if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) {
- dc_stream_adjust_vmin_vmax(adev->dm.dc,
- acrtc->dm_irq_params.stream,
- &acrtc->dm_irq_params.vrr_params.adjust);
- }
+ dc_stream_adjust_vmin_vmax(adev->dm.dc, acrtc->dm_irq_params.stream,
+ &acrtc->dm_irq_params.vrr_params.adjust);
}
/*
@@ -2006,8 +2000,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_debug_mask & DC_FORCE_SUBVP_MCLK_SWITCH)
adev->dm.dc->debug.force_subvp_mclk_switch = true;
- if (amdgpu_dc_debug_mask & DC_DISABLE_SUBVP)
+ if (amdgpu_dc_debug_mask & DC_DISABLE_SUBVP_FAMS) {
adev->dm.dc->debug.force_disable_subvp = true;
+ adev->dm.dc->debug.fams2_config.bits.enable = false;
+ }
if (amdgpu_dc_debug_mask & DC_ENABLE_DML2) {
adev->dm.dc->debug.using_dml2 = true;
@@ -2020,6 +2016,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_debug_mask & DC_HDCP_LC_ENABLE_SW_FALLBACK)
adev->dm.dc->debug.hdcp_lc_enable_sw_fallback = true;
+ if (amdgpu_dc_debug_mask & DC_SKIP_DETECTION_LT)
+ adev->dm.dc->debug.skip_detection_link_training = true;
+
adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm;
/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
@@ -4911,6 +4910,7 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
struct backlight_properties props = { 0 };
struct amdgpu_dm_backlight_caps caps = { 0 };
char bl_name[16];
+ int min, max;
if (aconnector->bl_idx == -1)
return;
@@ -4923,11 +4923,15 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector)
}
amdgpu_acpi_get_backlight_caps(&caps);
- if (caps.caps_valid) {
+ if (caps.caps_valid && get_brightness_range(&caps, &min, &max)) {
if (power_supply_is_system_supplied() > 0)
- props.brightness = caps.ac_level;
+ props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.ac_level, 100);
else
- props.brightness = caps.dc_level;
+ props.brightness = (max - min) * DIV_ROUND_CLOSEST(caps.dc_level, 100);
+ /* min is zero, so max needs to be adjusted */
+ props.max_brightness = max - min;
+ drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max,
+ caps.ac_level, caps.dc_level);
} else
props.brightness = AMDGPU_MAX_BL_LEVEL;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index e8bdd7f0c460..87058271b00c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -246,8 +246,6 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
struct vblank_control_work *vblank_work =
container_of(work, struct vblank_control_work, work);
struct amdgpu_display_manager *dm = vblank_work->dm;
- struct amdgpu_device *adev = drm_to_adev(dm->ddev);
- int r;
mutex_lock(&dm->dc_lock);
@@ -275,15 +273,8 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
vblank_work->acrtc->dm_irq_params.allow_sr_entry);
}
- if (dm->active_vblank_irq_count == 0) {
- r = amdgpu_dpm_pause_power_profile(adev, true);
- if (r)
- dev_warn(adev->dev, "failed to set default power profile mode\n");
+ if (dm->active_vblank_irq_count == 0)
dc_allow_idle_optimizations(dm->dc, true);
- r = amdgpu_dpm_pause_power_profile(adev, false);
- if (r)
- dev_warn(adev->dev, "failed to restore the power profile mode\n");
- }
mutex_unlock(&dm->dc_lock);
diff --git a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c
index 681799468487..d897f8a30ede 100644
--- a/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/basics/dce_calcs.c
@@ -1393,7 +1393,7 @@ static void calculate_bandwidth(
if ((bw_mtn(data->dram_speed_change_margin, bw_int_to_fixed(0)) && bw_ltn(data->dram_speed_change_margin, bw_int_to_fixed(9999)))) {
/*determine the minimum dram clock change margin for each set of clock frequencies*/
data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin);
- /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/
+ /*compute the maximum clock frequency required for the dram clock change at each set of clock frequencies*/
data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->active_time[k]))));
if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) {
data->display_pstate_change_enable[k] = 1;
@@ -1407,7 +1407,7 @@ static void calculate_bandwidth(
if ((bw_mtn(data->dram_speed_change_margin, bw_int_to_fixed(0)) && bw_ltn(data->dram_speed_change_margin, bw_int_to_fixed(9999)))) {
/*determine the minimum dram clock change margin for each display pipe*/
data->min_dram_speed_change_margin[i][j] = bw_min2(data->min_dram_speed_change_margin[i][j], data->dram_speed_change_margin);
- /*compute the maximum clock frequuency required for the dram clock change at each set of clock frequencies*/
+ /*compute the maximum clock frequency required for the dram clock change at each set of clock frequencies*/
data->dispclk_required_for_dram_speed_change_pipe[i][j] = bw_max2(bw_div(bw_div(bw_mul(data->src_pixels_for_first_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]))), bw_div(bw_div(bw_mul(data->src_pixels_for_last_output_pixel[k], dceip->display_pipe_throughput_factor), dceip->lb_write_pixels_per_dispclk), (bw_add(bw_sub(bw_sub(bw_sub(bw_sub(data->maximum_latency_hiding_with_cursor[k], vbios->nbp_state_change_latency), data->dmif_burst_time[i][j]), data->dram_speed_change_line_source_transfer_time[k][i][j]), data->mcifwr_burst_time[i][j]), data->active_time[k]))));
if ((bw_ltn(data->dispclk_required_for_dram_speed_change_pipe[i][j], vbios->high_voltage_max_dispclk))) {
data->display_pstate_change_enable[k] = 1;
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
index 3f13a744d07d..01ec451004f7 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c
@@ -62,7 +62,7 @@ static void dal_hw_hpd_destroy(
*ptr = NULL;
}
-static enum gpio_result get_value(
+static enum gpio_result dal_hw_hpd_get_value(
const struct hw_gpio_pin *ptr,
uint32_t *value)
{
@@ -85,7 +85,7 @@ static enum gpio_result get_value(
return dal_hw_gpio_get_value(ptr, value);
}
-static enum gpio_result set_config(
+static enum gpio_result dal_hw_hpd_set_config(
struct hw_gpio_pin *ptr,
const struct gpio_config_data *config_data)
{
@@ -104,9 +104,9 @@ static enum gpio_result set_config(
static const struct hw_gpio_pin_funcs funcs = {
.destroy = dal_hw_hpd_destroy,
.open = dal_hw_gpio_open,
- .get_value = get_value,
+ .get_value = dal_hw_hpd_get_value,
.set_value = dal_hw_gpio_set_value,
- .set_config = set_config,
+ .set_config = dal_hw_hpd_set_config,
.change_mode = dal_hw_gpio_change_mode,
.close = dal_hw_gpio_close,
};
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index 23bec5d25ed6..e8730cc40edb 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -952,8 +952,8 @@ void dce110_edp_backlight_control(
struct dc_context *ctx = link->ctx;
struct bp_transmitter_control cntl = { 0 };
uint8_t pwrseq_instance = 0;
- unsigned int pre_T11_delay = OLED_PRE_T11_DELAY;
- unsigned int post_T7_delay = OLED_POST_T7_DELAY;
+ unsigned int pre_T11_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_PRE_T11_DELAY : 0);
+ unsigned int post_T7_delay = (link->dpcd_sink_ext_caps.bits.oled ? OLED_POST_T7_DELAY : 0);
if (dal_graphics_object_id_get_connector_id(link->link_enc->connector)
!= CONNECTOR_ID_EDP) {
@@ -1069,7 +1069,8 @@ void dce110_edp_backlight_control(
if (!enable) {
/*follow oem panel config's requirement*/
pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms;
- msleep(pre_T11_delay);
+ if (pre_T11_delay)
+ msleep(pre_T11_delay);
}
}
@@ -1220,6 +1221,9 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
struct dc_link *link = stream->link;
struct dce_hwseq *hws = link->dc->hwseq;
+ if (hws && hws->wa_state.skip_blank_stream)
+ return;
+
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
if (!link->skip_implict_edp_power_control)
hws->funcs.edp_backlight_control(link, false);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 858288c3b1ac..c277df12c817 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -76,6 +76,7 @@ void dcn20_log_color_state(struct dc *dc,
{
struct dc_context *dc_ctx = dc->ctx;
struct resource_pool *pool = dc->res_pool;
+ bool is_gamut_remap_available = false;
int i;
DTN_INFO("DPP: DGAM mode SHAPER mode 3DLUT mode 3DLUT bit depth"
@@ -89,15 +90,15 @@ void dcn20_log_color_state(struct dc *dc,
struct dcn_dpp_state s = {0};
dpp->funcs->dpp_read_state(dpp, &s);
- dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
+ if (dpp->funcs->dpp_get_gamut_remap) {
+ dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
+ is_gamut_remap_available = true;
+ }
if (!s.is_enabled)
continue;
- DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s %12s "
- "%010lld %010lld %010lld %010lld "
- "%010lld %010lld %010lld %010lld "
- "%010lld %010lld %010lld %010lld",
+ DTN_INFO("[%2d]: %8s %11s %10s %15s %10s %9s",
dpp->inst,
(s.dgam_lut_mode == 0) ? "Bypass" :
((s.dgam_lut_mode == 1) ? "sRGB" :
@@ -114,10 +115,17 @@ void dcn20_log_color_state(struct dc *dc,
(s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit",
(s.lut3d_size == 0) ? "17x17x17" : "9x9x9",
(s.rgam_lut_mode == 1) ? "RAM A" :
- ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"),
+ ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"));
+
+ if (is_gamut_remap_available) {
+ DTN_INFO(" %12s "
+ "%010lld %010lld %010lld %010lld "
+ "%010lld %010lld %010lld %010lld "
+ "%010lld %010lld %010lld %010lld",
+
(s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :
- ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
- "SW"),
+ ((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
+ "SW"),
s.gamut_remap.temperature_matrix[0].value,
s.gamut_remap.temperature_matrix[1].value,
s.gamut_remap.temperature_matrix[2].value,
@@ -130,6 +138,8 @@ void dcn20_log_color_state(struct dc *dc,
s.gamut_remap.temperature_matrix[9].value,
s.gamut_remap.temperature_matrix[10].value,
s.gamut_remap.temperature_matrix[11].value);
+ }
+
DTN_INFO("\n");
}
DTN_INFO("\n");
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index e89ebfda4873..37a239219dfe 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -74,6 +74,7 @@ void dcn30_log_color_state(struct dc *dc,
{
struct dc_context *dc_ctx = dc->ctx;
struct resource_pool *pool = dc->res_pool;
+ bool is_gamut_remap_available = false;
int i;
DTN_INFO("DPP: DGAM ROM DGAM ROM type DGAM LUT SHAPER mode"
@@ -88,16 +89,16 @@ void dcn30_log_color_state(struct dc *dc,
struct dcn_dpp_state s = {0};
dpp->funcs->dpp_read_state(dpp, &s);
- dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
+
+ if (dpp->funcs->dpp_get_gamut_remap) {
+ dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
+ is_gamut_remap_available = true;
+ }
if (!s.is_enabled)
continue;
- DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s"
- " %12s "
- "%010lld %010lld %010lld %010lld "
- "%010lld %010lld %010lld %010lld "
- "%010lld %010lld %010lld %010lld",
+ DTN_INFO("[%2d]: %7x %13s %8s %11s %10s %15s %10s %9s",
dpp->inst,
s.pre_dgam_mode,
(s.pre_dgam_select == 0) ? "sRGB" :
@@ -121,7 +122,14 @@ void dcn30_log_color_state(struct dc *dc,
(s.lut3d_size == 0) ? "17x17x17" : "9x9x9",
(s.rgam_lut_mode == 0) ? "Bypass" :
((s.rgam_lut_mode == 1) ? "RAM A" :
- "RAM B"),
+ "RAM B"));
+
+ if (is_gamut_remap_available) {
+ DTN_INFO(" %12s "
+ "%010lld %010lld %010lld %010lld "
+ "%010lld %010lld %010lld %010lld "
+ "%010lld %010lld %010lld %010lld",
+
(s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :
((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
"SW"),
@@ -137,6 +145,8 @@ void dcn30_log_color_state(struct dc *dc,
s.gamut_remap.temperature_matrix[9].value,
s.gamut_remap.temperature_matrix[10].value,
s.gamut_remap.temperature_matrix[11].value);
+ }
+
DTN_INFO("\n");
}
DTN_INFO("\n");
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
index f38340aa3f15..5ba3999991b0 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
@@ -526,9 +526,15 @@ static void dcn31_reset_back_end_for_pipe(
link = pipe_ctx->stream->link;
+ if (dc->hwseq)
+ dc->hwseq->wa_state.skip_blank_stream = false;
+
if ((!pipe_ctx->stream->dpms_off || link->link_status.link_active) &&
- (link->connector_signal == SIGNAL_TYPE_EDP))
+ (link->connector_signal == SIGNAL_TYPE_EDP)) {
dc->hwss.blank_stream(pipe_ctx);
+ if (dc->hwseq)
+ dc->hwseq->wa_state.skip_blank_stream = true;
+ }
pipe_ctx->stream_res.tg->funcs->set_dsc_config(
pipe_ctx->stream_res.tg,
@@ -570,7 +576,8 @@ static void dcn31_reset_back_end_for_pipe(
pipe_ctx->stream_res.audio = NULL;
}
}
-
+ if (dc->hwseq)
+ dc->hwseq->wa_state.skip_blank_stream = false;
pipe_ctx->stream = NULL;
DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
index 09bc65c2fa23..1e2d247fbbac 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
@@ -49,6 +49,7 @@ struct hwseq_wa_state {
bool DEGVIDCN10_253_applied;
bool disallow_self_refresh_during_multi_plane_transition_applied;
unsigned int disallow_self_refresh_during_multi_plane_transition_applied_on_frame;
+ bool skip_blank_stream;
};
struct pipe_ctx;
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
index 8f79881ad9f1..a5127c2d47ef 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
@@ -2023,7 +2023,7 @@ static bool retrieve_link_cap(struct dc_link *link)
/* Read DP tunneling information. */
status = dpcd_get_tunneling_device_data(link);
if (status != DC_OK)
- dm_error("%s: Read DP tunneling device data failed.\n", __func__);
+ DC_LOG_DP2("%s: Read DP tunneling device data failed.\n", __func__);
retrieve_cable_id(link);
dpcd_write_cable_id_to_dprx(link);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c
index 81857ce6d68d..e7a90a437fff 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c
@@ -502,7 +502,7 @@ void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, uint32_t *ref
REG_GET(OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, refresh_rate);
}
-static struct timing_generator_funcs dcn20_tg_funcs = {
+static const struct timing_generator_funcs dcn20_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c
index f2415eebdc09..772a8bfb949c 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c
@@ -129,7 +129,7 @@ static void optc201_get_optc_source(struct timing_generator *optc,
*num_of_src_opp = 1;
}
-static struct timing_generator_funcs dcn201_tg_funcs = {
+static const struct timing_generator_funcs dcn201_tg_funcs = {
.validate_timing = optc201_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
index 78b58a449fa4..ee4665aa49e9 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
@@ -357,7 +357,7 @@ void optc3_tg_init(struct timing_generator *optc)
optc1_clear_optc_underflow(optc);
}
-static struct timing_generator_funcs dcn30_tg_funcs = {
+static const struct timing_generator_funcs dcn30_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c
index 65e9089b7f31..38f85bc2681a 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c
@@ -109,7 +109,7 @@ void optc301_setup_manual_trigger(struct timing_generator *optc)
OTG_TRIGA_CLEAR, 1);
}
-static struct timing_generator_funcs dcn30_tg_funcs = {
+static const struct timing_generator_funcs dcn30_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
index ef536f37b4ed..4f1830ba619f 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
@@ -315,7 +315,7 @@ void optc31_read_otg_state(struct timing_generator *optc,
s->otg_double_buffer_control = REG_READ(OTG_DOUBLE_BUFFER_CONTROL);
}
-static struct timing_generator_funcs dcn31_tg_funcs = {
+static const struct timing_generator_funcs dcn31_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
index 0e603bad0d12..4a2caca37255 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
@@ -192,7 +192,7 @@ static void optc314_set_h_timing_div_manual_mode(struct timing_generator *optc,
}
-static struct timing_generator_funcs dcn314_tg_funcs = {
+static const struct timing_generator_funcs dcn314_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
index 2cdd19ba634b..b2b226bcd871 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
@@ -297,7 +297,7 @@ static void optc32_set_drr(
optc32_setup_manual_trigger(optc);
}
-static struct timing_generator_funcs dcn32_tg_funcs = {
+static const struct timing_generator_funcs dcn32_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
index 4cfc6c0fa147..72bff94cb57d 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
@@ -428,7 +428,7 @@ static void optc35_set_long_vtotal(
}
}
-static struct timing_generator_funcs dcn35_tg_funcs = {
+static const struct timing_generator_funcs dcn35_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
index 382ac18e7854..ff79c38287df 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
@@ -459,7 +459,7 @@ bool optc401_wait_update_lock_status(struct timing_generator *tg, bool locked)
return true;
}
-static struct timing_generator_funcs dcn401_tg_funcs = {
+static const struct timing_generator_funcs dcn401_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
index e0e32975ca34..f420c4dafa03 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c
@@ -1938,8 +1938,8 @@ static bool dcn401_resource_construct(
dc->caps.color.dpp.gamma_corr = 1;
dc->caps.color.dpp.dgam_rom_for_yuv = 0;
- dc->caps.color.dpp.hw_3d_lut = 1;
- dc->caps.color.dpp.ogam_ram = 1;
+ dc->caps.color.dpp.hw_3d_lut = 0;
+ dc->caps.color.dpp.ogam_ram = 0;
// no OGAM ROM on DCN2 and later ASICs
dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 57fa05bddb45..b66bd10cdc9b 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -2139,11 +2139,6 @@ union dmub_cmd_fams2_config {
} stream_v1; //v1
};
-struct dmub_fams2_config_v2 {
- struct dmub_cmd_fams2_global_config global;
- struct dmub_fams2_stream_static_state_v1 stream_v1[DMUB_MAX_STREAMS]; //v1
-};
-
/**
* DMUB rb command definition for FAMS2 (merged SubVP, FPO, Legacy)
*/
@@ -2153,22 +2148,6 @@ struct dmub_rb_cmd_fams2 {
};
/**
- * Indirect buffer descriptor
- */
-struct dmub_ib_data {
- union dmub_addr src; // location of indirect buffer in memory
- uint16_t size; // indirect buffer size in bytes
-};
-
-/**
- * DMUB rb command definition for commands passed over indirect buffer
- */
-struct dmub_rb_cmd_ib {
- struct dmub_cmd_header header;
- struct dmub_ib_data ib_data;
-};
-
-/**
* enum dmub_cmd_idle_opt_type - Idle optimization command type.
*/
enum dmub_cmd_idle_opt_type {
@@ -2191,11 +2170,6 @@ enum dmub_cmd_idle_opt_type {
* DCN hardware notify power state.
*/
DMUB_CMD__IDLE_OPT_SET_DC_POWER_STATE = 3,
-
- /**
- * DCN notify to release HW.
- */
- DMUB_CMD__IDLE_OPT_RELEASE_HW = 4,
};
/**
@@ -2957,9 +2931,8 @@ enum dmub_cmd_fams_type {
*/
DMUB_CMD__FAMS_SET_MANUAL_TRIGGER = 3,
DMUB_CMD__FAMS2_CONFIG = 4,
- DMUB_CMD__FAMS2_IB_CONFIG = 5,
- DMUB_CMD__FAMS2_DRR_UPDATE = 6,
- DMUB_CMD__FAMS2_FLIP = 7,
+ DMUB_CMD__FAMS2_DRR_UPDATE = 5,
+ DMUB_CMD__FAMS2_FLIP = 6,
};
/**
@@ -5953,11 +5926,8 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__PSP_ASSR_ENABLE command.
*/
struct dmub_rb_cmd_assr_enable assr_enable;
-
struct dmub_rb_cmd_fams2 fams2_config;
- struct dmub_rb_cmd_ib ib_fams2_config;
-
struct dmub_rb_cmd_fams2_drr_update fams2_drr_update;
struct dmub_rb_cmd_fams2_flip fams2_flip;
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
index 813463ffe15c..cc467031651d 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
@@ -424,7 +424,7 @@ struct integrated_info {
/*
* DFS-bypass flag
*/
-/* Copy of SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS from atombios.h */
+/* Copy of SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS from atombios.h */
enum {
DFS_BYPASS_ENABLE = 0x10
};
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
index 8c137d7c032e..e58e7b93810b 100644
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
@@ -368,6 +368,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_encryption(struct mod_hdcp *hdcp)
struct mod_hdcp_display *display = get_first_active_display(hdcp);
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
+ if (!display)
+ return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
+
mutex_lock(&psp->hdcp_context.mutex);
hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf;
memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h
index c8eccee9b023..11374a2cbab8 100644
--- a/drivers/gpu/drm/amd/include/amd_shared.h
+++ b/drivers/gpu/drm/amd/include/amd_shared.h
@@ -351,9 +351,10 @@ enum DC_DEBUG_MASK {
DC_DISABLE_HDMI_CEC = 0x10000,
/**
- * @DC_DISABLE_SUBVP: If set, disable DCN Sub-Viewport feature in amdgpu driver.
+ * @DC_DISABLE_SUBVP_FAMS: If set, disable DCN Sub-Viewport & Firmware Assisted
+ * Memory Clock Switching (FAMS) feature in amdgpu driver.
*/
- DC_DISABLE_SUBVP = 0x20000,
+ DC_DISABLE_SUBVP_FAMS = 0x20000,
/**
* @DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE: If set, disable support for custom brightness curves
*/
@@ -370,6 +371,11 @@ enum DC_DEBUG_MASK {
* path failure, retry using legacy SW path.
*/
DC_HDCP_LC_ENABLE_SW_FALLBACK = 0x100000,
+
+ /**
+ * @DC_SKIP_DETECTION_LT: If set, skip detection link training
+ */
+ DC_SKIP_DETECTION_LT = 0x200000,
};
enum amd_dpm_forced_level;
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h
index 15e5a65cf492..70ee6be94a9b 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_offset.h
@@ -9776,6 +9776,14 @@
#define regDIG0_DIG_BE_CNTL_BASE_IDX 2
#define regDIG0_DIG_BE_EN_CNTL 0x20bd
#define regDIG0_DIG_BE_EN_CNTL_BASE_IDX 2
+#define regDIG0_HDCP_INT_CONTROL 0x20c0
+#define regDIG0_HDCP_INT_CONTROL_BASE_IDX 2
+#define regDIG0_HDCP_LINK0_STATUS 0x20c1
+#define regDIG0_HDCP_LINK0_STATUS_BASE_IDX 2
+#define regDIG0_HDCP_I2C_CONTROL_0 0x20c2
+#define regDIG0_HDCP_I2C_CONTROL_0_BASE_IDX 2
+#define regDIG0_HDCP_I2C_CONTROL_1 0x20c3
+#define regDIG0_HDCP_I2C_CONTROL_1_BASE_IDX 2
#define regDIG0_TMDS_CNTL 0x20e4
#define regDIG0_TMDS_CNTL_BASE_IDX 2
#define regDIG0_TMDS_CONTROL_CHAR 0x20e5
@@ -10081,6 +10089,12 @@
#define regDIG1_DIG_BE_CNTL_BASE_IDX 2
#define regDIG1_DIG_BE_EN_CNTL 0x21e1
#define regDIG1_DIG_BE_EN_CNTL_BASE_IDX 2
+#define regDIG1_HDCP_INT_CONTROL 0x21e4
+#define regDIG1_HDCP_INT_CONTROL_BASE_IDX 2
+#define regDIG1_HDCP_I2C_CONTROL_0 0x21e6
+#define regDIG1_HDCP_I2C_CONTROL_0_BASE_IDX 2
+#define regDIG1_HDCP_I2C_CONTROL_1 0x21e7
+#define regDIG1_HDCP_I2C_CONTROL_1_BASE_IDX 2
#define regDIG1_TMDS_CNTL 0x2208
#define regDIG1_TMDS_CNTL_BASE_IDX 2
#define regDIG1_TMDS_CONTROL_CHAR 0x2209
@@ -10386,6 +10400,12 @@
#define regDIG2_DIG_BE_CNTL_BASE_IDX 2
#define regDIG2_DIG_BE_EN_CNTL 0x2305
#define regDIG2_DIG_BE_EN_CNTL_BASE_IDX 2
+#define regDIG2_HDCP_INT_CONTROL 0x2308
+#define regDIG2_HDCP_INT_CONTROL_BASE_IDX 2
+#define regDIG2_HDCP_I2C_CONTROL_0 0x230a
+#define regDIG2_HDCP_I2C_CONTROL_0_BASE_IDX 2
+#define regDIG2_HDCP_I2C_CONTROL_1 0x230b
+#define regDIG2_HDCP_I2C_CONTROL_1_BASE_IDX 2
#define regDIG2_TMDS_CNTL 0x232c
#define regDIG2_TMDS_CNTL_BASE_IDX 2
#define regDIG2_TMDS_CONTROL_CHAR 0x232d
@@ -10691,6 +10711,12 @@
#define regDIG3_DIG_BE_CNTL_BASE_IDX 2
#define regDIG3_DIG_BE_EN_CNTL 0x2429
#define regDIG3_DIG_BE_EN_CNTL_BASE_IDX 2
+#define regDIG3_HDCP_INT_CONTROL 0x242c
+#define regDIG3_HDCP_INT_CONTROL_BASE_IDX 2
+#define regDIG3_HDCP_I2C_CONTROL_0 0x242e
+#define regDIG3_HDCP_I2C_CONTROL_0_BASE_IDX 2
+#define regDIG3_HDCP_I2C_CONTROL_1 0x242f
+#define regDIG3_HDCP_I2C_CONTROL_1_BASE_IDX 2
#define regDIG3_TMDS_CNTL 0x2450
#define regDIG3_TMDS_CNTL_BASE_IDX 2
#define regDIG3_TMDS_CONTROL_CHAR 0x2451
diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h
index 5d9d5fea6e06..e3d841b2e9af 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h
@@ -2847,6 +2847,14 @@
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x1
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0x2
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0x3
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0x4
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x5
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0x6
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0x7
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0x8
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0x9
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0xa
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_DONE_INTERRUPT_DEST__SHIFT 0xb
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_SUCCESS_INTERRUPT_DEST__SHIFT 0xc
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_FAIL_INTERRUPT_DEST__SHIFT 0xd
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_I2C_XFER_REQ_INTERRUPT_DEST__SHIFT 0xe
@@ -2871,6 +2879,14 @@
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000002L
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000004L
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP0_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000008L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00000010L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000020L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000040L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP1_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000080L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00000100L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00000200L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00000400L
+#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP2_I2C_XFER_DONE_INTERRUPT_DEST_MASK 0x00000800L
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_SUCCESS_INTERRUPT_DEST_MASK 0x00001000L
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_AUTH_FAIL_INTERRUPT_DEST_MASK 0x00002000L
#define HDCP_INTERRUPT_DEST__DOUT_IHC_HDCP3_I2C_XFER_REQ_INTERRUPT_DEST_MASK 0x00004000L
diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h
index c4aaa86a95e2..72a118b2af69 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_offset.h
@@ -1067,7 +1067,13 @@
#define regVCN_FEATURES_BASE_IDX 1
#define regUVD_GPUIOV_STATUS 0x0055
#define regUVD_GPUIOV_STATUS_BASE_IDX 1
+#define regUVD_RAS_VCPU_VCODEC_STATUS 0x0057
+#define regUVD_RAS_VCPU_VCODEC_STATUS_BASE_IDX 1
#define regUVD_SCRATCH15 0x005c
+#define regUVD_RAS_JPEG0_STATUS 0x0059
+#define regUVD_RAS_JPEG0_STATUS_BASE_IDX 1
+#define regUVD_RAS_JPEG1_STATUS 0x005a
+#define regUVD_RAS_JPEG1_STATUS_BASE_IDX 1
#define regUVD_SCRATCH15_BASE_IDX 1
#define regUVD_VERSION 0x005d
#define regUVD_VERSION_BASE_IDX 1
diff --git a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h
index bd7242e4e9c6..c78b09d6fbae 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/vcn/vcn_5_0_0_sh_mask.h
@@ -5714,6 +5714,22 @@
//UVD_GPUIOV_STATUS
#define UVD_GPUIOV_STATUS__UVD_GPUIOV_STATUS_VF_ENABLE__SHIFT 0x0
#define UVD_GPUIOV_STATUS__UVD_GPUIOV_STATUS_VF_ENABLE_MASK 0x00000001L
+//UVD_RAS_VCPU_VCODEC_STATUS
+#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_VF__SHIFT 0x0
+#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_PF__SHIFT 0x1f
+#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_VF_MASK 0x7FFFFFFFL
+#define UVD_RAS_VCPU_VCODEC_STATUS__POISONED_PF_MASK 0x80000000L
+
+//UVD_RAS_JPEG0_STATUS
+#define UVD_RAS_JPEG0_STATUS__POISONED_VF__SHIFT 0x0
+#define UVD_RAS_JPEG0_STATUS__POISONED_PF__SHIFT 0x1f
+#define UVD_RAS_JPEG0_STATUS__POISONED_VF_MASK 0x7FFFFFFFL
+#define UVD_RAS_JPEG0_STATUS__POISONED_PF_MASK 0x80000000L
+//UVD_RAS_JPEG1_STATUS
+#define UVD_RAS_JPEG1_STATUS__POISONED_VF__SHIFT 0x0
+#define UVD_RAS_JPEG1_STATUS__POISONED_PF__SHIFT 0x1f
+#define UVD_RAS_JPEG1_STATUS__POISONED_VF_MASK 0x7FFFFFFFL
+#define UVD_RAS_JPEG1_STATUS__POISONED_PF_MASK 0x80000000L
//UVD_SCRATCH15
#define UVD_SCRATCH15__SCRATCH15_DATA__SHIFT 0x0
#define UVD_SCRATCH15__SCRATCH15_DATA_MASK 0xFFFFFFFFL
diff --git a/drivers/gpu/drm/amd/include/atombios.h b/drivers/gpu/drm/amd/include/atombios.h
index 52bac19fb404..b344acefc606 100644
--- a/drivers/gpu/drm/amd/include/atombios.h
+++ b/drivers/gpu/drm/amd/include/atombios.h
@@ -6017,7 +6017,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
#define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01
#define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02
#define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08
-#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10
+#define SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS 0x10
//ulGPUCapInfo[16]=1 indicate SMC firmware is able to support GNB fast resume function, so that driver can call SMC to program most of GNB register during resuming, from ML
#define SYS_INFO_GPUCAPS__GNB_FAST_RESUME_CAPABLE 0x00010000
@@ -6460,7 +6460,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_9
// ulGPUCapInfo
#define SYS_INFO_V1_9_GPUCAPSINFO_DISABLE_AUX_MODE_DETECT 0x08
-#define SYS_INFO_V1_9_GPUCAPSINFO_ENABEL_DFS_BYPASS 0x10
+#define SYS_INFO_V1_9_GPUCAPSINFO_ENABLE_DFS_BYPASS 0x10
//ulGPUCapInfo[16]=1 indicate SMC firmware is able to support GNB fast resume function, so that driver can call SMC to program most of GNB register during resuming, from ML
#define SYS_INFO_V1_9_GPUCAPSINFO_GNB_FAST_RESUME_CAPABLE 0x00010000
//ulGPUCapInfo[18]=1 indicate the IOMMU is not available
diff --git a/drivers/gpu/drm/amd/include/atomfirmware.h b/drivers/gpu/drm/amd/include/atomfirmware.h
index 2d1135bdc4b9..5c86423c2e92 100644
--- a/drivers/gpu/drm/amd/include/atomfirmware.h
+++ b/drivers/gpu/drm/amd/include/atomfirmware.h
@@ -1714,7 +1714,7 @@ enum atom_system_vbiosmisc_def{
// gpucapinfo
enum atom_system_gpucapinf_def{
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS = 0x10,
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS = 0x10,
};
//dpphy_override
diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
index 3a4670bc4449..b98b7ae551b5 100644
--- a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
+++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_11_0_0.h
@@ -48,6 +48,7 @@
#define GFX_11_0_0__SRCID__SDMA_SRAM_ECC 64 // 0x40 SRAM ECC Error
#define GFX_11_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout)
#define GFX_11_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout
+#define GFX_11_0_0__SRCID__SDMA_FENCE 67 // 0x43 User fence
#define GFX_11_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning)
diff --git a/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h
new file mode 100644
index 000000000000..467897ec2e65
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/ivsrcid/gfx/irqsrcs_gfx_12_0_0.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2024 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __IRQSRCS_GFX_12_0_0_H__
+#define __IRQSRCS_GFX_12_0_0_H__
+
+#define GFX_12_0_0__SRCID__UTCL2_FAULT 0 // UTCL2 has encountered a fault or retry scenario
+#define GFX_12_0_0__SRCID__UTCL2_DATA_POISONING 1 // UTCL2 for data poisoning
+#define GFX_12_0_0__SRCID__MEM_ACCES_MON 10 // 0x0A EA memory access monitor interrupt
+#define GFX_12_0_0__SRCID__SDMA_ATOMIC_RTN_DONE 48 // 0x30 SDMA atomic*_rtn ops complete
+#define GFX_12_0_0__SRCID__SDMA_TRAP 49 // 0x31 Trap
+#define GFX_12_0_0__SRCID__SDMA_SRBMWRITE 50 // 0x32 SRBM write Protection
+#define GFX_12_0_0__SRCID__SDMA_CTXEMPTY 51 // 0x33 Context Empty
+#define GFX_12_0_0__SRCID__SDMA_PREEMPT 52 // 0x34 SDMA New Run List
+#define GFX_12_0_0__SRCID__SDMA_IB_PREEMPT 53 // 0x35 sdma mid - command buffer preempt interrupt
+#define GFX_12_0_0__SRCID__SDMA_DOORBELL_INVALID 54 // 0x36 Doorbell BE invalid
+#define GFX_12_0_0__SRCID__SDMA_QUEUE_HANG 55 // 0x37 Queue hang or Command timeout
+#define GFX_12_0_0__SRCID__SDMA_ATOMIC_TIMEOUT 56 // 0x38 SDMA atomic CMPSWAP loop timeout
+#define GFX_12_0_0__SRCID__SDMA_POLL_TIMEOUT 57 // 0x39 SRBM read poll timeout
+#define GFX_12_0_0__SRCID__SDMA_PAGE_TIMEOUT 58 // 0x3A Page retry timeout after UTCL2 return nack = 1
+#define GFX_12_0_0__SRCID__SDMA_PAGE_NULL 59 // 0x3B Page Null from UTCL2 when nack = 2
+#define GFX_12_0_0__SRCID__SDMA_PAGE_FAULT 60 // 0x3C Page Fault Error from UTCL2 when nack = 3
+#define GFX_12_0_0__SRCID__SDMA_VM_HOLE 61 // 0x3D MC or SEM address in VM hole
+#define GFX_12_0_0__SRCID__SDMA_ECC 62 // 0x3E ECC Error
+#define GFX_12_0_0__SRCID__SDMA_FROZEN 63 // 0x3F SDMA Frozen
+#define GFX_12_0_0__SRCID__SDMA_SRAM_ECC 64 // 0x40 SRAM ECC Error
+#define GFX_12_0_0__SRCID__SDMA_SEM_INCOMPLETE_TIMEOUT 65 // 0x41 GPF(Sem incomplete timeout)
+#define GFX_12_0_0__SRCID__SDMA_SEM_WAIT_FAIL_TIMEOUT 66 // 0x42 Semaphore wait fail timeout
+#define GFX_12_0_0__SRCID__SDMA_FENCE 70 // 0x46 User fence
+#define GFX_12_0_0__SRCID__RLC_GC_FED_INTERRUPT 128 // 0x80 FED Interrupt (for data poisoning)
+#define GFX_12_0_0__SRCID__CP_GENERIC_INT 177 // 0xB1 CP_GENERIC int
+#define GFX_12_0_0__SRCID__CP_PM4_PKT_RSVD_BIT_ERROR 180 // 0xB4 PM4 Pkt Rsvd Bits Error
+#define GFX_12_0_0__SRCID__CP_EOP_INTERRUPT 181 // 0xB5 End-of-Pipe Interrupt
+#define GFX_12_0_0__SRCID__CP_BAD_OPCODE_ERROR 183 // 0xB7 Bad Opcode Error
+#define GFX_12_0_0__SRCID__CP_PRIV_REG_FAULT 184 // 0xB8 Privileged Register Fault
+#define GFX_12_0_0__SRCID__CP_PRIV_INSTR_FAULT 185 // 0xB9 Privileged Instr Fault
+#define GFX_12_0_0__SRCID__CP_WAIT_MEM_SEM_FAULT 186 // 0xBA Wait Memory Semaphore Fault (Sync Object Fault)
+#define GFX_12_0_0__SRCID__CP_CTX_EMPTY_INTERRUPT 187 // 0xBB Context Empty Interrupt
+#define GFX_12_0_0__SRCID__CP_CTX_BUSY_INTERRUPT 188 // 0xBC Context Busy Interrupt
+#define GFX_12_0_0__SRCID__CP_ME_WAIT_REG_MEM_POLL_TIMEOUT 192 // 0xC0 CP.ME Wait_Reg_Mem Poll Timeout
+#define GFX_12_0_0__SRCID__CP_SIG_INCOMPLETE 193 // 0xC1 "Surface Probe Fault Signal Incomplete"
+#define GFX_12_0_0__SRCID__CP_PREEMPT_ACK 194 // 0xC2 Preemption Ack-wledge
+#define GFX_12_0_0__SRCID__CP_GPF 195 // 0xC3 General Protection Fault (GPF)
+#define GFX_12_0_0__SRCID__CP_GDS_ALLOC_ERROR 196 // 0xC4 GDS Alloc Error
+#define GFX_12_0_0__SRCID__CP_ECC_ERROR 197 // 0xC5 ECC Error
+#define GFX_12_0_0__SRCID__CP_COMPUTE_QUERY_STATUS 199 // 0xC7 Compute query status
+#define GFX_12_0_0__SRCID__CP_VM_DOORBELL 200 // 0xC8 Unattached VM Doorbell Received
+#define GFX_12_0_0__SRCID__CP_FUE_ERROR 201 // 0xC9 ECC FUE Error
+#define GFX_12_0_0__SRCID__RLC_STRM_PERF_MONITOR_INTERRUPT 202 // 0xCA Streaming Perf Monitor Interrupt
+#define GFX_12_0_0__SRCID__GRBM_RD_TIMEOUT_ERROR 232 // 0xE8 CRead timeout error
+#define GFX_12_0_0__SRCID__GRBM_REG_GUI_IDLE 233 // 0xE9 Register GUI Idle
+#define GFX_12_0_0__SRCID__SQ_INTERRUPT_ID 239 // 0xEF SQ Interrupt (ttrace wrap, errors)
+
+#endif
diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
index 0f7542d7074b..f4d914dc731f 100644
--- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h
@@ -494,6 +494,7 @@ struct amd_pm_funcs {
int (*set_df_cstate)(void *handle, enum pp_df_cstate state);
int (*set_xgmi_pstate)(void *handle, uint32_t pstate);
ssize_t (*get_gpu_metrics)(void *handle, void **table);
+ ssize_t (*get_xcp_metrics)(void *handle, int xcp_id, void *table);
ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size);
int (*set_watermarks_for_clock_ranges)(void *handle,
struct pp_smu_wm_range_sets *ranges);
@@ -1592,4 +1593,27 @@ struct amdgpu_pm_metrics {
uint8_t data[];
};
+struct amdgpu_partition_metrics_v1_0 {
+ struct metrics_table_header common_header;
+ /* Current clocks (Mhz) */
+ uint16_t current_gfxclk[MAX_XCC];
+ uint16_t current_socclk[MAX_CLKS];
+ uint16_t current_vclk0[MAX_CLKS];
+ uint16_t current_dclk0[MAX_CLKS];
+ uint16_t current_uclk;
+ uint16_t padding;
+
+ /* Utilization Instantaneous (%) */
+ uint32_t gfx_busy_inst[MAX_XCC];
+ uint16_t jpeg_busy[NUM_JPEG_ENG_V1];
+ uint16_t vcn_busy[NUM_VCN];
+ /* Utilization Accumulated (%) */
+ uint64_t gfx_busy_acc[MAX_XCC];
+ /* Total App Clock Counter Accumulated */
+ uint64_t gfx_below_host_limit_ppt_acc[MAX_XCC];
+ uint64_t gfx_below_host_limit_thm_acc[MAX_XCC];
+ uint64_t gfx_low_utilization_acc[MAX_XCC];
+ uint64_t gfx_below_host_limit_total_acc[MAX_XCC];
+};
+
#endif
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index 2148c8db5a59..5c1cbdc122d2 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -1697,6 +1697,28 @@ int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev)
}
}
+int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev)
+{
+ if (is_support_sw_smu(adev)) {
+ struct smu_context *smu = adev->powerplay.pp_handle;
+
+ return smu->od_enabled;
+ } else {
+ struct pp_hwmgr *hwmgr;
+
+ /*
+ * dpm on some legacy asics don't carry od_enabled member
+ * as its pp_handle is casted directly from adev.
+ */
+ if (amdgpu_dpm_is_legacy_dpm(adev))
+ return false;
+
+ hwmgr = (struct pp_hwmgr *)adev->powerplay.pp_handle;
+
+ return hwmgr->od_enabled;
+ }
+}
+
int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const char *buf,
size_t size)
@@ -2019,3 +2041,35 @@ int amdgpu_dpm_get_dpm_clock_table(struct amdgpu_device *adev,
return ret;
}
+
+/**
+ * amdgpu_dpm_get_xcp_metrics - Retrieve metrics for a specific compute
+ * partition
+ * @adev: Pointer to the device.
+ * @xcp_id: Identifier of the XCP for which metrics are to be retrieved.
+ * @table: Pointer to a buffer where the metrics will be stored. If NULL, the
+ * function returns the size of the metrics structure.
+ *
+ * This function retrieves metrics for a specific XCP, including details such as
+ * VCN/JPEG activity, clock frequencies, and other performance metrics. If the
+ * table parameter is NULL, the function returns the size of the metrics
+ * structure without populating it.
+ *
+ * Return: Size of the metrics structure on success, or a negative error code on failure.
+ */
+ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
+ void *table)
+{
+ const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
+
+ if (!pp_funcs->get_xcp_metrics)
+ return 0;
+
+ mutex_lock(&adev->pm.mutex);
+ ret = pp_funcs->get_xcp_metrics(adev->powerplay.pp_handle, xcp_id,
+ table);
+ mutex_unlock(&adev->pm.mutex);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index 2c3c97587dd5..768317ee1486 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -524,6 +524,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
long *input, uint32_t size);
int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
+ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
+ void *table);
/**
* @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The
@@ -561,6 +563,7 @@ int amdgpu_dpm_get_smu_prv_buf_details(struct amdgpu_device *adev,
void **addr,
size_t *size);
int amdgpu_dpm_is_overdrive_supported(struct amdgpu_device *adev);
+int amdgpu_dpm_is_overdrive_enabled(struct amdgpu_device *adev);
int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const char *buf,
size_t size);
diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
index 59fae668dc3f..34e71727b27d 100644
--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
+++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c
@@ -2594,7 +2594,7 @@ static int kv_parse_sys_info_table(struct amdgpu_device *adev)
le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]);
}
if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS)
pi->caps_enable_dfs_bypass = true;
sumo_construct_sclk_voltage_mapping_table(adev,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
index 9d3b33446adc..9b20076e26c0 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu8_hwmgr.c
@@ -394,7 +394,7 @@ static int smu8_get_system_info_data(struct pp_hwmgr *hwmgr)
}
if (le32_to_cpu(info->ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS) {
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_EnableDFSBypass);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index f24a1d8c77db..d79a1d94661a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -3758,6 +3758,19 @@ int smu_set_pm_policy(struct smu_context *smu, enum pp_pm_policy p_type,
return ret;
}
+static ssize_t smu_sys_get_xcp_metrics(void *handle, int xcp_id, void *table)
+{
+ struct smu_context *smu = handle;
+
+ if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled)
+ return -EOPNOTSUPP;
+
+ if (!smu->adev->xcp_mgr || !smu->ppt_funcs->get_xcp_metrics)
+ return -EOPNOTSUPP;
+
+ return smu->ppt_funcs->get_xcp_metrics(smu, xcp_id, table);
+}
+
static const struct amd_pm_funcs swsmu_pm_funcs = {
/* export for sysfs */
.set_fan_control_mode = smu_set_fan_control_mode,
@@ -3816,6 +3829,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = {
.get_uclk_dpm_states = smu_get_uclk_dpm_states,
.get_dpm_clock_table = smu_get_dpm_clock_table,
.get_smu_prv_buf_details = smu_get_prv_buffer_details,
+ .get_xcp_metrics = smu_sys_get_xcp_metrics,
};
int smu_wait_for_event(struct smu_context *smu, enum smu_event_type event,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
index d47e32ae4671..9aacc7bc1c69 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h
@@ -1466,6 +1466,12 @@ struct pptable_funcs {
*/
int (*set_wbrf_exclusion_ranges)(struct smu_context *smu,
struct freq_band_range *exclusion_ranges);
+ /**
+ * @get_xcp_metrics: Get a copy of the partition metrics table from SMU.
+ * Return: Size of table
+ */
+ ssize_t (*get_xcp_metrics)(struct smu_context *smu, int xcp_id,
+ void *table);
};
typedef enum {
diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
index 3d9e5e967c94..01790a927930 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h
@@ -127,7 +127,7 @@ typedef enum {
VOLTAGE_GUARDBAND_COUNT
} GFX_GUARDBAND_e;
-#define SMU_METRICS_TABLE_VERSION 0x10
+#define SMU_METRICS_TABLE_VERSION 0x11
// Unified metrics table for smu_v13_0_6
typedef struct __attribute__((packed, aligned(4))) {
@@ -463,6 +463,8 @@ typedef struct __attribute__((packed, aligned(4))) {
typedef struct {
// Telemetry
uint32_t InputTelemetryVoltageInmV;
+ // General info
+ uint32_t pldmVersion[2];
} StaticMetricsTable_t;
#pragma pack(pop)
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
index 533d58e57d05..e0d356f93ab0 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c
@@ -322,7 +322,63 @@ int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
return ret;
}
-ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table)
+ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu, struct amdgpu_xcp *xcp, void *table, void *smu_metrics)
+{
+ const u8 num_jpeg_rings = NUM_JPEG_RINGS_FW;
+ struct amdgpu_partition_metrics_v1_0 *xcp_metrics;
+ struct amdgpu_device *adev = smu->adev;
+ MetricsTable_t *metrics;
+ int inst, j, k, idx;
+ u32 inst_mask;
+
+ metrics = (MetricsTable_t *)smu_metrics;
+ xcp_metrics = (struct amdgpu_partition_metrics_v1_0 *) table;
+ smu_cmn_init_partition_metrics(xcp_metrics, 1, 0);
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ /* Both JPEG and VCN has same instance */
+ inst = GET_INST(VCN, k);
+ for (j = 0; j < num_jpeg_rings; ++j) {
+ xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(metrics->
+ JpegBusy[(inst * num_jpeg_rings) + j]);
+ }
+ xcp_metrics->vcn_busy[idx] =
+ SMUQ10_ROUND(metrics->VcnBusy[inst]);
+ xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND(
+ metrics->VclkFrequency[inst]);
+ xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND(
+ metrics->DclkFrequency[inst]);
+ xcp_metrics->current_socclk[idx] = SMUQ10_ROUND(
+ metrics->SocclkFrequency[inst]);
+
+ idx++;
+ }
+
+ xcp_metrics->current_uclk =
+ SMUQ10_ROUND(metrics->UclkFrequency);
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ inst = GET_INST(GC, k);
+ xcp_metrics->current_gfxclk[idx] = SMUQ10_ROUND(metrics->GfxclkFrequency[inst]);
+ xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(metrics->GfxBusy[inst]);
+ xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(metrics->GfxBusyAcc[inst]);
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(HST_LIMIT_METRICS))) {
+ xcp_metrics->gfx_below_host_limit_ppt_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitPptAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_thm_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitThmAcc[inst]);
+ xcp_metrics->gfx_low_utilization_acc[idx] = SMUQ10_ROUND(metrics->GfxclkLowUtilizationAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_total_acc[idx] = SMUQ10_ROUND(metrics->GfxclkBelowHostLimitTotalAcc[inst]);
+ }
+ idx++;
+ }
+
+ return sizeof(*xcp_metrics);
+}
+
+ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, void *smu_metrics)
{
struct smu_table_context *smu_table = &smu->smu_table;
struct gpu_metrics_v1_8 *gpu_metrics =
@@ -334,8 +390,7 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table)
struct amdgpu_xcp *xcp;
u32 inst_mask;
- metrics = kzalloc(sizeof(MetricsTable_t), GFP_KERNEL);
- memcpy(metrics, smu_table->metrics_table, sizeof(MetricsTable_t));
+ metrics = (MetricsTable_t *)smu_metrics;
smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 8);
@@ -416,13 +471,16 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table)
gpu_metrics->mem_activity_acc = SMUQ10_ROUND(metrics->DramBandwidthUtilizationAcc);
for (i = 0; i < NUM_XGMI_LINKS; i++) {
- gpu_metrics->xgmi_read_data_acc[i] =
+ j = amdgpu_xgmi_get_ext_link(adev, i);
+ if (j < 0 || j >= NUM_XGMI_LINKS)
+ continue;
+ gpu_metrics->xgmi_read_data_acc[j] =
SMUQ10_ROUND(metrics->XgmiReadDataSizeAcc[i]);
- gpu_metrics->xgmi_write_data_acc[i] =
+ gpu_metrics->xgmi_write_data_acc[j] =
SMUQ10_ROUND(metrics->XgmiWriteDataSizeAcc[i]);
ret = amdgpu_get_xgmi_link_status(adev, i);
if (ret >= 0)
- gpu_metrics->xgmi_link_status[i] = ret;
+ gpu_metrics->xgmi_link_status[j] = ret;
}
gpu_metrics->num_partition = adev->xcp_mgr->num_xcps;
@@ -474,7 +532,6 @@ ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table)
gpu_metrics->firmware_timestamp = metrics->Timestamp;
*table = (void *)gpu_metrics;
- kfree(metrics);
return sizeof(*gpu_metrics);
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
index 7d4ff09be7e8..f00ef7f3f355 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
@@ -312,6 +312,11 @@ static void smu_v13_0_14_init_caps(struct smu_context *smu)
smu_v13_0_6_cap_set(smu, SMU_CAP(PER_INST_METRICS));
if (fw_ver >= 0x5551200)
smu_v13_0_6_cap_set(smu, SMU_CAP(SDMA_RESET));
+ if (fw_ver >= 0x5551600) {
+ smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE));
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
+ }
}
static void smu_v13_0_12_init_caps(struct smu_context *smu)
@@ -392,10 +397,14 @@ static void smu_v13_0_6_init_caps(struct smu_context *smu)
if ((pgm == 7 && fw_ver >= 0x7550E00) ||
(pgm == 0 && fw_ver >= 0x00557E00))
smu_v13_0_6_cap_set(smu, SMU_CAP(HST_LIMIT_METRICS));
- if (fw_ver >= 0x00557F01) {
+ if ((pgm == 0 && fw_ver >= 0x00557F01) ||
+ (pgm == 7 && fw_ver >= 0x7551000)) {
smu_v13_0_6_cap_set(smu, SMU_CAP(STATIC_METRICS));
smu_v13_0_6_cap_set(smu, SMU_CAP(BOARD_VOLTAGE));
}
+ if ((pgm == 0 && fw_ver >= 0x00558000) ||
+ (pgm == 7 && fw_ver >= 0x7551000))
+ smu_v13_0_6_cap_set(smu, SMU_CAP(PLDM_VERSION));
}
if (((pgm == 7) && (fw_ver >= 0x7550700)) ||
((pgm == 0) && (fw_ver >= 0x00557900)) ||
@@ -752,6 +761,11 @@ static void smu_v13_0_6_fill_static_metrics_table(struct smu_context *smu,
}
dpm_context->board_volt = static_metrics->InputTelemetryVoltageInmV;
+
+ if (smu_v13_0_6_cap_supported(smu, SMU_CAP(PLDM_VERSION)) &&
+ static_metrics->pldmVersion[0] != 0xFFFFFFFF)
+ smu->adev->firmware.pldm_version =
+ static_metrics->pldmVersion[0];
}
int smu_v13_0_6_get_static_metrics_table(struct smu_context *smu)
@@ -2529,6 +2543,126 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu)
return pcie_gen_to_speed(speed_level + 1);
}
+static ssize_t smu_v13_0_6_get_xcp_metrics(struct smu_context *smu, int xcp_id,
+ void *table)
+{
+ const u8 num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3;
+ int version = smu_v13_0_6_get_metrics_version(smu);
+ struct amdgpu_partition_metrics_v1_0 *xcp_metrics;
+ struct amdgpu_device *adev = smu->adev;
+ int ret, inst, i, j, k, idx;
+ MetricsTableV0_t *metrics_v0;
+ MetricsTableV1_t *metrics_v1;
+ MetricsTableV2_t *metrics_v2;
+ struct amdgpu_xcp *xcp;
+ u32 inst_mask;
+ bool per_inst;
+
+ if (!table)
+ return sizeof(*xcp_metrics);
+
+ for_each_xcp(adev->xcp_mgr, xcp, i) {
+ if (xcp->id == xcp_id)
+ break;
+ }
+ if (i == adev->xcp_mgr->num_xcps)
+ return -EINVAL;
+
+ xcp_metrics = (struct amdgpu_partition_metrics_v1_0 *)table;
+ smu_cmn_init_partition_metrics(xcp_metrics, 1, 0);
+
+ metrics_v0 = kzalloc(METRICS_TABLE_SIZE, GFP_KERNEL);
+ if (!metrics_v0)
+ return -ENOMEM;
+
+ ret = smu_v13_0_6_get_metrics_table(smu, metrics_v0, false);
+ if (ret) {
+ kfree(metrics_v0);
+ return ret;
+ }
+
+ if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) ==
+ IP_VERSION(13, 0, 12) &&
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) {
+ ret = smu_v13_0_12_get_xcp_metrics(smu, xcp, table, metrics_v0);
+ goto out;
+ }
+
+ metrics_v1 = (MetricsTableV1_t *)metrics_v0;
+ metrics_v2 = (MetricsTableV2_t *)metrics_v0;
+
+ per_inst = smu_v13_0_6_cap_supported(smu, SMU_CAP(PER_INST_METRICS));
+
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ /* Both JPEG and VCN has same instances */
+ inst = GET_INST(VCN, k);
+
+ for (j = 0; j < num_jpeg_rings; ++j) {
+ xcp_metrics->jpeg_busy[(idx * num_jpeg_rings) + j] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(
+ JpegBusy,
+ version)[(inst * num_jpeg_rings) + j]);
+ }
+ xcp_metrics->vcn_busy[idx] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, version)[inst]);
+
+ xcp_metrics->current_vclk0[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(VclkFrequency, version)[inst]);
+ xcp_metrics->current_dclk0[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(DclkFrequency, version)[inst]);
+ xcp_metrics->current_socclk[idx] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(SocclkFrequency, version)[inst]);
+
+ idx++;
+ }
+
+ xcp_metrics->current_uclk =
+ SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, version));
+
+ if (per_inst) {
+ amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask);
+ idx = 0;
+ for_each_inst(k, inst_mask) {
+ inst = GET_INST(GC, k);
+ xcp_metrics->current_gfxclk[idx] =
+ SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency,
+ version)[inst]);
+
+ xcp_metrics->gfx_busy_inst[idx] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusy, version)[inst]);
+ xcp_metrics->gfx_busy_acc[idx] = SMUQ10_ROUND(
+ GET_GPU_METRIC_FIELD(GfxBusyAcc,
+ version)[inst]);
+ if (smu_v13_0_6_cap_supported(
+ smu, SMU_CAP(HST_LIMIT_METRICS))) {
+ xcp_metrics->gfx_below_host_limit_ppt_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitPptAcc
+ [inst]);
+ xcp_metrics->gfx_below_host_limit_thm_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitThmAcc
+ [inst]);
+ xcp_metrics->gfx_low_utilization_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0
+ ->GfxclkLowUtilizationAcc[inst]);
+ xcp_metrics->gfx_below_host_limit_total_acc
+ [idx] = SMUQ10_ROUND(
+ metrics_v0->GfxclkBelowHostLimitTotalAcc
+ [inst]);
+ }
+ idx++;
+ }
+ }
+out:
+ kfree(metrics_v0);
+
+ return sizeof(*xcp_metrics);
+}
+
static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table)
{
struct smu_table_context *smu_table = &smu->smu_table;
@@ -2542,6 +2676,7 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
MetricsTableV2_t *metrics_v2;
struct amdgpu_xcp *xcp;
u16 link_width_level;
+ ssize_t num_bytes;
u8 num_jpeg_rings;
u32 inst_mask;
bool per_inst;
@@ -2554,8 +2689,11 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
}
if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 12) &&
- smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS)))
- return smu_v13_0_12_get_gpu_metrics(smu, table);
+ smu_v13_0_6_cap_supported(smu, SMU_CAP(STATIC_METRICS))) {
+ num_bytes = smu_v13_0_12_get_gpu_metrics(smu, table, metrics_v0);
+ kfree(metrics_v0);
+ return num_bytes;
+ }
metrics_v1 = (MetricsTableV1_t *)metrics_v0;
metrics_v2 = (MetricsTableV2_t *)metrics_v0;
@@ -2670,13 +2808,16 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, version));
for (i = 0; i < NUM_XGMI_LINKS; i++) {
- gpu_metrics->xgmi_read_data_acc[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]);
- gpu_metrics->xgmi_write_data_acc[i] =
- SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]);
+ j = amdgpu_xgmi_get_ext_link(adev, i);
+ if (j < 0 || j >= NUM_XGMI_LINKS)
+ continue;
+ gpu_metrics->xgmi_read_data_acc[j] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(XgmiReadDataSizeAcc, version)[i]);
+ gpu_metrics->xgmi_write_data_acc[j] = SMUQ10_ROUND(
+ GET_METRIC_FIELD(XgmiWriteDataSizeAcc, version)[i]);
ret = amdgpu_get_xgmi_link_status(adev, i);
if (ret >= 0)
- gpu_metrics->xgmi_link_status[i] = ret;
+ gpu_metrics->xgmi_link_status[j] = ret;
}
gpu_metrics->num_partition = adev->xcp_mgr->num_xcps;
@@ -3673,6 +3814,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = {
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
.get_gpu_metrics = smu_v13_0_6_get_gpu_metrics,
.get_pm_metrics = smu_v13_0_6_get_pm_metrics,
+ .get_xcp_metrics = smu_v13_0_6_get_xcp_metrics,
.get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range,
.mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported,
.link_reset_is_support = smu_v13_0_6_is_link_reset_supported,
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
index d151bcd0cca7..d38d6d76b1e7 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.h
@@ -67,6 +67,7 @@ enum smu_v13_0_6_caps {
SMU_CAP(STATIC_METRICS),
SMU_CAP(HST_LIMIT_METRICS),
SMU_CAP(BOARD_VOLTAGE),
+ SMU_CAP(PLDM_VERSION),
SMU_CAP(ALL),
};
@@ -79,7 +80,10 @@ int smu_v13_0_12_get_max_metrics_size(void);
int smu_v13_0_12_setup_driver_pptable(struct smu_context *smu);
int smu_v13_0_12_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member, uint32_t *value);
-ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table);
+ssize_t smu_v13_0_12_get_gpu_metrics(struct smu_context *smu, void **table, void *smu_metrics);
+ssize_t smu_v13_0_12_get_xcp_metrics(struct smu_context *smu,
+ struct amdgpu_xcp *xcp, void *table,
+ void *smu_metrics);
extern const struct cmn2asic_mapping smu_v13_0_12_feature_mask_map[];
extern const struct cmn2asic_msg_mapping smu_v13_0_12_message_map[];
#endif
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
index 80eb1a03b3ca..7eaf58fd7f9a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
@@ -1051,73 +1051,6 @@ int smu_cmn_get_combo_pptable(struct smu_context *smu)
false);
}
-void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev)
-{
- struct metrics_table_header *header = (struct metrics_table_header *)table;
- uint16_t structure_size;
-
-#define METRICS_VERSION(a, b) ((a << 16) | b)
-
- switch (METRICS_VERSION(frev, crev)) {
- case METRICS_VERSION(1, 0):
- structure_size = sizeof(struct gpu_metrics_v1_0);
- break;
- case METRICS_VERSION(1, 1):
- structure_size = sizeof(struct gpu_metrics_v1_1);
- break;
- case METRICS_VERSION(1, 2):
- structure_size = sizeof(struct gpu_metrics_v1_2);
- break;
- case METRICS_VERSION(1, 3):
- structure_size = sizeof(struct gpu_metrics_v1_3);
- break;
- case METRICS_VERSION(1, 4):
- structure_size = sizeof(struct gpu_metrics_v1_4);
- break;
- case METRICS_VERSION(1, 5):
- structure_size = sizeof(struct gpu_metrics_v1_5);
- break;
- case METRICS_VERSION(1, 6):
- structure_size = sizeof(struct gpu_metrics_v1_6);
- break;
- case METRICS_VERSION(1, 7):
- structure_size = sizeof(struct gpu_metrics_v1_7);
- break;
- case METRICS_VERSION(1, 8):
- structure_size = sizeof(struct gpu_metrics_v1_8);
- break;
- case METRICS_VERSION(2, 0):
- structure_size = sizeof(struct gpu_metrics_v2_0);
- break;
- case METRICS_VERSION(2, 1):
- structure_size = sizeof(struct gpu_metrics_v2_1);
- break;
- case METRICS_VERSION(2, 2):
- structure_size = sizeof(struct gpu_metrics_v2_2);
- break;
- case METRICS_VERSION(2, 3):
- structure_size = sizeof(struct gpu_metrics_v2_3);
- break;
- case METRICS_VERSION(2, 4):
- structure_size = sizeof(struct gpu_metrics_v2_4);
- break;
- case METRICS_VERSION(3, 0):
- structure_size = sizeof(struct gpu_metrics_v3_0);
- break;
- default:
- return;
- }
-
-#undef METRICS_VERSION
-
- memset(header, 0xFF, structure_size);
-
- header->format_revision = frev;
- header->content_revision = crev;
- header->structure_size = structure_size;
-
-}
-
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state)
{
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
index a020277dec3e..7473672abd2a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h
@@ -40,6 +40,30 @@
#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_ABNORMAL 0x8
#define SMU_IH_INTERRUPT_CONTEXT_ID_FAN_RECOVERY 0x9
+#define smu_cmn_init_soft_gpu_metrics(ptr, frev, crev) \
+ do { \
+ typecheck(struct gpu_metrics_v##frev##_##crev, \
+ typeof(*(ptr))); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)(ptr); \
+ memset(header, 0xFF, sizeof(*(ptr))); \
+ header->format_revision = frev; \
+ header->content_revision = crev; \
+ header->structure_size = sizeof(*(ptr)); \
+ } while (0)
+
+#define smu_cmn_init_partition_metrics(ptr, frev, crev) \
+ do { \
+ typecheck(struct amdgpu_partition_metrics_v##frev##_##crev, \
+ typeof(*(ptr))); \
+ struct metrics_table_header *header = \
+ (struct metrics_table_header *)(ptr); \
+ memset(header, 0xFF, sizeof(*(ptr))); \
+ header->format_revision = frev; \
+ header->content_revision = crev; \
+ header->structure_size = sizeof(*(ptr)); \
+ } while (0)
+
extern const int link_speed[];
/* Helper to Convert from PCIE Gen 1/2/3/4/5/6 to 0.1 GT/s speed units */
@@ -125,8 +149,6 @@ int smu_cmn_get_metrics_table(struct smu_context *smu,
int smu_cmn_get_combo_pptable(struct smu_context *smu);
-void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
-
int smu_cmn_set_mp1_state(struct smu_context *smu,
enum pp_mp1_state mp1_state);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index a761941bc3c2..505eec6b819b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1531,10 +1531,8 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
}
dp->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(dp->reg_base)) {
- ret = PTR_ERR(dp->reg_base);
- goto err_disable_clk;
- }
+ if (IS_ERR(dp->reg_base))
+ return ERR_CAST(dp->reg_base);
dp->force_hpd = of_property_read_bool(dev->of_node, "force-hpd");
@@ -1546,8 +1544,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
if (IS_ERR(dp->hpd_gpiod)) {
dev_err(dev, "error getting HDP GPIO: %ld\n",
PTR_ERR(dp->hpd_gpiod));
- ret = PTR_ERR(dp->hpd_gpiod);
- goto err_disable_clk;
+ return ERR_CAST(dp->hpd_gpiod);
}
if (dp->hpd_gpiod) {
@@ -1567,8 +1564,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
if (dp->irq == -ENXIO) {
dev_err(&pdev->dev, "failed to get irq\n");
- ret = -ENODEV;
- goto err_disable_clk;
+ return ERR_PTR(-ENODEV);
}
ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
@@ -1577,7 +1573,7 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
irq_flags, "analogix-dp", dp);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto err_disable_clk;
+ return ERR_PTR(ret);
}
dp->aux.name = "DP-AUX";
@@ -1590,13 +1586,9 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
pm_runtime_set_autosuspend_delay(dp->dev, 100);
ret = devm_pm_runtime_enable(dp->dev);
if (ret)
- goto err_disable_clk;
+ return ERR_PTR(ret);
return dp;
-
-err_disable_clk:
- clk_disable_unprepare(dp->clock);
- return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(analogix_dp_probe);
diff --git a/drivers/gpu/drm/display/drm_hdmi_audio_helper.c b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c
index 05afc9f0bdd6..ae8a0cf595fc 100644
--- a/drivers/gpu/drm/display/drm_hdmi_audio_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c
@@ -103,7 +103,8 @@ static int drm_connector_hdmi_audio_hook_plugged_cb(struct device *dev,
connector->hdmi_audio.plugged_cb = fn;
connector->hdmi_audio.plugged_cb_dev = codec_dev;
- fn(codec_dev, connector->hdmi_audio.last_state);
+ if (fn)
+ fn(codec_dev, connector->hdmi_audio.last_state);
mutex_unlock(&connector->hdmi_audio.lock);
diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c
index 40d8bbd8107d..55af3a553c58 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.c
+++ b/drivers/gpu/drm/i915/display/intel_audio.c
@@ -397,6 +397,19 @@ hsw_audio_config_update(struct intel_encoder *encoder,
hsw_hdmi_audio_config_update(encoder, crtc_state);
}
+static void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state,
+ bool enable)
+{
+ struct intel_display *display = to_intel_display(crtc_state);
+ enum transcoder trans = crtc_state->cpu_transcoder;
+
+ if (!HAS_DP20(display))
+ return;
+
+ intel_de_rmw(display, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT,
+ enable && crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0);
+}
+
static void hsw_audio_codec_disable(struct intel_encoder *encoder,
const struct intel_crtc_state *old_crtc_state,
const struct drm_connector_state *old_conn_state)
@@ -430,6 +443,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder,
if (needs_wa_14020863754(display))
intel_de_rmw(display, AUD_CHICKENBIT_REG3, DACBE_DISABLE_MIN_HBLANK_FIX, 0);
+ intel_audio_sdp_split_update(old_crtc_state, false);
+
mutex_unlock(&display->audio.mutex);
}
@@ -555,6 +570,8 @@ static void hsw_audio_codec_enable(struct intel_encoder *encoder,
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP))
enable_audio_dsc_wa(encoder, crtc_state);
+ intel_audio_sdp_split_update(crtc_state, true);
+
if (needs_wa_14020863754(display))
intel_de_rmw(display, AUD_CHICKENBIT_REG3, 0, DACBE_DISABLE_MIN_HBLANK_FIX);
@@ -681,16 +698,6 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder,
mutex_unlock(&display->audio.mutex);
}
-void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state)
-{
- struct intel_display *display = to_intel_display(crtc_state);
- enum transcoder trans = crtc_state->cpu_transcoder;
-
- if (HAS_DP20(display))
- intel_de_rmw(display, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT,
- crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0);
-}
-
bool intel_audio_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
diff --git a/drivers/gpu/drm/i915/display/intel_audio.h b/drivers/gpu/drm/i915/display/intel_audio.h
index ad49eefa7182..42cf886f3d24 100644
--- a/drivers/gpu/drm/i915/display/intel_audio.h
+++ b/drivers/gpu/drm/i915/display/intel_audio.h
@@ -31,6 +31,5 @@ int intel_audio_min_cdclk(const struct intel_crtc_state *crtc_state);
void intel_audio_init(struct intel_display *display);
void intel_audio_register(struct intel_display *display);
void intel_audio_deinit(struct intel_display *display);
-void intel_audio_sdp_split_update(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_AUDIO_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 74132c1d6385..d58f8fc37326 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -3507,9 +3507,6 @@ static void intel_ddi_enable(struct intel_atomic_state *state,
intel_vrr_transcoder_enable(crtc_state);
- /* Enable/Disable DP2.0 SDP split config before transcoder */
- intel_audio_sdp_split_update(crtc_state);
-
/* 128b/132b SST */
if (!is_hdmi && intel_dp_is_uhbr(crtc_state)) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 06f4ad8de591..e1501b13f08f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1328,8 +1328,6 @@ static void mst_stream_enable(struct intel_atomic_state *state,
FECSTALL_DIS_DPTSTREAM_DPTTG,
pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0);
- intel_audio_sdp_split_update(pipe_config);
-
intel_enable_transcoder(pipe_config);
for_each_pipe_crtc_modeset_enable(display, pipe_crtc, pipe_config, i) {
diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h
index 795e6b9cc575..248136456048 100644
--- a/drivers/gpu/drm/i915/display/intel_psr_regs.h
+++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h
@@ -325,8 +325,8 @@
#define PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(20, 16)
#define PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val)
#define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(12, 8)
-#define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val)
+#define PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION_MASK, val)
#define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION_MASK REG_GENMASK(4, 0)
-#define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION_MASK, val)
+#define PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION(val) REG_FIELD_PREP(PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION_MASK, val)
#endif /* __INTEL_PSR_REGS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c
index c6321dafef4f..74bb3bedf30f 100644
--- a/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c
+++ b/drivers/gpu/drm/i915/display/intel_snps_hdmi_pll.c
@@ -41,12 +41,12 @@ static s64 interp(s64 x, s64 x1, s64 x2, s64 y1, s64 y2)
{
s64 dydx;
- dydx = DIV_ROUND_UP_ULL((y2 - y1) * 100000, (x2 - x1));
+ dydx = DIV64_U64_ROUND_UP((y2 - y1) * 100000, (x2 - x1));
- return (y1 + DIV_ROUND_UP_ULL(dydx * (x - x1), 100000));
+ return (y1 + DIV64_U64_ROUND_UP(dydx * (x - x1), 100000));
}
-static void get_ana_cp_int_prop(u32 vco_clk,
+static void get_ana_cp_int_prop(u64 vco_clk,
u32 refclk_postscalar,
int mpll_ana_v2i,
int c, int a,
@@ -115,16 +115,16 @@ static void get_ana_cp_int_prop(u32 vco_clk,
CURVE0_MULTIPLIER));
scaled_interpolated_sqrt =
- int_sqrt(DIV_ROUND_UP_ULL(interpolated_product, vco_div_refclk_float) *
+ int_sqrt(DIV64_U64_ROUND_UP(interpolated_product, vco_div_refclk_float) *
DIV_ROUND_DOWN_ULL(1000000000000ULL, 55));
/* Scale vco_div_refclk for ana_cp_int */
scaled_vco_div_refclk2 = DIV_ROUND_UP_ULL(vco_div_refclk_float, 1000000);
- adjusted_vco_clk2 = 1460281 * DIV_ROUND_UP_ULL(scaled_interpolated_sqrt *
+ adjusted_vco_clk2 = 1460281 * DIV64_U64_ROUND_UP(scaled_interpolated_sqrt *
scaled_vco_div_refclk2,
curve_1_interpolated);
- *ana_cp_prop = DIV_ROUND_UP_ULL(adjusted_vco_clk2, curve_2_scaled2);
+ *ana_cp_prop = DIV64_U64_ROUND_UP(adjusted_vco_clk2, curve_2_scaled2);
*ana_cp_prop = max(1, min(*ana_cp_prop, 127));
}
@@ -165,10 +165,10 @@ static void compute_hdmi_tmds_pll(u64 pixel_clock, u32 refclk,
/* Select appropriate v2i point */
if (datarate <= INTEL_SNPS_PHY_HDMI_9999MHZ) {
mpll_ana_v2i = 2;
- tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_9999MHZ, datarate));
+ tx_clk_div = ilog2(div64_u64(INTEL_SNPS_PHY_HDMI_9999MHZ, datarate));
} else {
mpll_ana_v2i = 3;
- tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_16GHZ, datarate));
+ tx_clk_div = ilog2(div64_u64(INTEL_SNPS_PHY_HDMI_16GHZ, datarate));
}
vco_clk = (datarate << tx_clk_div) >> 1;
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
index f8cb7c630d5b..127316d2c8aa 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
@@ -633,7 +633,7 @@ static int guc_submission_send_busy_loop(struct intel_guc *guc,
atomic_inc(&guc->outstanding_submission_g2h);
ret = intel_guc_send_busy_loop(guc, action, len, g2h_len_dw, loop);
- if (ret)
+ if (ret && g2h_len_dw)
atomic_dec(&guc->outstanding_submission_g2h);
return ret;
@@ -3443,18 +3443,29 @@ static inline int guc_lrc_desc_unpin(struct intel_context *ce)
* GuC is active, lets destroy this context, but at this point we can still be racing
* with suspend, so we undo everything if the H2G fails in deregister_context so
* that GuC reset will find this context during clean up.
+ *
+ * There is a race condition where the reset code could have altered
+ * this context's state and done a wakeref put before we try to
+ * deregister it here. So check if the context is still set to be
+ * destroyed before undoing earlier changes, to avoid two wakeref puts
+ * on the same context.
*/
ret = deregister_context(ce, ce->guc_id.id);
if (ret) {
+ bool pending_destroyed;
spin_lock_irqsave(&ce->guc_state.lock, flags);
- set_context_registered(ce);
- clr_context_destroyed(ce);
+ pending_destroyed = context_destroyed(ce);
+ if (pending_destroyed) {
+ set_context_registered(ce);
+ clr_context_destroyed(ce);
+ }
spin_unlock_irqrestore(&ce->guc_state.lock, flags);
/*
* As gt-pm is awake at function entry, intel_wakeref_put_async merely decrements
* the wakeref immediately but per function spec usage call this after unlock.
*/
- intel_wakeref_put_async(&gt->wakeref);
+ if (pending_destroyed)
+ intel_wakeref_put_async(&gt->wakeref);
}
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c
index 9446049642e1..d294844d9eae 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/vfn/r535.c
@@ -42,7 +42,7 @@ r535_vfn_new(const struct nvkm_vfn_func *hw,
return -ENOMEM;
rm->dtor = r535_vfn_dtor;
- rm->intr = &tu102_vfn_intr,
+ rm->intr = &tu102_vfn_intr;
rm->user.addr = 0x030000;
rm->user.size = 0x010000;
rm->user.base.minver = -1;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 721581d425b4..cfebb08e8a62 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -522,6 +522,8 @@ config DRM_PANEL_NOVATEK_NT37801
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_DISPLAY_DSC_HELPER
+ select DRM_DISPLAY_HELPER
help
Say Y here if you want to enable support for Novatek NT37801 (or
NT37810) AMOLED DSI Video Mode LCD panel module with 1440x3200
diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c
index 84d367eab058..d6a37d7e0cc6 100644
--- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c
+++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c
@@ -257,8 +257,8 @@ static int novatek_nt37801_probe(struct mipi_dsi_device *dsi)
ctx = devm_drm_panel_alloc(dev, struct novatek_nt37801, panel,
&novatek_nt37801_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
- if (!ctx)
- return -ENOMEM;
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
ret = devm_regulator_bulk_get_const(dev,
ARRAY_SIZE(novatek_nt37801_supplies),
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 82ee2f12b8d2..0a3b26bb4d73 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2198,13 +2198,14 @@ static const struct display_timing evervision_vgg644804_timing = {
static const struct panel_desc evervision_vgg644804 = {
.timings = &evervision_vgg644804_timing,
.num_timings = 1,
- .bpc = 8,
+ .bpc = 6,
.size = {
.width = 115,
.height = 86,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
- .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE,
+ .bus_flags = DRM_BUS_FLAG_DE_HIGH,
+ .connector_type = DRM_MODE_CONNECTOR_LVDS,
};
static const struct display_timing evervision_vgg804821_timing = {
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index a7caac5b8ac8..1afa70566985 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -5071,7 +5071,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
#define SYS_INFO_GPUCAPS__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01
#define SYS_INFO_GPUCAPS__DP_SINGLEPLL_MODE 0x02
#define SYS_INFO_GPUCAPS__DISABLE_AUX_MODE_DETECT 0x08
-#define SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS 0x10
+#define SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS 0x10
/**********************************************************************************************************************
ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c
index 55dbf450bd9c..4aa050385284 100644
--- a/drivers/gpu/drm/radeon/kv_dpm.c
+++ b/drivers/gpu/drm/radeon/kv_dpm.c
@@ -2329,7 +2329,7 @@ static int kv_parse_sys_info_table(struct radeon_device *rdev)
le32_to_cpu(igp_info->info_8.ulNbpStateNClkFreq[i]);
}
if (le32_to_cpu(igp_info->info_8.ulGPUCapInfo) &
- SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS)
+ SYS_INFO_GPUCAPS__ENABLE_DFS_BYPASS)
pi->caps_enable_dfs_bypass = true;
sumo_construct_sclk_voltage_mapping_table(rdev,
diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index bd39db7bb240..e671aa241720 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -176,6 +176,7 @@ static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
{
struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
+ drm_sched_fence_scheduled(job->s_fence, NULL);
drm_sched_fence_finished(job->s_fence, -ESRCH);
WARN_ON(job->s_fence->parent);
job->sched->ops->free_job(job);
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index 2169bc969ea1..fcc2677a4229 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -2,6 +2,8 @@
config DRM_XE
tristate "Intel Xe Graphics"
depends on DRM && PCI && (m || (y && KUNIT=y))
+ depends on INTEL_VSEC || !INTEL_VSEC
+ depends on X86_PLATFORM_DEVICES || !(X86 && ACPI)
select INTERVAL_TREE
# we need shmfs for the swappable backing store, and in particular
# the shmem_readpage() which depends upon tmpfs
@@ -27,7 +29,6 @@ config DRM_XE
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select ACPI_VIDEO if X86 && ACPI
- select X86_PLATFORM_DEVICES if X86 && ACPI
select ACPI_WMI if X86 && ACPI
select SYNC_FILE
select IOSF_MBI
diff --git a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h
index f5e5234857c1..5394a1373a6b 100644
--- a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h
@@ -38,10 +38,10 @@
#define TEMP_MASK REG_GENMASK(7, 0)
#define PCU_CR_PACKAGE_RAPL_LIMIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x59a0)
-#define PKG_PWR_LIM_1 REG_GENMASK(14, 0)
-#define PKG_PWR_LIM_1_EN REG_BIT(15)
-#define PKG_PWR_LIM_1_TIME REG_GENMASK(23, 17)
-#define PKG_PWR_LIM_1_TIME_X REG_GENMASK(23, 22)
-#define PKG_PWR_LIM_1_TIME_Y REG_GENMASK(21, 17)
+#define PWR_LIM_VAL REG_GENMASK(14, 0)
+#define PWR_LIM_EN REG_BIT(15)
+#define PWR_LIM_TIME REG_GENMASK(23, 17)
+#define PWR_LIM_TIME_X REG_GENMASK(23, 22)
+#define PWR_LIM_TIME_Y REG_GENMASK(21, 17)
#endif /* _XE_MCHBAR_REGS_H_ */
diff --git a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
index c7d5d782e3f9..c556a04670ee 100644
--- a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
+++ b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
@@ -18,16 +18,12 @@
#define PVC_GT0_PLATFORM_ENERGY_STATUS XE_REG(0x28106c)
#define PVC_GT0_PACKAGE_POWER_SKU XE_REG(0x281080)
-#define BMG_PACKAGE_POWER_SKU XE_REG(0x138098)
-#define BMG_PACKAGE_POWER_SKU_UNIT XE_REG(0x1380dc)
#define BMG_PACKAGE_ENERGY_STATUS XE_REG(0x138120)
#define BMG_FAN_1_SPEED XE_REG(0x138140)
#define BMG_FAN_2_SPEED XE_REG(0x138170)
#define BMG_FAN_3_SPEED XE_REG(0x1381a0)
#define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0)
#define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434)
-#define BMG_PACKAGE_RAPL_LIMIT XE_REG(0x138440)
#define BMG_PLATFORM_ENERGY_STATUS XE_REG(0x138458)
-#define BMG_PLATFORM_POWER_LIMIT XE_REG(0x138460)
#endif /* _XE_PCODE_REGS_H_ */
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index d99d91fe8aa9..7aa2c17825da 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -841,21 +841,6 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
goto out;
}
- /* Reject BO eviction if BO is bound to current VM. */
- if (evict && ctx->resv) {
- struct drm_gpuvm_bo *vm_bo;
-
- drm_gem_for_each_gpuvm_bo(vm_bo, &bo->ttm.base) {
- struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm);
-
- if (xe_vm_resv(vm) == ctx->resv &&
- xe_vm_in_preempt_fence_mode(vm)) {
- ret = -EBUSY;
- goto out;
- }
- }
- }
-
/*
* Failed multi-hop where the old_mem is still marked as
* TTM_PL_FLAG_TEMPORARY, should just be a dummy move.
@@ -1013,6 +998,25 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx,
return lret;
}
+static bool
+xe_bo_eviction_valuable(struct ttm_buffer_object *bo, const struct ttm_place *place)
+{
+ struct drm_gpuvm_bo *vm_bo;
+
+ if (!ttm_bo_eviction_valuable(bo, place))
+ return false;
+
+ if (!xe_bo_is_xe_bo(bo))
+ return true;
+
+ drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) {
+ if (xe_vm_is_validating(gpuvm_to_vm(vm_bo->vm)))
+ return false;
+ }
+
+ return true;
+}
+
/**
* xe_bo_shrink() - Try to shrink an xe bo.
* @ctx: The struct ttm_operation_ctx used for shrinking.
@@ -1047,7 +1051,7 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
(flags.purge && !xe_tt->purgeable))
return -EBUSY;
- if (!ttm_bo_eviction_valuable(bo, &place))
+ if (!xe_bo_eviction_valuable(bo, &place))
return -EBUSY;
if (!xe_bo_is_xe_bo(bo) || !xe_bo_get_unless_zero(xe_bo))
@@ -1588,7 +1592,7 @@ const struct ttm_device_funcs xe_ttm_funcs = {
.io_mem_pfn = xe_ttm_io_mem_pfn,
.access_memory = xe_ttm_access_memory,
.release_notify = xe_ttm_bo_release_notify,
- .eviction_valuable = ttm_bo_eviction_valuable,
+ .eviction_valuable = xe_bo_eviction_valuable,
.delete_mem_notify = xe_ttm_bo_delete_mem_notify,
.swap_notify = xe_ttm_bo_swap_notify,
};
@@ -2431,6 +2435,8 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
.no_wait_gpu = false,
.gfp_retry_mayfail = true,
};
+ struct pin_cookie cookie;
+ int ret;
if (vm) {
lockdep_assert_held(&vm->lock);
@@ -2440,8 +2446,12 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
ctx.resv = xe_vm_resv(vm);
}
+ cookie = xe_vm_set_validating(vm, allow_res_evict);
trace_xe_bo_validate(bo);
- return ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
+ ret = ttm_bo_validate(&bo->ttm, &bo->placement, &ctx);
+ xe_vm_clear_validating(vm, allow_res_evict, cookie);
+
+ return ret;
}
bool xe_bo_is_xe_bo(struct ttm_buffer_object *bo)
@@ -2557,7 +2567,7 @@ typedef int (*xe_gem_create_set_property_fn)(struct xe_device *xe,
u64 value);
static const xe_gem_create_set_property_fn gem_create_set_property_funcs[] = {
- [DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_set_pxp_type,
+ [DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE] = gem_create_set_pxp_type,
};
static int gem_create_user_ext_set_property(struct xe_device *xe,
diff --git a/drivers/gpu/drm/xe/xe_device_sysfs.c b/drivers/gpu/drm/xe/xe_device_sysfs.c
index 2e657692e5b5..b9440f8c781e 100644
--- a/drivers/gpu/drm/xe/xe_device_sysfs.c
+++ b/drivers/gpu/drm/xe/xe_device_sysfs.c
@@ -115,7 +115,7 @@ auto_link_downgrade_capable_show(struct device *dev, struct device_attribute *at
xe_pm_runtime_put(xe);
cap = REG_FIELD_GET(LINK_DOWNGRADE, val);
- return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE ? true : false);
+ return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE);
}
static DEVICE_ATTR_ADMIN_RO(auto_link_downgrade_capable);
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index c8fa2c011666..6383a1c0d478 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -325,6 +325,10 @@ struct xe_device {
u8 has_heci_gscfi:1;
/** @info.has_llc: Device has a shared CPU+GPU last level cache */
u8 has_llc:1;
+ /** @info.has_mbx_power_limits: Device has support to manage power limits using
+ * pcode mailbox commands.
+ */
+ u8 has_mbx_power_limits:1;
/** @info.has_pxp: Device has PXP support */
u8 has_pxp:1;
/** @info.has_range_tlb_invalidation: Has range based TLB invalidations */
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index ce78cee5dec6..fee22358cc09 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -114,7 +114,6 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
static int __xe_exec_queue_init(struct xe_exec_queue *q)
{
- struct xe_vm *vm = q->vm;
int i, err;
u32 flags = 0;
@@ -132,32 +131,20 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q)
flags |= XE_LRC_CREATE_RUNALONE;
}
- if (vm) {
- err = xe_vm_lock(vm, true);
- if (err)
- return err;
- }
-
for (i = 0; i < q->width; ++i) {
q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, q->msix_vec, flags);
if (IS_ERR(q->lrc[i])) {
err = PTR_ERR(q->lrc[i]);
- goto err_unlock;
+ goto err_lrc;
}
}
- if (vm)
- xe_vm_unlock(vm);
-
err = q->ops->init(q);
if (err)
goto err_lrc;
return 0;
-err_unlock:
- if (vm)
- xe_vm_unlock(vm);
err_lrc:
for (i = i - 1; i >= 0; --i)
xe_lrc_put(q->lrc[i]);
diff --git a/drivers/gpu/drm/xe/xe_gpu_scheduler.h b/drivers/gpu/drm/xe/xe_gpu_scheduler.h
index c250ea773491..308061f0cf37 100644
--- a/drivers/gpu/drm/xe/xe_gpu_scheduler.h
+++ b/drivers/gpu/drm/xe/xe_gpu_scheduler.h
@@ -51,7 +51,15 @@ static inline void xe_sched_tdr_queue_imm(struct xe_gpu_scheduler *sched)
static inline void xe_sched_resubmit_jobs(struct xe_gpu_scheduler *sched)
{
- drm_sched_resubmit_jobs(&sched->base);
+ struct drm_sched_job *s_job;
+
+ list_for_each_entry(s_job, &sched->base.pending_list, list) {
+ struct drm_sched_fence *s_fence = s_job->s_fence;
+ struct dma_fence *hw_fence = s_fence->parent;
+
+ if (hw_fence && !dma_fence_is_signaled(hw_fence))
+ sched->base.ops->run_job(s_job);
+ }
}
static inline bool
diff --git a/drivers/gpu/drm/xe/xe_gt_freq.c b/drivers/gpu/drm/xe/xe_gt_freq.c
index 868a5d2c1a52..60d9354e7dbf 100644
--- a/drivers/gpu/drm/xe/xe_gt_freq.c
+++ b/drivers/gpu/drm/xe/xe_gt_freq.c
@@ -32,13 +32,18 @@
* Xe's Freq provides a sysfs API for frequency management:
*
* device/tile#/gt#/freq0/<item>_freq *read-only* files:
+ *
* - act_freq: The actual resolved frequency decided by PCODE.
* - cur_freq: The current one requested by GuC PC to the PCODE.
* - rpn_freq: The Render Performance (RP) N level, which is the minimal one.
+ * - rpa_freq: The Render Performance (RP) A level, which is the achiveable one.
+ * Calculated by PCODE at runtime based on multiple running conditions
* - rpe_freq: The Render Performance (RP) E level, which is the efficient one.
+ * Calculated by PCODE at runtime based on multiple running conditions
* - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.
*
* device/tile#/gt#/freq0/<item>_freq *read-write* files:
+ *
* - min_freq: Min frequency request.
* - max_freq: Max frequency request.
* If max <= min, then freq_min becomes a fixed frequency request.
diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c
index 2ad38f6b103e..6d84a52b660a 100644
--- a/drivers/gpu/drm/xe/xe_guc_submit.c
+++ b/drivers/gpu/drm/xe/xe_guc_submit.c
@@ -229,6 +229,17 @@ static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q)
static void guc_submit_fini(struct drm_device *drm, void *arg)
{
struct xe_guc *guc = arg;
+ struct xe_device *xe = guc_to_xe(guc);
+ struct xe_gt *gt = guc_to_gt(guc);
+ int ret;
+
+ ret = wait_event_timeout(guc->submission_state.fini_wq,
+ xa_empty(&guc->submission_state.exec_queue_lookup),
+ HZ * 5);
+
+ drain_workqueue(xe->destroy_wq);
+
+ xe_gt_assert(gt, ret);
xa_destroy(&guc->submission_state.exec_queue_lookup);
}
diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index eb293aec36a0..74f31639b37f 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -52,6 +52,14 @@ enum xe_fan_channel {
};
/*
+ * For platforms that support mailbox commands for power limits, REG_PKG_POWER_SKU_UNIT is
+ * not supported and below are SKU units to be used.
+ */
+#define PWR_UNIT 0x3
+#define ENERGY_UNIT 0xe
+#define TIME_UNIT 0xa
+
+/*
* SF_* - scale factors for particular quantities according to hwmon spec.
*/
#define SF_POWER 1000000 /* microwatts */
@@ -60,6 +68,18 @@ enum xe_fan_channel {
#define SF_ENERGY 1000000 /* microjoules */
#define SF_TIME 1000 /* milliseconds */
+/*
+ * PL*_HWMON_ATTR - mapping of hardware power limits to corresponding hwmon power attribute.
+ */
+#define PL1_HWMON_ATTR hwmon_power_max
+
+#define PWR_ATTR_TO_STR(attr) (((attr) == hwmon_power_max) ? "PL1" : "Invalid")
+
+/*
+ * Timeout for power limit write mailbox command.
+ */
+#define PL_WRITE_MBX_TIMEOUT_MS (1)
+
/**
* struct xe_hwmon_energy_info - to accumulate energy
*/
@@ -100,8 +120,80 @@ struct xe_hwmon {
struct xe_hwmon_energy_info ei[CHANNEL_MAX];
/** @fi: Fan info for fanN_input */
struct xe_hwmon_fan_info fi[FAN_MAX];
+ /** @boot_power_limit_read: is boot power limits read */
+ bool boot_power_limit_read;
+ /** @pl1_on_boot: power limit PL1 on boot */
+ u32 pl1_on_boot[CHANNEL_MAX];
};
+static int xe_hwmon_pcode_read_power_limit(const struct xe_hwmon *hwmon, u32 attr, int channel,
+ u32 *uval)
+{
+ struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
+ u32 val0 = 0, val1 = 0;
+ int ret = 0;
+
+ ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_POWER_SETUP,
+ (channel == CHANNEL_CARD) ?
+ READ_PSYSGPU_POWER_LIMIT :
+ READ_PACKAGE_POWER_LIMIT,
+ hwmon->boot_power_limit_read ?
+ READ_PL_FROM_PCODE : READ_PL_FROM_FW),
+ &val0, &val1);
+
+ if (ret) {
+ drm_dbg(&hwmon->xe->drm, "read failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n",
+ channel, val0, val1, ret);
+ *uval = 0;
+ return ret;
+ }
+
+ /* return the value only if limit is enabled */
+ if (attr == PL1_HWMON_ATTR)
+ *uval = (val0 & PWR_LIM_EN) ? val0 : 0;
+ else if (attr == hwmon_power_label)
+ *uval = (val0 & PWR_LIM_EN) ? 1 : 0;
+ else
+ *uval = 0;
+
+ return ret;
+}
+
+static int xe_hwmon_pcode_write_power_limit(const struct xe_hwmon *hwmon, u32 attr, u8 channel,
+ u32 uval)
+{
+ struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
+ u32 val0, val1;
+ int ret = 0;
+
+ ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_POWER_SETUP,
+ (channel == CHANNEL_CARD) ?
+ READ_PSYSGPU_POWER_LIMIT :
+ READ_PACKAGE_POWER_LIMIT,
+ hwmon->boot_power_limit_read ?
+ READ_PL_FROM_PCODE : READ_PL_FROM_FW),
+ &val0, &val1);
+
+ if (ret)
+ drm_dbg(&hwmon->xe->drm, "read failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n",
+ channel, val0, val1, ret);
+
+ if (attr == PL1_HWMON_ATTR)
+ val0 = uval;
+ else
+ return -EIO;
+
+ ret = xe_pcode_write64_timeout(root_tile, PCODE_MBOX(PCODE_POWER_SETUP,
+ (channel == CHANNEL_CARD) ?
+ WRITE_PSYSGPU_POWER_LIMIT :
+ WRITE_PACKAGE_POWER_LIMIT, 0),
+ val0, val1, PL_WRITE_MBX_TIMEOUT_MS);
+ if (ret)
+ drm_dbg(&hwmon->xe->drm, "write failed ch %d val0 0x%08x, val1 0x%08x, ret %d\n",
+ channel, val0, val1, ret);
+ return ret;
+}
+
static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg,
int channel)
{
@@ -122,29 +214,19 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
}
break;
case REG_PKG_RAPL_LIMIT:
- if (xe->info.platform == XE_BATTLEMAGE) {
- if (channel == CHANNEL_PKG)
- return BMG_PACKAGE_RAPL_LIMIT;
- else
- return BMG_PLATFORM_POWER_LIMIT;
- } else if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG) {
+ if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG)
return PVC_GT0_PACKAGE_RAPL_LIMIT;
- } else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG)) {
+ else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG))
return PCU_CR_PACKAGE_RAPL_LIMIT;
- }
break;
case REG_PKG_POWER_SKU:
- if (xe->info.platform == XE_BATTLEMAGE)
- return BMG_PACKAGE_POWER_SKU;
- else if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG)
+ if (xe->info.platform == XE_PVC && channel == CHANNEL_PKG)
return PVC_GT0_PACKAGE_POWER_SKU;
else if ((xe->info.platform == XE_DG2) && (channel == CHANNEL_PKG))
return PCU_CR_PACKAGE_POWER_SKU;
break;
case REG_PKG_POWER_SKU_UNIT:
- if (xe->info.platform == XE_BATTLEMAGE)
- return BMG_PACKAGE_POWER_SKU_UNIT;
- else if (xe->info.platform == XE_PVC)
+ if (xe->info.platform == XE_PVC)
return PVC_GT0_PACKAGE_POWER_SKU_UNIT;
else if (xe->info.platform == XE_DG2)
return PCU_CR_PACKAGE_POWER_SKU_UNIT;
@@ -181,7 +263,7 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
return XE_REG(0);
}
-#define PL1_DISABLE 0
+#define PL_DISABLE 0
/*
* HW allows arbitrary PL1 limits to be set but silently clamps these values to
@@ -189,67 +271,83 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
* same pattern for sysfs, allow arbitrary PL1 limits to be set but display
* clamped values when read.
*/
-static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *value)
+static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *value)
{
u64 reg_val, min, max;
struct xe_device *xe = hwmon->xe;
struct xe_reg rapl_limit, pkg_power_sku;
struct xe_mmio *mmio = xe_root_tile_mmio(xe);
- rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel);
- pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
+ mutex_lock(&hwmon->hwmon_lock);
- /*
- * Valid check of REG_PKG_RAPL_LIMIT is already done in xe_hwmon_power_is_visible.
- * So not checking it again here.
- */
- if (!xe_reg_is_valid(pkg_power_sku)) {
- drm_warn(&xe->drm, "pkg_power_sku invalid\n");
- *value = 0;
- return;
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, (u32 *)&reg_val);
+ } else {
+ rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel);
+ pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
+
+ /*
+ * Valid check of REG_PKG_RAPL_LIMIT is already done in xe_hwmon_power_is_visible.
+ * So not checking it again here.
+ */
+ if (!xe_reg_is_valid(pkg_power_sku)) {
+ drm_warn(&xe->drm, "pkg_power_sku invalid\n");
+ *value = 0;
+ goto unlock;
+ }
+ reg_val = xe_mmio_read32(mmio, rapl_limit);
}
- mutex_lock(&hwmon->hwmon_lock);
-
- reg_val = xe_mmio_read32(mmio, rapl_limit);
- /* Check if PL1 limit is disabled */
- if (!(reg_val & PKG_PWR_LIM_1_EN)) {
- *value = PL1_DISABLE;
+ /* Check if PL limits are disabled. */
+ if (!(reg_val & PWR_LIM_EN)) {
+ *value = PL_DISABLE;
+ drm_info(&hwmon->xe->drm, "%s disabled for channel %d, val 0x%016llx\n",
+ PWR_ATTR_TO_STR(attr), channel, reg_val);
goto unlock;
}
- reg_val = REG_FIELD_GET(PKG_PWR_LIM_1, reg_val);
+ reg_val = REG_FIELD_GET(PWR_LIM_VAL, reg_val);
*value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
- reg_val = xe_mmio_read64_2x32(mmio, pkg_power_sku);
- min = REG_FIELD_GET(PKG_MIN_PWR, reg_val);
- min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
- max = REG_FIELD_GET(PKG_MAX_PWR, reg_val);
- max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
-
- if (min && max)
- *value = clamp_t(u64, *value, min, max);
+ /* For platforms with mailbox power limit support clamping would be done by pcode. */
+ if (!hwmon->xe->info.has_mbx_power_limits) {
+ reg_val = xe_mmio_read64_2x32(mmio, pkg_power_sku);
+ min = REG_FIELD_GET(PKG_MIN_PWR, reg_val);
+ max = REG_FIELD_GET(PKG_MAX_PWR, reg_val);
+ min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
+ max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
+ if (min && max)
+ *value = clamp_t(u64, *value, min, max);
+ }
unlock:
mutex_unlock(&hwmon->hwmon_lock);
}
-static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long value)
+static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, u32 attr, int channel, long value)
{
struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
int ret = 0;
- u64 reg_val;
+ u32 reg_val;
struct xe_reg rapl_limit;
+ mutex_lock(&hwmon->hwmon_lock);
+
rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel);
- mutex_lock(&hwmon->hwmon_lock);
+ /* Disable Power Limit and verify, as limit cannot be disabled on all platforms. */
+ if (value == PL_DISABLE) {
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ drm_dbg(&hwmon->xe->drm, "disabling %s on channel %d\n",
+ PWR_ATTR_TO_STR(attr), channel);
+ xe_hwmon_pcode_write_power_limit(hwmon, attr, channel, 0);
+ xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, &reg_val);
+ } else {
+ reg_val = xe_mmio_rmw32(mmio, rapl_limit, PWR_LIM_EN, 0);
+ reg_val = xe_mmio_read32(mmio, rapl_limit);
+ }
- /* Disable PL1 limit and verify, as limit cannot be disabled on all platforms */
- if (value == PL1_DISABLE) {
- reg_val = xe_mmio_rmw32(mmio, rapl_limit, PKG_PWR_LIM_1_EN, 0);
- reg_val = xe_mmio_read32(mmio, rapl_limit);
- if (reg_val & PKG_PWR_LIM_1_EN) {
- drm_warn(&hwmon->xe->drm, "PL1 disable is not supported!\n");
+ if (reg_val & PWR_LIM_EN) {
+ drm_warn(&hwmon->xe->drm, "Power limit disable is not supported!\n");
ret = -EOPNOTSUPP;
}
goto unlock;
@@ -257,26 +355,50 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va
/* Computation in 64-bits to avoid overflow. Round to nearest. */
reg_val = DIV_ROUND_CLOSEST_ULL((u64)value << hwmon->scl_shift_power, SF_POWER);
- reg_val = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, reg_val);
- reg_val = xe_mmio_rmw32(mmio, rapl_limit, PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, reg_val);
+ reg_val = PWR_LIM_EN | REG_FIELD_PREP(PWR_LIM_VAL, reg_val);
+ /*
+ * Clamp power limit to card-firmware default as maximum, as an additional protection to
+ * pcode clamp.
+ */
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ if (reg_val > REG_FIELD_GET(PWR_LIM_VAL, hwmon->pl1_on_boot[channel])) {
+ reg_val = REG_FIELD_GET(PWR_LIM_VAL, hwmon->pl1_on_boot[channel]);
+ drm_dbg(&hwmon->xe->drm, "Clamping power limit to firmware default 0x%x\n",
+ reg_val);
+ }
+ }
+
+ if (hwmon->xe->info.has_mbx_power_limits)
+ ret = xe_hwmon_pcode_write_power_limit(hwmon, attr, channel, reg_val);
+ else
+ reg_val = xe_mmio_rmw32(mmio, rapl_limit, PWR_LIM_EN | PWR_LIM_VAL,
+ reg_val);
unlock:
mutex_unlock(&hwmon->hwmon_lock);
return ret;
}
-static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, int channel, long *value)
+static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, u32 attr, int channel,
+ long *value)
{
struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
- struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
- u64 reg_val;
+ u32 reg_val;
+
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ /* PL1 is rated max if supported. */
+ xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, channel, &reg_val);
+ } else {
+ /*
+ * This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check
+ * for this register can be skipped.
+ * See xe_hwmon_power_is_visible.
+ */
+ struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel);
+
+ reg_val = xe_mmio_read32(mmio, reg);
+ }
- /*
- * This sysfs file won't be visible if REG_PKG_POWER_SKU is invalid, so valid check
- * for this register can be skipped.
- * See xe_hwmon_power_is_visible.
- */
- reg_val = xe_mmio_read32(mmio, reg);
reg_val = REG_FIELD_GET(PKG_TDP, reg_val);
*value = mul_u64_u32_shr(reg_val, SF_POWER, hwmon->scl_shift_power);
}
@@ -330,23 +452,35 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at
struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
u32 x, y, x_w = 2; /* 2 bits */
u64 r, tau4, out;
- int sensor_index = to_sensor_dev_attr(attr)->index;
+ int channel = to_sensor_dev_attr(attr)->index;
+ u32 power_attr = PL1_HWMON_ATTR;
+ int ret = 0;
xe_pm_runtime_get(hwmon->xe);
mutex_lock(&hwmon->hwmon_lock);
- r = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index));
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ ret = xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, (u32 *)&r);
+ if (ret) {
+ drm_err(&hwmon->xe->drm,
+ "power interval read fail, ch %d, attr %d, r 0%llx, ret %d\n",
+ channel, power_attr, r, ret);
+ r = 0;
+ }
+ } else {
+ r = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel));
+ }
mutex_unlock(&hwmon->hwmon_lock);
xe_pm_runtime_put(hwmon->xe);
- x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r);
- y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r);
+ x = REG_FIELD_GET(PWR_LIM_TIME_X, r);
+ y = REG_FIELD_GET(PWR_LIM_TIME_Y, r);
/*
- * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17)
+ * tau = (1 + (x / 4)) * power(2,y), x = bits(23:22), y = bits(21:17)
* = (4 | x) << (y - 2)
*
* Here (y - 2) ensures a 1.x fixed point representation of 1.x
@@ -373,14 +507,15 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a
u64 tau4, r, max_win;
unsigned long val;
int ret;
- int sensor_index = to_sensor_dev_attr(attr)->index;
+ int channel = to_sensor_dev_attr(attr)->index;
+ u32 power_attr = PL1_HWMON_ATTR;
ret = kstrtoul(buf, 0, &val);
if (ret)
return ret;
/*
- * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12.
+ * Max HW supported tau in '(1 + (x / 4)) * power(2,y)' format, x = 0, y = 0x12.
* The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds.
*
* The ideal scenario is for PKG_MAX_WIN to be read from the PKG_PWR_SKU register.
@@ -400,11 +535,13 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a
tau4 = (u64)((1 << x_w) | x) << y;
max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
- if (val > max_win)
+ if (val > max_win) {
+ drm_warn(&hwmon->xe->drm, "power_interval invalid val 0x%lx\n", val);
return -EINVAL;
+ }
/* val in hw units */
- val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME);
+ val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME) + 1;
/*
* Convert val to 1.x * power(2,y)
@@ -419,14 +556,21 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a
x = (val - (1ul << y)) << x_w >> y;
}
- rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y);
+ rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) |
+ REG_FIELD_PREP(PWR_LIM_TIME_Y, y);
xe_pm_runtime_get(hwmon->xe);
mutex_lock(&hwmon->hwmon_lock);
- r = xe_mmio_rmw32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, sensor_index),
- PKG_PWR_LIM_1_TIME, rxy);
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ ret = xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, (u32 *)&r);
+ r = (r & ~PWR_LIM_TIME) | rxy;
+ xe_hwmon_pcode_write_power_limit(hwmon, power_attr, channel, r);
+ } else {
+ r = xe_mmio_rmw32(mmio, xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel),
+ PWR_LIM_TIME, rxy);
+ }
mutex_unlock(&hwmon->hwmon_lock);
@@ -435,6 +579,7 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a
return count;
}
+/* PSYS PL1 */
static SENSOR_DEVICE_ATTR(power1_max_interval, 0664,
xe_hwmon_power_max_interval_show,
xe_hwmon_power_max_interval_store, CHANNEL_CARD);
@@ -455,10 +600,19 @@ static umode_t xe_hwmon_attributes_visible(struct kobject *kobj,
struct device *dev = kobj_to_dev(kobj);
struct xe_hwmon *hwmon = dev_get_drvdata(dev);
int ret = 0;
+ int channel = index ? CHANNEL_PKG : CHANNEL_CARD;
+ u32 power_attr = PL1_HWMON_ATTR;
+ u32 uval;
xe_pm_runtime_get(hwmon->xe);
- ret = xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, index)) ? attr->mode : 0;
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ xe_hwmon_pcode_read_power_limit(hwmon, power_attr, channel, &uval);
+ ret = (uval & PWR_LIM_EN) ? attr->mode : 0;
+ } else {
+ ret = xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT,
+ channel)) ? attr->mode : 0;
+ }
xe_pm_runtime_put(hwmon->xe);
@@ -478,8 +632,8 @@ static const struct attribute_group *hwmon_groups[] = {
static const struct hwmon_channel_info * const hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
- HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL,
- HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT | HWMON_P_LABEL),
+ HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT,
+ HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL),
HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | HWMON_C_LABEL),
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL),
HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
@@ -604,19 +758,27 @@ xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
switch (attr) {
case hwmon_power_max:
- return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT,
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ xe_hwmon_pcode_read_power_limit(hwmon, attr, channel, &uval);
+ return (uval) ? 0664 : 0;
+ } else {
+ return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT,
channel)) ? 0664 : 0;
+ }
case hwmon_power_rated_max:
- return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU,
- channel)) ? 0444 : 0;
+ if (hwmon->xe->info.has_mbx_power_limits)
+ return 0;
+ else
+ return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU,
+ channel)) ? 0444 : 0;
case hwmon_power_crit:
- if (channel == CHANNEL_PKG)
- return (xe_hwmon_pcode_read_i1(hwmon, &uval) ||
- !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
- break;
case hwmon_power_label:
- return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT,
- channel)) ? 0444 : 0;
+ if (channel == CHANNEL_CARD) {
+ xe_hwmon_pcode_read_i1(hwmon, &uval);
+ return (uval & POWER_SETUP_I1_WATTS) ? (attr == hwmon_power_label) ?
+ 0444 : 0644 : 0;
+ }
+ break;
default:
return 0;
}
@@ -628,10 +790,10 @@ xe_hwmon_power_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
{
switch (attr) {
case hwmon_power_max:
- xe_hwmon_power_max_read(hwmon, channel, val);
+ xe_hwmon_power_max_read(hwmon, attr, channel, val);
return 0;
case hwmon_power_rated_max:
- xe_hwmon_power_rated_max_read(hwmon, channel, val);
+ xe_hwmon_power_rated_max_read(hwmon, attr, channel, val);
return 0;
case hwmon_power_crit:
return xe_hwmon_power_curr_crit_read(hwmon, channel, val, SF_POWER);
@@ -645,7 +807,7 @@ xe_hwmon_power_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
{
switch (attr) {
case hwmon_power_max:
- return xe_hwmon_power_max_write(hwmon, channel, val);
+ return xe_hwmon_power_max_write(hwmon, attr, channel, val);
case hwmon_power_crit:
return xe_hwmon_power_curr_crit_write(hwmon, channel, val, SF_POWER);
default:
@@ -965,18 +1127,42 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
int channel;
struct xe_reg pkg_power_sku_unit;
- /*
- * The contents of register PKG_POWER_SKU_UNIT do not change,
- * so read it once and store the shift values.
- */
- pkg_power_sku_unit = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0);
- if (xe_reg_is_valid(pkg_power_sku_unit)) {
- val_sku_unit = xe_mmio_read32(mmio, pkg_power_sku_unit);
- hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
- hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
- hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
+ if (hwmon->xe->info.has_mbx_power_limits) {
+ /* Check if card firmware support mailbox power limits commands. */
+ if (xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, CHANNEL_CARD,
+ &hwmon->pl1_on_boot[CHANNEL_CARD]) |
+ xe_hwmon_pcode_read_power_limit(hwmon, PL1_HWMON_ATTR, CHANNEL_PKG,
+ &hwmon->pl1_on_boot[CHANNEL_PKG])) {
+ drm_warn(&hwmon->xe->drm,
+ "Failed to read power limits, check card firmware !\n");
+ } else {
+ drm_info(&hwmon->xe->drm, "Using mailbox commands for power limits\n");
+ /* Write default limits to read from pcode from now on. */
+ xe_hwmon_pcode_write_power_limit(hwmon, PL1_HWMON_ATTR,
+ CHANNEL_CARD,
+ hwmon->pl1_on_boot[CHANNEL_CARD]);
+ xe_hwmon_pcode_write_power_limit(hwmon, PL1_HWMON_ATTR,
+ CHANNEL_PKG,
+ hwmon->pl1_on_boot[CHANNEL_PKG]);
+ hwmon->scl_shift_power = PWR_UNIT;
+ hwmon->scl_shift_energy = ENERGY_UNIT;
+ hwmon->scl_shift_time = TIME_UNIT;
+ hwmon->boot_power_limit_read = true;
+ }
+ } else {
+ drm_info(&hwmon->xe->drm, "Using register for power limits\n");
+ /*
+ * The contents of register PKG_POWER_SKU_UNIT do not change,
+ * so read it once and store the shift values.
+ */
+ pkg_power_sku_unit = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU_UNIT, 0);
+ if (xe_reg_is_valid(pkg_power_sku_unit)) {
+ val_sku_unit = xe_mmio_read32(mmio, pkg_power_sku_unit);
+ hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
+ hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
+ hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
+ }
}
-
/*
* Initialize 'struct xe_hwmon_energy_info', i.e. set fields to the
* first value of the energy register read
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 61a2e87990a9..63d74e27f54c 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -909,10 +909,7 @@ static void xe_lrc_set_ppgtt(struct xe_lrc *lrc, struct xe_vm *vm)
static void xe_lrc_finish(struct xe_lrc *lrc)
{
xe_hw_fence_ctx_finish(&lrc->fence_ctx);
- xe_bo_lock(lrc->bo, false);
- xe_bo_unpin(lrc->bo);
- xe_bo_unlock(lrc->bo);
- xe_bo_put(lrc->bo);
+ xe_bo_unpin_map_no_vm(lrc->bo);
xe_bo_unpin_map_no_vm(lrc->bb_per_ctx_bo);
}
@@ -1007,7 +1004,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
* FIXME: Perma-pinning LRC as we don't yet support moving GGTT address
* via VM bind calls.
*/
- lrc->bo = xe_bo_create_pin_map(xe, tile, vm, lrc_size,
+ lrc->bo = xe_bo_create_pin_map(xe, tile, NULL, lrc_size,
ttm_bo_type_kernel,
bo_flags);
if (IS_ERR(lrc->bo))
@@ -1795,9 +1792,6 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc)
if (!snapshot)
return NULL;
- if (lrc->bo->vm)
- xe_vm_get(lrc->bo->vm);
-
snapshot->context_desc = xe_lrc_ggtt_addr(lrc);
snapshot->ring_addr = __xe_lrc_ring_ggtt_addr(lrc);
snapshot->indirect_context_desc = xe_lrc_indirect_ring_ggtt_addr(lrc);
@@ -1819,14 +1813,12 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc)
void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot)
{
struct xe_bo *bo;
- struct xe_vm *vm;
struct iosys_map src;
if (!snapshot)
return;
bo = snapshot->lrc_bo;
- vm = bo->vm;
snapshot->lrc_bo = NULL;
snapshot->lrc_snapshot = kvmalloc(snapshot->lrc_size, GFP_KERNEL);
@@ -1846,8 +1838,6 @@ void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot)
xe_bo_unlock(bo);
put_bo:
xe_bo_put(bo);
- if (vm)
- xe_vm_put(vm);
}
void xe_lrc_snapshot_print(struct xe_lrc_snapshot *snapshot, struct drm_printer *p)
@@ -1900,14 +1890,9 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot)
return;
kvfree(snapshot->lrc_snapshot);
- if (snapshot->lrc_bo) {
- struct xe_vm *vm;
-
- vm = snapshot->lrc_bo->vm;
+ if (snapshot->lrc_bo)
xe_bo_put(snapshot->lrc_bo);
- if (vm)
- xe_vm_put(vm);
- }
+
kfree(snapshot);
}
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 024175cfe61e..ac4beaed58ff 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -66,6 +66,7 @@ struct xe_device_desc {
u8 has_heci_gscfi:1;
u8 has_heci_cscfi:1;
u8 has_llc:1;
+ u8 has_mbx_power_limits:1;
u8 has_pxp:1;
u8 has_sriov:1;
u8 needs_scratch:1;
@@ -306,6 +307,7 @@ static const struct xe_device_desc dg2_desc = {
DG2_FEATURES,
.has_display = true,
.has_fan_control = true,
+ .has_mbx_power_limits = false,
};
static const __maybe_unused struct xe_device_desc pvc_desc = {
@@ -317,6 +319,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = {
.has_heci_gscfi = 1,
.max_remote_tiles = 1,
.require_force_probe = true,
+ .has_mbx_power_limits = false,
};
static const struct xe_device_desc mtl_desc = {
@@ -342,6 +345,7 @@ static const struct xe_device_desc bmg_desc = {
.dma_mask_size = 46,
.has_display = true,
.has_fan_control = true,
+ .has_mbx_power_limits = true,
.has_heci_cscfi = 1,
.needs_scratch = true,
};
@@ -584,6 +588,7 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.dma_mask_size = desc->dma_mask_size;
xe->info.is_dgfx = desc->is_dgfx;
xe->info.has_fan_control = desc->has_fan_control;
+ xe->info.has_mbx_power_limits = desc->has_mbx_power_limits;
xe->info.has_heci_gscfi = desc->has_heci_gscfi;
xe->info.has_heci_cscfi = desc->has_heci_cscfi;
xe->info.has_llc = desc->has_llc;
diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c
index cf955b3ed52c..9189117fe825 100644
--- a/drivers/gpu/drm/xe/xe_pcode.c
+++ b/drivers/gpu/drm/xe/xe_pcode.c
@@ -109,6 +109,17 @@ int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 data, int timeout
return err;
}
+int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, u32 data1, int timeout)
+{
+ int err;
+
+ mutex_lock(&tile->pcode.lock);
+ err = pcode_mailbox_rw(tile, mbox, &data0, &data1, timeout, false, false);
+ mutex_unlock(&tile->pcode.lock);
+
+ return err;
+}
+
int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val, u32 *val1)
{
int err;
diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h
index ba33991d72a7..de38f44f3201 100644
--- a/drivers/gpu/drm/xe/xe_pcode.h
+++ b/drivers/gpu/drm/xe/xe_pcode.h
@@ -18,6 +18,9 @@ int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq,
int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val, u32 *val1);
int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 val,
int timeout_ms);
+int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0,
+ u32 data1, int timeout);
+
#define xe_pcode_write(tile, mbox, val) \
xe_pcode_write_timeout(tile, mbox, val, 1)
diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
index 127d4d26c4cf..0befdea77db1 100644
--- a/drivers/gpu/drm/xe/xe_pcode_api.h
+++ b/drivers/gpu/drm/xe/xe_pcode_api.h
@@ -43,6 +43,13 @@
#define POWER_SETUP_I1_SHIFT 6 /* 10.6 fixed point format */
#define POWER_SETUP_I1_DATA_MASK REG_GENMASK(15, 0)
+#define READ_PSYSGPU_POWER_LIMIT 0x6
+#define WRITE_PSYSGPU_POWER_LIMIT 0x7
+#define READ_PACKAGE_POWER_LIMIT 0x8
+#define WRITE_PACKAGE_POWER_LIMIT 0x9
+#define READ_PL_FROM_FW 0x1
+#define READ_PL_FROM_PCODE 0x0
+
#define PCODE_FREQUENCY_CONFIG 0x6e
/* Frequency Config Sub Commands (param1) */
#define PCODE_MBOX_FC_SC_READ_FUSED_P0 0x0
diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c
index 454ea7dc08ac..b5bc15f436fa 100644
--- a/drivers/gpu/drm/xe/xe_pxp.c
+++ b/drivers/gpu/drm/xe/xe_pxp.c
@@ -541,10 +541,14 @@ int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q)
*/
xe_pm_runtime_get(pxp->xe);
- if (!pxp_prerequisites_done(pxp)) {
- ret = -EBUSY;
+ /* get_readiness_status() returns 0 for in-progress and 1 for done */
+ ret = xe_pxp_get_readiness_status(pxp);
+ if (ret <= 0) {
+ if (!ret)
+ ret = -EBUSY;
goto out;
}
+ ret = 0;
wait_for_idle:
/*
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 79323c78130f..861577746929 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -1678,13 +1678,21 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
* scheduler drops all the references of it, hence protecting the VM
* for this case is necessary.
*/
- if (flags & XE_VM_FLAG_LR_MODE)
+ if (flags & XE_VM_FLAG_LR_MODE) {
+ INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func);
xe_pm_runtime_get_noresume(xe);
+ }
+
+ if (flags & XE_VM_FLAG_FAULT_MODE) {
+ err = xe_svm_init(vm);
+ if (err)
+ goto err_no_resv;
+ }
vm_resv_obj = drm_gpuvm_resv_object_alloc(&xe->drm);
if (!vm_resv_obj) {
err = -ENOMEM;
- goto err_no_resv;
+ goto err_svm_fini;
}
drm_gpuvm_init(&vm->gpuvm, "Xe VM", DRM_GPUVM_RESV_PROTECTED, &xe->drm,
@@ -1724,10 +1732,8 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
vm->batch_invalidate_tlb = true;
}
- if (vm->flags & XE_VM_FLAG_LR_MODE) {
- INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func);
+ if (vm->flags & XE_VM_FLAG_LR_MODE)
vm->batch_invalidate_tlb = false;
- }
/* Fill pt_root after allocating scratch tables */
for_each_tile(tile, xe, id) {
@@ -1757,12 +1763,6 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
}
}
- if (flags & XE_VM_FLAG_FAULT_MODE) {
- err = xe_svm_init(vm);
- if (err)
- goto err_close;
- }
-
if (number_tiles > 1)
vm->composite_fence_ctx = dma_fence_context_alloc(1);
@@ -1776,6 +1776,11 @@ err_close:
xe_vm_close_and_put(vm);
return ERR_PTR(err);
+err_svm_fini:
+ if (flags & XE_VM_FLAG_FAULT_MODE) {
+ vm->size = 0; /* close the vm */
+ xe_svm_fini(vm);
+ }
err_no_resv:
mutex_destroy(&vm->snap_mutex);
for_each_tile(tile, xe, id)
diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
index 0ef811fc2bde..494af6bdc646 100644
--- a/drivers/gpu/drm/xe/xe_vm.h
+++ b/drivers/gpu/drm/xe/xe_vm.h
@@ -301,6 +301,75 @@ void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap);
void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p);
void xe_vm_snapshot_free(struct xe_vm_snapshot *snap);
+/**
+ * xe_vm_set_validating() - Register this task as currently making bos resident
+ * @allow_res_evict: Allow eviction of buffer objects bound to @vm when
+ * validating.
+ * @vm: Pointer to the vm or NULL.
+ *
+ * Register this task as currently making bos resident for the vm. Intended
+ * to avoid eviction by the same task of shared bos bound to the vm.
+ * Call with the vm's resv lock held.
+ *
+ * Return: A pin cookie that should be used for xe_vm_clear_validating().
+ */
+static inline struct pin_cookie xe_vm_set_validating(struct xe_vm *vm,
+ bool allow_res_evict)
+{
+ struct pin_cookie cookie = {};
+
+ if (vm && !allow_res_evict) {
+ xe_vm_assert_held(vm);
+ cookie = lockdep_pin_lock(&xe_vm_resv(vm)->lock.base);
+ /* Pairs with READ_ONCE in xe_vm_is_validating() */
+ WRITE_ONCE(vm->validating, current);
+ }
+
+ return cookie;
+}
+
+/**
+ * xe_vm_clear_validating() - Unregister this task as currently making bos resident
+ * @vm: Pointer to the vm or NULL
+ * @allow_res_evict: Eviction from @vm was allowed. Must be set to the same
+ * value as for xe_vm_set_validation().
+ * @cookie: Cookie obtained from xe_vm_set_validating().
+ *
+ * Register this task as currently making bos resident for the vm. Intended
+ * to avoid eviction by the same task of shared bos bound to the vm.
+ * Call with the vm's resv lock held.
+ */
+static inline void xe_vm_clear_validating(struct xe_vm *vm, bool allow_res_evict,
+ struct pin_cookie cookie)
+{
+ if (vm && !allow_res_evict) {
+ lockdep_unpin_lock(&xe_vm_resv(vm)->lock.base, cookie);
+ /* Pairs with READ_ONCE in xe_vm_is_validating() */
+ WRITE_ONCE(vm->validating, NULL);
+ }
+}
+
+/**
+ * xe_vm_is_validating() - Whether bos bound to the vm are currently being made resident
+ * by the current task.
+ * @vm: Pointer to the vm.
+ *
+ * If this function returns %true, we should be in a vm resv locked region, since
+ * the current process is the same task that called xe_vm_set_validating().
+ * The function asserts that that's indeed the case.
+ *
+ * Return: %true if the task is currently making bos resident, %false otherwise.
+ */
+static inline bool xe_vm_is_validating(struct xe_vm *vm)
+{
+ /* Pairs with WRITE_ONCE in xe_vm_is_validating() */
+ if (READ_ONCE(vm->validating) == current) {
+ xe_vm_assert_held(vm);
+ return true;
+ }
+ return false;
+}
+
#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma);
#else
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 1662604c4486..1979e9bdbdf3 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -310,6 +310,14 @@ struct xe_vm {
* protected by the vm resv.
*/
u64 tlb_flush_seqno;
+ /**
+ * @validating: The task that is currently making bos resident for this vm.
+ * Protected by the VM's resv for writing. Opportunistic reading can be done
+ * using READ_ONCE. Note: This is a workaround for the
+ * TTM eviction_valuable() callback not being passed a struct
+ * ttm_operation_context(). Future work might want to address this.
+ */
+ struct task_struct *validating;
/** @batch_invalidate_tlb: Always invalidate TLB before batch start */
bool batch_invalidate_tlb;
/** @xef: XE file handle for tracking this VM's drm client */
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 1b1d64493909..079620dd4286 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1905,16 +1905,6 @@ config SENSORS_SBTSI
This driver can also be built as a module. If so, the module will
be called sbtsi_temp.
-config SENSORS_SBRMI
- tristate "Emulated SB-RMI sensor"
- depends on I2C
- help
- If you say yes here you get support for emulated RMI
- sensors on AMD SoCs with APML interface connected to a BMC device.
-
- This driver can also be built as a module. If so, the module will
- be called sbrmi.
-
config SENSORS_SHT15
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
depends on GPIOLIB || COMPILE_TEST
diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c
deleted file mode 100644
index d48d8e5460ff..000000000000
--- a/drivers/hwmon/sbrmi.c
+++ /dev/null
@@ -1,357 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * sbrmi.c - hwmon driver for a SB-RMI mailbox
- * compliant AMD SoC device.
- *
- * Copyright (C) 2020-2021 Advanced Micro Devices, Inc.
- */
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/hwmon.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-
-/* Do not allow setting negative power limit */
-#define SBRMI_PWR_MIN 0
-/* Mask for Status Register bit[1] */
-#define SW_ALERT_MASK 0x2
-
-/* Software Interrupt for triggering */
-#define START_CMD 0x80
-#define TRIGGER_MAILBOX 0x01
-
-/*
- * SB-RMI supports soft mailbox service request to MP1 (power management
- * firmware) through SBRMI inbound/outbound message registers.
- * SB-RMI message IDs
- */
-enum sbrmi_msg_id {
- SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1,
- SBRMI_WRITE_PKG_PWR_LIMIT,
- SBRMI_READ_PKG_PWR_LIMIT,
- SBRMI_READ_PKG_MAX_PWR_LIMIT,
-};
-
-/* SB-RMI registers */
-enum sbrmi_reg {
- SBRMI_CTRL = 0x01,
- SBRMI_STATUS,
- SBRMI_OUTBNDMSG0 = 0x30,
- SBRMI_OUTBNDMSG1,
- SBRMI_OUTBNDMSG2,
- SBRMI_OUTBNDMSG3,
- SBRMI_OUTBNDMSG4,
- SBRMI_OUTBNDMSG5,
- SBRMI_OUTBNDMSG6,
- SBRMI_OUTBNDMSG7,
- SBRMI_INBNDMSG0,
- SBRMI_INBNDMSG1,
- SBRMI_INBNDMSG2,
- SBRMI_INBNDMSG3,
- SBRMI_INBNDMSG4,
- SBRMI_INBNDMSG5,
- SBRMI_INBNDMSG6,
- SBRMI_INBNDMSG7,
- SBRMI_SW_INTERRUPT,
-};
-
-/* Each client has this additional data */
-struct sbrmi_data {
- struct i2c_client *client;
- struct mutex lock;
- u32 pwr_limit_max;
-};
-
-struct sbrmi_mailbox_msg {
- u8 cmd;
- bool read;
- u32 data_in;
- u32 data_out;
-};
-
-static int sbrmi_enable_alert(struct i2c_client *client)
-{
- int ctrl;
-
- /*
- * Enable the SB-RMI Software alert status
- * by writing 0 to bit 4 of Control register(0x1)
- */
- ctrl = i2c_smbus_read_byte_data(client, SBRMI_CTRL);
- if (ctrl < 0)
- return ctrl;
-
- if (ctrl & 0x10) {
- ctrl &= ~0x10;
- return i2c_smbus_write_byte_data(client,
- SBRMI_CTRL, ctrl);
- }
-
- return 0;
-}
-
-static int rmi_mailbox_xfer(struct sbrmi_data *data,
- struct sbrmi_mailbox_msg *msg)
-{
- int i, ret, retry = 10;
- int sw_status;
- u8 byte;
-
- mutex_lock(&data->lock);
-
- /* Indicate firmware a command is to be serviced */
- ret = i2c_smbus_write_byte_data(data->client,
- SBRMI_INBNDMSG7, START_CMD);
- if (ret < 0)
- goto exit_unlock;
-
- /* Write the command to SBRMI::InBndMsg_inst0 */
- ret = i2c_smbus_write_byte_data(data->client,
- SBRMI_INBNDMSG0, msg->cmd);
- if (ret < 0)
- goto exit_unlock;
-
- /*
- * For both read and write the initiator (BMC) writes
- * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
- * SBRMI_x3C(MSB):SBRMI_x39(LSB)
- */
- for (i = 0; i < 4; i++) {
- byte = (msg->data_in >> i * 8) & 0xff;
- ret = i2c_smbus_write_byte_data(data->client,
- SBRMI_INBNDMSG1 + i, byte);
- if (ret < 0)
- goto exit_unlock;
- }
-
- /*
- * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
- * perform the requested read or write command
- */
- ret = i2c_smbus_write_byte_data(data->client,
- SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
- if (ret < 0)
- goto exit_unlock;
-
- /*
- * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
- * an ALERT (if enabled) to initiator (BMC) to indicate completion
- * of the requested command
- */
- do {
- sw_status = i2c_smbus_read_byte_data(data->client,
- SBRMI_STATUS);
- if (sw_status < 0) {
- ret = sw_status;
- goto exit_unlock;
- }
- if (sw_status & SW_ALERT_MASK)
- break;
- usleep_range(50, 100);
- } while (retry--);
-
- if (retry < 0) {
- dev_err(&data->client->dev,
- "Firmware fail to indicate command completion\n");
- ret = -EIO;
- goto exit_unlock;
- }
-
- /*
- * For a read operation, the initiator (BMC) reads the firmware
- * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
- * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
- */
- if (msg->read) {
- for (i = 0; i < 4; i++) {
- ret = i2c_smbus_read_byte_data(data->client,
- SBRMI_OUTBNDMSG1 + i);
- if (ret < 0)
- goto exit_unlock;
- msg->data_out |= ret << i * 8;
- }
- }
-
- /*
- * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
- * ALERT to initiator
- */
- ret = i2c_smbus_write_byte_data(data->client, SBRMI_STATUS,
- sw_status | SW_ALERT_MASK);
-
-exit_unlock:
- mutex_unlock(&data->lock);
- return ret;
-}
-
-static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long *val)
-{
- struct sbrmi_data *data = dev_get_drvdata(dev);
- struct sbrmi_mailbox_msg msg = { 0 };
- int ret;
-
- if (type != hwmon_power)
- return -EINVAL;
-
- msg.read = true;
- switch (attr) {
- case hwmon_power_input:
- msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
- ret = rmi_mailbox_xfer(data, &msg);
- break;
- case hwmon_power_cap:
- msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
- ret = rmi_mailbox_xfer(data, &msg);
- break;
- case hwmon_power_cap_max:
- msg.data_out = data->pwr_limit_max;
- ret = 0;
- break;
- default:
- return -EINVAL;
- }
- if (ret < 0)
- return ret;
- /* hwmon power attributes are in microWatt */
- *val = (long)msg.data_out * 1000;
- return ret;
-}
-
-static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
- u32 attr, int channel, long val)
-{
- struct sbrmi_data *data = dev_get_drvdata(dev);
- struct sbrmi_mailbox_msg msg = { 0 };
-
- if (type != hwmon_power && attr != hwmon_power_cap)
- return -EINVAL;
- /*
- * hwmon power attributes are in microWatt
- * mailbox read/write is in mWatt
- */
- val /= 1000;
-
- val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);
-
- msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
- msg.data_in = val;
- msg.read = false;
-
- return rmi_mailbox_xfer(data, &msg);
-}
-
-static umode_t sbrmi_is_visible(const void *data,
- enum hwmon_sensor_types type,
- u32 attr, int channel)
-{
- switch (type) {
- case hwmon_power:
- switch (attr) {
- case hwmon_power_input:
- case hwmon_power_cap_max:
- return 0444;
- case hwmon_power_cap:
- return 0644;
- }
- break;
- default:
- break;
- }
- return 0;
-}
-
-static const struct hwmon_channel_info * const sbrmi_info[] = {
- HWMON_CHANNEL_INFO(power,
- HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
- NULL
-};
-
-static const struct hwmon_ops sbrmi_hwmon_ops = {
- .is_visible = sbrmi_is_visible,
- .read = sbrmi_read,
- .write = sbrmi_write,
-};
-
-static const struct hwmon_chip_info sbrmi_chip_info = {
- .ops = &sbrmi_hwmon_ops,
- .info = sbrmi_info,
-};
-
-static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
-{
- struct sbrmi_mailbox_msg msg = { 0 };
- int ret;
-
- msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT;
- msg.read = true;
- ret = rmi_mailbox_xfer(data, &msg);
- if (ret < 0)
- return ret;
- data->pwr_limit_max = msg.data_out;
-
- return ret;
-}
-
-static int sbrmi_probe(struct i2c_client *client)
-{
- struct device *dev = &client->dev;
- struct device *hwmon_dev;
- struct sbrmi_data *data;
- int ret;
-
- data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->client = client;
- mutex_init(&data->lock);
-
- /* Enable alert for SB-RMI sequence */
- ret = sbrmi_enable_alert(client);
- if (ret < 0)
- return ret;
-
- /* Cache maximum power limit */
- ret = sbrmi_get_max_pwr_limit(data);
- if (ret < 0)
- return ret;
-
- hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
- &sbrmi_chip_info, NULL);
-
- return PTR_ERR_OR_ZERO(hwmon_dev);
-}
-
-static const struct i2c_device_id sbrmi_id[] = {
- {"sbrmi"},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, sbrmi_id);
-
-static const struct of_device_id __maybe_unused sbrmi_of_match[] = {
- {
- .compatible = "amd,sbrmi",
- },
- { },
-};
-MODULE_DEVICE_TABLE(of, sbrmi_of_match);
-
-static struct i2c_driver sbrmi_driver = {
- .driver = {
- .name = "sbrmi",
- .of_match_table = of_match_ptr(sbrmi_of_match),
- },
- .probe = sbrmi_probe,
- .id_table = sbrmi_id,
-};
-
-module_i2c_driver(sbrmi_driver);
-
-MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
-MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig
index ecd7086a5b83..f064e3d172b3 100644
--- a/drivers/hwtracing/coresight/Kconfig
+++ b/drivers/hwtracing/coresight/Kconfig
@@ -259,4 +259,13 @@ config CORESIGHT_DUMMY
To compile this driver as a module, choose M here: the module will be
called coresight-dummy.
+
+config CORESIGHT_KUNIT_TESTS
+ tristate "Enable Coresight unit tests"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Enable Coresight unit tests. Only useful for development and not
+ intended for production.
+
endif
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 8e62c3150aeb..4e7cc3c5bf99 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -22,6 +22,8 @@ condflags := \
$(call cc-option, -Wstringop-truncation)
subdir-ccflags-y += $(condflags)
+CFLAGS_coresight-stm.o := -D__DISABLE_TRACE_MMIO__
+
obj-$(CONFIG_CORESIGHT) += coresight.o
coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \
coresight-sysfs.o coresight-syscfg.o coresight-config.o \
@@ -53,3 +55,4 @@ obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb.o
obj-$(CONFIG_CORESIGHT_DUMMY) += coresight-dummy.o
obj-$(CONFIG_CORESIGHT_CTCU) += coresight-ctcu.o
coresight-ctcu-y := coresight-ctcu-core.o
+obj-$(CONFIG_CORESIGHT_KUNIT_TESTS) += coresight-kunit-tests.o
diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c
index fa170c966bc3..5058432233da 100644
--- a/drivers/hwtracing/coresight/coresight-catu.c
+++ b/drivers/hwtracing/coresight/coresight-catu.c
@@ -113,9 +113,8 @@ typedef u64 cate_t;
* containing the data page pointer for @offset. If @daddrp is not NULL,
* @daddrp points the DMA address of the beginning of the table.
*/
-static inline cate_t *catu_get_table(struct tmc_sg_table *catu_table,
- unsigned long offset,
- dma_addr_t *daddrp)
+static cate_t *catu_get_table(struct tmc_sg_table *catu_table, unsigned long offset,
+ dma_addr_t *daddrp)
{
unsigned long buf_size = tmc_sg_table_buf_size(catu_table);
unsigned int table_nr, pg_idx, pg_offset;
@@ -165,12 +164,12 @@ static void catu_dump_table(struct tmc_sg_table *catu_table)
}
#else
-static inline void catu_dump_table(struct tmc_sg_table *catu_table)
+static void catu_dump_table(struct tmc_sg_table *catu_table)
{
}
#endif
-static inline cate_t catu_make_entry(dma_addr_t addr)
+static cate_t catu_make_entry(dma_addr_t addr)
{
return addr ? CATU_VALID_ENTRY(addr) : 0;
}
@@ -390,7 +389,7 @@ static const struct attribute_group *catu_groups[] = {
};
-static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
+static int catu_wait_for_ready(struct catu_drvdata *drvdata)
{
struct csdev_access *csa = &drvdata->csdev->access;
@@ -458,12 +457,17 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *data)
{
- int rc;
+ int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
- CS_UNLOCK(catu_drvdata->base);
- rc = catu_enable_hw(catu_drvdata, mode, data);
- CS_LOCK(catu_drvdata->base);
+ guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock);
+ if (csdev->refcnt == 0) {
+ CS_UNLOCK(catu_drvdata->base);
+ rc = catu_enable_hw(catu_drvdata, mode, data);
+ CS_LOCK(catu_drvdata->base);
+ }
+ if (!rc)
+ csdev->refcnt++;
return rc;
}
@@ -486,12 +490,15 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
static int catu_disable(struct coresight_device *csdev, void *__unused)
{
- int rc;
+ int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
- CS_UNLOCK(catu_drvdata->base);
- rc = catu_disable_hw(catu_drvdata);
- CS_LOCK(catu_drvdata->base);
+ guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock);
+ if (--csdev->refcnt == 0) {
+ CS_UNLOCK(catu_drvdata->base);
+ rc = catu_disable_hw(catu_drvdata);
+ CS_LOCK(catu_drvdata->base);
+ }
return rc;
}
@@ -550,6 +557,7 @@ static int __catu_probe(struct device *dev, struct resource *res)
dev->platform_data = pdata;
drvdata->base = base;
+ raw_spin_lock_init(&drvdata->spinlock);
catu_desc.access = CSDEV_ACCESS_IOMEM(base);
catu_desc.pdata = pdata;
catu_desc.dev = dev;
@@ -558,6 +566,7 @@ static int __catu_probe(struct device *dev, struct resource *res)
catu_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU;
catu_desc.ops = &catu_ops;
+ coresight_clear_self_claim_tag(&catu_desc.access);
drvdata->csdev = coresight_register(&catu_desc);
if (IS_ERR(drvdata->csdev))
ret = PTR_ERR(drvdata->csdev);
@@ -702,7 +711,7 @@ static int __init catu_init(void)
{
int ret;
- ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver);
+ ret = coresight_init_driver("catu", &catu_driver, &catu_platform_driver, THIS_MODULE);
tmc_etr_set_catu_ops(&etr_catu_buf_ops);
return ret;
}
diff --git a/drivers/hwtracing/coresight/coresight-catu.h b/drivers/hwtracing/coresight/coresight-catu.h
index 141feac1c14b..755776cd19c5 100644
--- a/drivers/hwtracing/coresight/coresight-catu.h
+++ b/drivers/hwtracing/coresight/coresight-catu.h
@@ -65,6 +65,7 @@ struct catu_drvdata {
void __iomem *base;
struct coresight_device *csdev;
int irq;
+ raw_spinlock_t spinlock;
};
#define CATU_REG32(name, offset) \
diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h
index b9ebc9fcfb7f..90fd937d3bd8 100644
--- a/drivers/hwtracing/coresight/coresight-config.h
+++ b/drivers/hwtracing/coresight/coresight-config.h
@@ -228,7 +228,7 @@ struct cscfg_feature_csdev {
* @feats_csdev:references to the device features to enable.
*/
struct cscfg_config_csdev {
- const struct cscfg_config_desc *config_desc;
+ struct cscfg_config_desc *config_desc;
struct coresight_device *csdev;
bool enabled;
struct list_head node;
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index fb43ef6a3b1f..fa758cc21827 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -129,34 +129,36 @@ coresight_find_out_connection(struct coresight_device *csdev,
return ERR_PTR(-ENODEV);
}
-static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
+static u32 coresight_read_claim_tags_unlocked(struct coresight_device *csdev)
{
- return csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR);
+ return FIELD_GET(CORESIGHT_CLAIM_MASK,
+ csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR));
}
-static inline bool coresight_is_claimed_self_hosted(struct coresight_device *csdev)
-{
- return coresight_read_claim_tags(csdev) == CORESIGHT_CLAIM_SELF_HOSTED;
-}
-
-static inline bool coresight_is_claimed_any(struct coresight_device *csdev)
-{
- return coresight_read_claim_tags(csdev) != 0;
-}
-
-static inline void coresight_set_claim_tags(struct coresight_device *csdev)
+static void coresight_set_self_claim_tag_unlocked(struct coresight_device *csdev)
{
csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
CORESIGHT_CLAIMSET);
isb();
}
-static inline void coresight_clear_claim_tags(struct coresight_device *csdev)
+void coresight_clear_self_claim_tag(struct csdev_access *csa)
{
- csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
+ if (csa->io_mem)
+ CS_UNLOCK(csa->base);
+ coresight_clear_self_claim_tag_unlocked(csa);
+ if (csa->io_mem)
+ CS_LOCK(csa->base);
+}
+EXPORT_SYMBOL_GPL(coresight_clear_self_claim_tag);
+
+void coresight_clear_self_claim_tag_unlocked(struct csdev_access *csa)
+{
+ csdev_access_relaxed_write32(csa, CORESIGHT_CLAIM_SELF_HOSTED,
CORESIGHT_CLAIMCLR);
isb();
}
+EXPORT_SYMBOL_GPL(coresight_clear_self_claim_tag_unlocked);
/*
* coresight_claim_device_unlocked : Claim the device for self-hosted usage
@@ -170,18 +172,41 @@ static inline void coresight_clear_claim_tags(struct coresight_device *csdev)
*/
int coresight_claim_device_unlocked(struct coresight_device *csdev)
{
+ int tag;
+ struct csdev_access *csa;
+
if (WARN_ON(!csdev))
return -EINVAL;
- if (coresight_is_claimed_any(csdev))
+ csa = &csdev->access;
+ tag = coresight_read_claim_tags_unlocked(csdev);
+
+ switch (tag) {
+ case CORESIGHT_CLAIM_FREE:
+ coresight_set_self_claim_tag_unlocked(csdev);
+ if (coresight_read_claim_tags_unlocked(csdev) == CORESIGHT_CLAIM_SELF_HOSTED)
+ return 0;
+
+ /* There was a race setting the tag, clean up and fail */
+ coresight_clear_self_claim_tag_unlocked(csa);
+ dev_dbg(&csdev->dev, "Busy: Couldn't set self claim tag");
return -EBUSY;
- coresight_set_claim_tags(csdev);
- if (coresight_is_claimed_self_hosted(csdev))
- return 0;
- /* There was a race setting the tags, clean up and fail */
- coresight_clear_claim_tags(csdev);
- return -EBUSY;
+ case CORESIGHT_CLAIM_EXTERNAL:
+ /* External debug is an expected state, so log and report BUSY */
+ dev_dbg(&csdev->dev, "Busy: Claimed by external debugger");
+ return -EBUSY;
+
+ default:
+ case CORESIGHT_CLAIM_SELF_HOSTED:
+ case CORESIGHT_CLAIM_INVALID:
+ /*
+ * Warn here because we clear a lingering self hosted tag
+ * on probe, so other tag combinations are impossible.
+ */
+ dev_err_once(&csdev->dev, "Invalid claim tag state: %x", tag);
+ return -EBUSY;
+ }
}
EXPORT_SYMBOL_GPL(coresight_claim_device_unlocked);
@@ -201,7 +226,7 @@ int coresight_claim_device(struct coresight_device *csdev)
EXPORT_SYMBOL_GPL(coresight_claim_device);
/*
- * coresight_disclaim_device_unlocked : Clear the claim tags for the device.
+ * coresight_disclaim_device_unlocked : Clear the claim tag for the device.
* Called with CS_UNLOCKed for the component.
*/
void coresight_disclaim_device_unlocked(struct coresight_device *csdev)
@@ -210,15 +235,15 @@ void coresight_disclaim_device_unlocked(struct coresight_device *csdev)
if (WARN_ON(!csdev))
return;
- if (coresight_is_claimed_self_hosted(csdev))
- coresight_clear_claim_tags(csdev);
+ if (coresight_read_claim_tags_unlocked(csdev) == CORESIGHT_CLAIM_SELF_HOSTED)
+ coresight_clear_self_claim_tag_unlocked(&csdev->access);
else
/*
* The external agent may have not honoured our claim
* and has manipulated it. Or something else has seriously
* gone wrong in our driver.
*/
- WARN_ON_ONCE(1);
+ dev_WARN_ONCE(&csdev->dev, 1, "External agent took claim tag");
}
EXPORT_SYMBOL_GPL(coresight_disclaim_device_unlocked);
@@ -367,6 +392,28 @@ void coresight_disable_source(struct coresight_device *csdev, void *data)
}
EXPORT_SYMBOL_GPL(coresight_disable_source);
+void coresight_pause_source(struct coresight_device *csdev)
+{
+ if (!coresight_is_percpu_source(csdev))
+ return;
+
+ if (source_ops(csdev)->pause_perf)
+ source_ops(csdev)->pause_perf(csdev);
+}
+EXPORT_SYMBOL_GPL(coresight_pause_source);
+
+int coresight_resume_source(struct coresight_device *csdev)
+{
+ if (!coresight_is_percpu_source(csdev))
+ return -EOPNOTSUPP;
+
+ if (!source_ops(csdev)->resume_perf)
+ return -EOPNOTSUPP;
+
+ return source_ops(csdev)->resume_perf(csdev);
+}
+EXPORT_SYMBOL_GPL(coresight_resume_source);
+
/*
* coresight_disable_path_from : Disable components in the given path beyond
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
@@ -465,7 +512,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
/* Enable all helpers adjacent to the path first */
ret = coresight_enable_helpers(csdev, mode, path);
if (ret)
- goto err;
+ goto err_disable_path;
/*
* ETF devices are tricky... They can be a link or a sink,
* depending on how they are configured. If an ETF has been
@@ -486,8 +533,10 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
* that need disabling. Disabling the path here
* would mean we could disrupt an existing session.
*/
- if (ret)
+ if (ret) {
+ coresight_disable_helpers(csdev, path);
goto out;
+ }
break;
case CORESIGHT_DEV_TYPE_SOURCE:
/* sources are enabled from either sysFS or Perf */
@@ -497,16 +546,19 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
child = list_next_entry(nd, link)->csdev;
ret = coresight_enable_link(csdev, parent, child, source);
if (ret)
- goto err;
+ goto err_disable_helpers;
break;
default:
- goto err;
+ ret = -EINVAL;
+ goto err_disable_helpers;
}
}
out:
return ret;
-err:
+err_disable_helpers:
+ coresight_disable_helpers(csdev, path);
+err_disable_path:
coresight_disable_path_from(path, nd);
goto out;
}
@@ -579,7 +631,7 @@ struct coresight_device *coresight_get_sink_by_id(u32 id)
* Return true in successful case and power up the device.
* Return false when failed to get reference of module.
*/
-static inline bool coresight_get_ref(struct coresight_device *csdev)
+static bool coresight_get_ref(struct coresight_device *csdev)
{
struct device *dev = csdev->dev.parent;
@@ -598,7 +650,7 @@ static inline bool coresight_get_ref(struct coresight_device *csdev)
*
* @csdev: The coresight device to decrement a reference from.
*/
-static inline void coresight_put_ref(struct coresight_device *csdev)
+static void coresight_put_ref(struct coresight_device *csdev)
{
struct device *dev = csdev->dev.parent;
@@ -821,7 +873,7 @@ void coresight_release_path(struct coresight_path *path)
}
/* return true if the device is a suitable type for a default sink */
-static inline bool coresight_is_def_sink_type(struct coresight_device *csdev)
+static bool coresight_is_def_sink_type(struct coresight_device *csdev)
{
/* sink & correct subtype */
if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
@@ -959,6 +1011,7 @@ coresight_find_default_sink(struct coresight_device *csdev)
}
return csdev->def_sink;
}
+EXPORT_SYMBOL_GPL(coresight_find_default_sink);
static int coresight_remove_sink_ref(struct device *dev, void *data)
{
@@ -1385,8 +1438,8 @@ EXPORT_SYMBOL_GPL(coresight_unregister);
*
* Returns the index of the entry, when found. Otherwise, -ENOENT.
*/
-static inline int coresight_search_device_idx(struct coresight_dev_list *dict,
- struct fwnode_handle *fwnode)
+static int coresight_search_device_idx(struct coresight_dev_list *dict,
+ struct fwnode_handle *fwnode)
{
int i;
@@ -1585,17 +1638,17 @@ module_init(coresight_init);
module_exit(coresight_exit);
int coresight_init_driver(const char *drv, struct amba_driver *amba_drv,
- struct platform_driver *pdev_drv)
+ struct platform_driver *pdev_drv, struct module *owner)
{
int ret;
- ret = amba_driver_register(amba_drv);
+ ret = __amba_driver_register(amba_drv, owner);
if (ret) {
pr_err("%s: error registering AMBA driver\n", drv);
return ret;
}
- ret = platform_driver_register(pdev_drv);
+ ret = __platform_driver_register(pdev_drv, owner);
if (!ret)
return 0;
diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c
index 342c3aaf414d..a871d997330b 100644
--- a/drivers/hwtracing/coresight/coresight-cpu-debug.c
+++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c
@@ -774,7 +774,8 @@ static struct platform_driver debug_platform_driver = {
static int __init debug_init(void)
{
- return coresight_init_driver("debug", &debug_driver, &debug_platform_driver);
+ return coresight_init_driver("debug", &debug_driver, &debug_platform_driver,
+ THIS_MODULE);
}
static void __exit debug_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-cti-core.c b/drivers/hwtracing/coresight/coresight-cti-core.c
index 80f6265e3740..8fb30dd73fd2 100644
--- a/drivers/hwtracing/coresight/coresight-cti-core.c
+++ b/drivers/hwtracing/coresight/coresight-cti-core.c
@@ -931,6 +931,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
cti_desc.ops = &cti_ops;
cti_desc.groups = drvdata->ctidev.con_groups;
cti_desc.dev = dev;
+
+ coresight_clear_self_claim_tag(&cti_desc.access);
drvdata->csdev = coresight_register(&cti_desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
diff --git a/drivers/hwtracing/coresight/coresight-cti.h b/drivers/hwtracing/coresight/coresight-cti.h
index 16e310e7e9d4..8362a47c939c 100644
--- a/drivers/hwtracing/coresight/coresight-cti.h
+++ b/drivers/hwtracing/coresight/coresight-cti.h
@@ -9,7 +9,6 @@
#include <linux/coresight.h>
#include <linux/device.h>
-#include <linux/fwnode.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
@@ -17,6 +16,8 @@
#include "coresight-priv.h"
+struct fwnode_handle;
+
/*
* Device registers
* 0x000 - 0x144: CTI programming and status
diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c
index 7948597d483d..d5efb085b30d 100644
--- a/drivers/hwtracing/coresight/coresight-etb10.c
+++ b/drivers/hwtracing/coresight/coresight-etb10.c
@@ -95,7 +95,7 @@ struct etb_drvdata {
static int etb_set_buffer(struct coresight_device *csdev,
struct perf_output_handle *handle);
-static inline unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
+static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
{
return readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG);
}
@@ -772,6 +772,8 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_etb_groups;
+
+ coresight_clear_self_claim_tag(&desc.access);
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index f4cccd68e625..f1551c08ecb2 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -366,6 +366,18 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
}
/*
+ * If AUX pause feature is enabled but the ETM driver does not
+ * support the operations, clear this CPU from the mask and
+ * continue to next one.
+ */
+ if (event->attr.aux_start_paused &&
+ (!source_ops(csdev)->pause_perf || !source_ops(csdev)->resume_perf)) {
+ dev_err_once(&csdev->dev, "AUX pause is not supported.\n");
+ cpumask_clear_cpu(cpu, mask);
+ continue;
+ }
+
+ /*
* No sink provided - look for a default sink for all the ETMs,
* where this event can be scheduled.
* We allocate the sink specific buffers only once for this
@@ -450,6 +462,15 @@ err:
goto out;
}
+static int etm_event_resume(struct coresight_device *csdev,
+ struct etm_ctxt *ctxt)
+{
+ if (!ctxt->event_data)
+ return 0;
+
+ return coresight_resume_source(csdev);
+}
+
static void etm_event_start(struct perf_event *event, int flags)
{
int cpu = smp_processor_id();
@@ -463,6 +484,14 @@ static void etm_event_start(struct perf_event *event, int flags)
if (!csdev)
goto fail;
+ if (flags & PERF_EF_RESUME) {
+ if (etm_event_resume(csdev, ctxt) < 0) {
+ dev_err(&csdev->dev, "Failed to resume ETM event.\n");
+ goto fail;
+ }
+ return;
+ }
+
/* Have we messed up our tracking ? */
if (WARN_ON(ctxt->event_data))
goto fail;
@@ -545,6 +574,55 @@ fail:
return;
}
+static void etm_event_pause(struct perf_event *event,
+ struct coresight_device *csdev,
+ struct etm_ctxt *ctxt)
+{
+ int cpu = smp_processor_id();
+ struct coresight_device *sink;
+ struct perf_output_handle *handle = &ctxt->handle;
+ struct coresight_path *path;
+ unsigned long size;
+
+ if (!ctxt->event_data)
+ return;
+
+ /* Stop tracer */
+ coresight_pause_source(csdev);
+
+ path = etm_event_cpu_path(ctxt->event_data, cpu);
+ sink = coresight_get_sink(path);
+ if (WARN_ON_ONCE(!sink))
+ return;
+
+ /*
+ * The per CPU sink has own interrupt handling, it might have
+ * race condition with updating buffer on AUX trace pause if
+ * it is invoked from NMI. To avoid the race condition,
+ * disallows updating buffer for the per CPU sink case.
+ */
+ if (coresight_is_percpu_sink(sink))
+ return;
+
+ if (WARN_ON_ONCE(handle->event != event))
+ return;
+
+ if (!sink_ops(sink)->update_buffer)
+ return;
+
+ size = sink_ops(sink)->update_buffer(sink, handle,
+ ctxt->event_data->snk_config);
+ if (READ_ONCE(handle->event)) {
+ if (!size)
+ return;
+
+ perf_aux_output_end(handle, size);
+ perf_aux_output_begin(handle, event);
+ } else {
+ WARN_ON_ONCE(size);
+ }
+}
+
static void etm_event_stop(struct perf_event *event, int mode)
{
int cpu = smp_processor_id();
@@ -555,6 +633,9 @@ static void etm_event_stop(struct perf_event *event, int mode)
struct etm_event_data *event_data;
struct coresight_path *path;
+ if (mode & PERF_EF_PAUSE)
+ return etm_event_pause(event, csdev, ctxt);
+
/*
* If we still have access to the event_data via handle,
* confirm that we haven't messed up the tracking.
@@ -899,7 +980,8 @@ int __init etm_perf_init(void)
int ret;
etm_pmu.capabilities = (PERF_PMU_CAP_EXCLUSIVE |
- PERF_PMU_CAP_ITRACE);
+ PERF_PMU_CAP_ITRACE |
+ PERF_PMU_CAP_AUX_PAUSE);
etm_pmu.attr_groups = etm_pmu_attr_groups;
etm_pmu.task_ctx_nr = perf_sw_context;
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 171f1384f7c0..1d753cca2943 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -229,7 +229,7 @@ struct etm_config {
* @config: structure holding configuration parameters.
*/
struct etm_drvdata {
- void __iomem *base;
+ struct csdev_access csa;
struct clk *atclk;
struct coresight_device *csdev;
spinlock_t spinlock;
@@ -260,7 +260,7 @@ static inline void etm_writel(struct etm_drvdata *drvdata,
"invalid CP14 access to ETM reg: %#x", off);
}
} else {
- writel_relaxed(val, drvdata->base + off);
+ writel_relaxed(val, drvdata->csa.base + off);
}
}
@@ -274,7 +274,7 @@ static inline unsigned int etm_readl(struct etm_drvdata *drvdata, u32 off)
"invalid CP14 access to ETM reg: %#x", off);
}
} else {
- val = readl_relaxed(drvdata->base + off);
+ val = readl_relaxed(drvdata->csa.base + off);
}
return val;
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index 8927bfaf3af2..1c6204e14422 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -86,9 +86,9 @@ static void etm_set_pwrup(struct etm_drvdata *drvdata)
{
u32 etmpdcr;
- etmpdcr = readl_relaxed(drvdata->base + ETMPDCR);
+ etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR);
etmpdcr |= ETMPDCR_PWD_UP;
- writel_relaxed(etmpdcr, drvdata->base + ETMPDCR);
+ writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR);
/* Ensure pwrup completes before subsequent cp14 accesses */
mb();
isb();
@@ -101,9 +101,9 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata)
/* Ensure pending cp14 accesses complete before clearing pwrup */
mb();
isb();
- etmpdcr = readl_relaxed(drvdata->base + ETMPDCR);
+ etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR);
etmpdcr &= ~ETMPDCR_PWD_UP;
- writel_relaxed(etmpdcr, drvdata->base + ETMPDCR);
+ writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR);
}
/**
@@ -365,7 +365,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
rc = coresight_claim_device_unlocked(csdev);
if (rc)
@@ -427,7 +427,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etm_clr_prog(drvdata);
done:
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n",
drvdata->cpu, rc);
@@ -549,7 +549,7 @@ static void etm_disable_hw(void *info)
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
etm_set_prog(drvdata);
/* Read back sequencer and counters for post trace analysis */
@@ -561,7 +561,7 @@ static void etm_disable_hw(void *info)
etm_set_pwrdwn(drvdata);
coresight_disclaim_device_unlocked(csdev);
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
dev_dbg(&drvdata->csdev->dev,
"cpu: %d disable smp call done\n", drvdata->cpu);
@@ -574,7 +574,7 @@ static void etm_disable_perf(struct coresight_device *csdev)
if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
return;
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
/* Setting the prog bit disables tracing immediately */
etm_set_prog(drvdata);
@@ -586,7 +586,7 @@ static void etm_disable_perf(struct coresight_device *csdev)
etm_set_pwrdwn(drvdata);
coresight_disclaim_device_unlocked(csdev);
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
/*
* perf will release trace ids when _free_aux()
@@ -733,7 +733,7 @@ static void etm_init_arch_data(void *info)
/* Make sure all registers are accessible */
etm_os_unlock(drvdata);
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
/* First dummy read */
(void)etm_readl(drvdata, ETMPDSR);
@@ -764,9 +764,10 @@ static void etm_init_arch_data(void *info)
drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+ coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
etm_set_pwrdwn(drvdata);
etm_clr_pwrup(drvdata);
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
}
static int __init etm_hp_setup(void)
@@ -827,8 +828,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
if (IS_ERR(base))
return PTR_ERR(base);
- drvdata->base = base;
- desc.access = CSDEV_ACCESS_IOMEM(base);
+ desc.access = drvdata->csa = CSDEV_ACCESS_IOMEM(base);
spin_lock_init(&drvdata->spinlock);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index b9006451f515..762109307b86 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -50,11 +50,11 @@ static ssize_t etmsr_show(struct device *dev,
pm_runtime_get_sync(dev->parent);
spin_lock_irqsave(&drvdata->spinlock, flags);
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
val = etm_readl(drvdata, ETMSR);
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
pm_runtime_put(dev->parent);
@@ -949,9 +949,9 @@ static ssize_t seq_curr_state_show(struct device *dev,
pm_runtime_get_sync(dev->parent);
spin_lock_irqsave(&drvdata->spinlock, flags);
- CS_UNLOCK(drvdata->base);
+ CS_UNLOCK(drvdata->csa.base);
val = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
- CS_LOCK(drvdata->base);
+ CS_LOCK(drvdata->csa.base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
pm_runtime_put(dev->parent);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 2b8f10463840..42e5d37403ad 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -84,7 +84,7 @@ static int etm4_probe_cpu(unsigned int cpu);
* TRCIDR4.NUMPC > 0b0000 .
* TRCSSCSR<n>.PC == 0b1
*/
-static inline bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
+static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
{
return (n < drvdata->nr_ss_cmp) &&
drvdata->nr_pe &&
@@ -185,7 +185,7 @@ static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
isb();
}
-static inline void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata,
+static void etm4_os_unlock_csa(struct etmv4_drvdata *drvdata,
struct csdev_access *csa)
{
WARN_ON(drvdata->cpu != smp_processor_id());
@@ -431,6 +431,44 @@ static int etm4x_wait_status(struct csdev_access *csa, int pos, int val)
return coresight_timeout(csa, TRCSTATR, pos, val);
}
+static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata)
+{
+ struct coresight_device *csdev = drvdata->csdev;
+ struct device *etm_dev = &csdev->dev;
+ struct csdev_access *csa = &csdev->access;
+
+ /*
+ * ETE mandates that the TRCRSR is written to before
+ * enabling it.
+ */
+ if (etm4x_is_ete(drvdata))
+ etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
+
+ etm4x_allow_trace(drvdata);
+ /* Enable the trace unit */
+ etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
+
+ /* Synchronize the register updates for sysreg access */
+ if (!csa->io_mem)
+ isb();
+
+ /* wait for TRCSTATR.IDLE to go back down to '0' */
+ if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0)) {
+ dev_err(etm_dev,
+ "timeout while waiting for Idle Trace Status\n");
+ return -ETIME;
+ }
+
+ /*
+ * As recommended by section 4.3.7 ("Synchronization when using the
+ * memory-mapped interface") of ARM IHI 0064D
+ */
+ dsb(sy);
+ isb();
+
+ return 0;
+}
+
static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
@@ -539,33 +577,8 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, trcpdcr | TRCPDCR_PU, TRCPDCR);
}
- /*
- * ETE mandates that the TRCRSR is written to before
- * enabling it.
- */
- if (etm4x_is_ete(drvdata))
- etm4x_relaxed_write32(csa, TRCRSR_TA, TRCRSR);
-
- etm4x_allow_trace(drvdata);
- /* Enable the trace unit */
- etm4x_relaxed_write32(csa, 1, TRCPRGCTLR);
-
- /* Synchronize the register updates for sysreg access */
- if (!csa->io_mem)
- isb();
-
- /* wait for TRCSTATR.IDLE to go back down to '0' */
- if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0))
- dev_err(etm_dev,
- "timeout while waiting for Idle Trace Status\n");
-
- /*
- * As recommended by section 4.3.7 ("Synchronization when using the
- * memory-mapped interface") of ARM IHI 0064D
- */
- dsb(sy);
- isb();
-
+ if (!drvdata->paused)
+ rc = etm4_enable_trace_unit(drvdata);
done:
etm4_cs_lock(drvdata, csa);
@@ -808,6 +821,9 @@ static int etm4_enable_perf(struct coresight_device *csdev,
drvdata->trcid = path->trace_id;
+ /* Populate pause state */
+ drvdata->paused = !!READ_ONCE(event->hw.aux_paused);
+
/* And enable it */
ret = etm4_enable_hw(drvdata);
@@ -834,6 +850,9 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
drvdata->trcid = path->trace_id;
+ /* Tracer will never be paused in sysfs mode */
+ drvdata->paused = false;
+
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
@@ -884,25 +903,12 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
return ret;
}
-static void etm4_disable_hw(void *info)
+static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata)
{
u32 control;
- struct etmv4_drvdata *drvdata = info;
- struct etmv4_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
struct device *etm_dev = &csdev->dev;
struct csdev_access *csa = &csdev->access;
- int i;
-
- etm4_cs_unlock(drvdata, csa);
- etm4_disable_arch_specific(drvdata);
-
- if (!drvdata->skip_power_up) {
- /* power can be removed from the trace unit now */
- control = etm4x_relaxed_read32(csa, TRCPDCR);
- control &= ~TRCPDCR_PU;
- etm4x_relaxed_write32(csa, control, TRCPDCR);
- }
control = etm4x_relaxed_read32(csa, TRCPRGCTLR);
@@ -943,6 +949,28 @@ static void etm4_disable_hw(void *info)
* of ARM IHI 0064H.b.
*/
isb();
+}
+
+static void etm4_disable_hw(void *info)
+{
+ u32 control;
+ struct etmv4_drvdata *drvdata = info;
+ struct etmv4_config *config = &drvdata->config;
+ struct coresight_device *csdev = drvdata->csdev;
+ struct csdev_access *csa = &csdev->access;
+ int i;
+
+ etm4_cs_unlock(drvdata, csa);
+ etm4_disable_arch_specific(drvdata);
+
+ if (!drvdata->skip_power_up) {
+ /* power can be removed from the trace unit now */
+ control = etm4x_relaxed_read32(csa, TRCPDCR);
+ control &= ~TRCPDCR_PU;
+ etm4x_relaxed_write32(csa, control, TRCPDCR);
+ }
+
+ etm4_disable_trace_unit(drvdata);
/* read the status of the single shot comparators */
for (i = 0; i < drvdata->nr_ss_cmp; i++) {
@@ -1020,6 +1048,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
raw_spin_unlock(&drvdata->spinlock);
+
+ cscfg_csdev_disable_active_config(csdev);
+
cpus_read_unlock();
/*
@@ -1059,10 +1090,43 @@ static void etm4_disable(struct coresight_device *csdev,
coresight_set_mode(csdev, CS_MODE_DISABLED);
}
+static int etm4_resume_perf(struct coresight_device *csdev)
+{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct csdev_access *csa = &csdev->access;
+
+ if (coresight_get_mode(csdev) != CS_MODE_PERF)
+ return -EINVAL;
+
+ etm4_cs_unlock(drvdata, csa);
+ etm4_enable_trace_unit(drvdata);
+ etm4_cs_lock(drvdata, csa);
+
+ drvdata->paused = false;
+ return 0;
+}
+
+static void etm4_pause_perf(struct coresight_device *csdev)
+{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct csdev_access *csa = &csdev->access;
+
+ if (coresight_get_mode(csdev) != CS_MODE_PERF)
+ return;
+
+ etm4_cs_unlock(drvdata, csa);
+ etm4_disable_trace_unit(drvdata);
+ etm4_cs_lock(drvdata, csa);
+
+ drvdata->paused = true;
+}
+
static const struct coresight_ops_source etm4_source_ops = {
.cpu_id = etm4_cpu_id,
.enable = etm4_enable,
.disable = etm4_disable,
+ .resume_perf = etm4_resume_perf,
+ .pause_perf = etm4_pause_perf,
};
static const struct coresight_ops etm4_cs_ops = {
@@ -1070,7 +1134,7 @@ static const struct coresight_ops etm4_cs_ops = {
.source_ops = &etm4_source_ops,
};
-static inline bool cpu_supports_sysreg_trace(void)
+static bool cpu_supports_sysreg_trace(void)
{
u64 dfr0 = read_sysreg_s(SYS_ID_AA64DFR0_EL1);
@@ -1176,7 +1240,7 @@ static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
* tracing at the kernel EL and EL0, forcing to use the
* virtual time as the timestamp.
*/
- trfcr = (TRFCR_EL1_TS_VIRTUAL |
+ trfcr = (FIELD_PREP(TRFCR_EL1_TS_MASK, TRFCR_EL1_TS_VIRTUAL) |
TRFCR_EL1_ExTRE |
TRFCR_EL1_E0TRE);
@@ -1372,11 +1436,13 @@ static void etm4_init_arch_data(void *info)
drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
/* NUMCNTR, bits[30:28] number of counters available for tracing */
drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
+
+ coresight_clear_self_claim_tag_unlocked(csa);
etm4_cs_lock(drvdata, csa);
cpu_detect_trace_filtering(drvdata);
}
-static inline u32 etm4_get_victlr_access_type(struct etmv4_config *config)
+static u32 etm4_get_victlr_access_type(struct etmv4_config *config)
{
return etm4_get_access_type(config) << __bf_shf(TRCVICTLR_EXLEVEL_MASK);
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index fdd0956fecb3..ab251865b893 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -2320,11 +2320,11 @@ static ssize_t ts_source_show(struct device *dev,
goto out;
}
- switch (drvdata->trfcr & TRFCR_EL1_TS_MASK) {
+ val = FIELD_GET(TRFCR_EL1_TS_MASK, drvdata->trfcr);
+ switch (val) {
case TRFCR_EL1_TS_VIRTUAL:
case TRFCR_EL1_TS_GUEST_PHYSICAL:
case TRFCR_EL1_TS_PHYSICAL:
- val = FIELD_GET(TRFCR_EL1_TS_MASK, drvdata->trfcr);
break;
default:
val = -1;
@@ -2440,7 +2440,7 @@ static u32 etmv4_cross_read(const struct etmv4_drvdata *drvdata, u32 offset)
return reg.data;
}
-static inline u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr)
+static u32 coresight_etm4x_attr_to_offset(struct device_attribute *attr)
{
struct dev_ext_attribute *eattr;
@@ -2464,7 +2464,7 @@ static ssize_t coresight_etm4x_reg_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);
}
-static inline bool
+static bool
etm4x_register_implemented(struct etmv4_drvdata *drvdata, u32 offset)
{
switch (offset) {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index bd7db36ba197..ac649515054d 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -983,6 +983,7 @@ struct etmv4_save_state {
* @state_needs_restore: True when there is context to restore after PM exit
* @skip_power_up: Indicates if an implementation can skip powering up
* the trace unit.
+ * @paused: Indicates if the trace unit is paused.
* @arch_features: Bitmap of arch features of etmv4 devices.
*/
struct etmv4_drvdata {
@@ -1036,6 +1037,7 @@ struct etmv4_drvdata {
struct etmv4_save_state *save_state;
bool state_needs_restore;
bool skip_power_up;
+ bool paused;
DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
};
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index 0541712b2bcb..b1922dbe9292 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -255,6 +255,7 @@ static int funnel_probe(struct device *dev, struct resource *res)
drvdata->base = base;
desc.groups = coresight_funnel_groups;
desc.access = CSDEV_ACCESS_IOMEM(base);
+ coresight_clear_self_claim_tag(&desc.access);
}
dev_set_drvdata(dev, drvdata);
@@ -433,7 +434,8 @@ static struct amba_driver dynamic_funnel_driver = {
static int __init funnel_init(void)
{
- return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver);
+ return coresight_init_driver("funnel", &dynamic_funnel_driver, &funnel_driver,
+ THIS_MODULE);
}
static void __exit funnel_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-kunit-tests.c b/drivers/hwtracing/coresight/coresight-kunit-tests.c
new file mode 100644
index 000000000000..c8f361767c45
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-kunit-tests.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <kunit/test.h>
+#include <kunit/device.h>
+#include <linux/coresight.h>
+
+#include "coresight-priv.h"
+
+static struct coresight_device *coresight_test_device(struct device *dev)
+{
+ struct coresight_device *csdev = devm_kcalloc(dev, 1,
+ sizeof(struct coresight_device),
+ GFP_KERNEL);
+ csdev->pdata = devm_kcalloc(dev, 1,
+ sizeof(struct coresight_platform_data),
+ GFP_KERNEL);
+ return csdev;
+}
+
+static void test_default_sink(struct kunit *test)
+{
+ /*
+ * Source -> ETF -> ETR -> CATU
+ * ^
+ * | default
+ */
+ struct device *dev = kunit_device_register(test, "coresight_kunit");
+ struct coresight_device *src = coresight_test_device(dev),
+ *etf = coresight_test_device(dev),
+ *etr = coresight_test_device(dev),
+ *catu = coresight_test_device(dev);
+ struct coresight_connection conn = {};
+
+ src->type = CORESIGHT_DEV_TYPE_SOURCE;
+ /*
+ * Don't use CORESIGHT_DEV_SUBTYPE_SOURCE_PROC, that would always return
+ * a TRBE sink if one is registered.
+ */
+ src->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
+ etf->type = CORESIGHT_DEV_TYPE_LINKSINK;
+ etf->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+ etr->type = CORESIGHT_DEV_TYPE_SINK;
+ etr->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
+ catu->type = CORESIGHT_DEV_TYPE_HELPER;
+
+ conn.src_dev = src;
+ conn.dest_dev = etf;
+ coresight_add_out_conn(dev, src->pdata, &conn);
+
+ conn.src_dev = etf;
+ conn.dest_dev = etr;
+ coresight_add_out_conn(dev, etf->pdata, &conn);
+
+ conn.src_dev = etr;
+ conn.dest_dev = catu;
+ coresight_add_out_conn(dev, etr->pdata, &conn);
+
+ KUNIT_ASSERT_PTR_EQ(test, coresight_find_default_sink(src), etr);
+}
+
+static struct kunit_case coresight_testcases[] = {
+ KUNIT_CASE(test_default_sink),
+ {}
+};
+
+static struct kunit_suite coresight_test_suite = {
+ .name = "coresight_test_suite",
+ .test_cases = coresight_testcases,
+};
+
+kunit_test_suites(&coresight_test_suite);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Clark <james.clark@linaro.org>");
+MODULE_DESCRIPTION("Arm CoreSight KUnit tests");
diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c
index 8192ba3279f0..0db64c5f4995 100644
--- a/drivers/hwtracing/coresight/coresight-platform.c
+++ b/drivers/hwtracing/coresight/coresight-platform.c
@@ -139,7 +139,7 @@ coresight_find_csdev_by_fwnode(struct fwnode_handle *r_fwnode)
EXPORT_SYMBOL_GPL(coresight_find_csdev_by_fwnode);
#ifdef CONFIG_OF
-static inline bool of_coresight_legacy_ep_is_input(struct device_node *ep)
+static bool of_coresight_legacy_ep_is_input(struct device_node *ep)
{
return of_property_read_bool(ep, "slave-mode");
}
@@ -159,7 +159,7 @@ static struct device_node *of_coresight_get_port_parent(struct device_node *ep)
return parent;
}
-static inline struct device_node *
+static struct device_node *
of_coresight_get_output_ports_node(const struct device_node *node)
{
return of_get_child_by_name(node, "out-ports");
@@ -327,14 +327,14 @@ static int of_get_coresight_platform_data(struct device *dev,
return 0;
}
#else
-static inline int
+static int
of_get_coresight_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
{
return -ENOENT;
}
-static inline int of_coresight_get_cpu(struct device *dev)
+static int of_coresight_get_cpu(struct device *dev)
{
return -ENODEV;
}
@@ -356,7 +356,7 @@ static const guid_t coresight_graph_uuid = GUID_INIT(0x3ecbc8b6, 0x1d0e, 0x4fb3,
#define ACPI_CORESIGHT_LINK_SLAVE 0
#define ACPI_CORESIGHT_LINK_MASTER 1
-static inline bool is_acpi_guid(const union acpi_object *obj)
+static bool is_acpi_guid(const union acpi_object *obj)
{
return (obj->type == ACPI_TYPE_BUFFER) && (obj->buffer.length == 16);
}
@@ -365,24 +365,24 @@ static inline bool is_acpi_guid(const union acpi_object *obj)
* acpi_guid_matches - Checks if the given object is a GUID object and
* that it matches the supplied the GUID.
*/
-static inline bool acpi_guid_matches(const union acpi_object *obj,
+static bool acpi_guid_matches(const union acpi_object *obj,
const guid_t *guid)
{
return is_acpi_guid(obj) &&
guid_equal((guid_t *)obj->buffer.pointer, guid);
}
-static inline bool is_acpi_dsd_graph_guid(const union acpi_object *obj)
+static bool is_acpi_dsd_graph_guid(const union acpi_object *obj)
{
return acpi_guid_matches(obj, &acpi_graph_uuid);
}
-static inline bool is_acpi_coresight_graph_guid(const union acpi_object *obj)
+static bool is_acpi_coresight_graph_guid(const union acpi_object *obj)
{
return acpi_guid_matches(obj, &coresight_graph_uuid);
}
-static inline bool is_acpi_coresight_graph(const union acpi_object *obj)
+static bool is_acpi_coresight_graph(const union acpi_object *obj)
{
const union acpi_object *graphid, *guid, *links;
@@ -469,7 +469,7 @@ static inline bool is_acpi_coresight_graph(const union acpi_object *obj)
* }, // End of ACPI Graph Property
* })
*/
-static inline bool acpi_validate_dsd_graph(const union acpi_object *graph)
+static bool acpi_validate_dsd_graph(const union acpi_object *graph)
{
int i, n;
const union acpi_object *rev, *nr_graphs;
@@ -553,7 +553,7 @@ acpi_get_dsd_graph(struct acpi_device *adev, struct acpi_buffer *buf)
return NULL;
}
-static inline bool
+static bool
acpi_validate_coresight_graph(const union acpi_object *cs_graph)
{
int nlinks;
@@ -794,14 +794,14 @@ acpi_get_coresight_platform_data(struct device *dev,
#else
-static inline int
+static int
acpi_get_coresight_platform_data(struct device *dev,
struct coresight_platform_data *pdata)
{
return -ENOENT;
}
-static inline int acpi_coresight_get_cpu(struct device *dev)
+static int acpi_coresight_get_cpu(struct device *dev)
{
return -ENODEV;
}
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 82644aff8d2b..33e22b1ba043 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -35,7 +35,11 @@ extern const struct device_type coresight_dev_type[];
* Coresight device CLAIM protocol.
* See PSCI - ARM DEN 0022D, Section: 6.8.1 Debug and Trace save and restore.
*/
-#define CORESIGHT_CLAIM_SELF_HOSTED BIT(1)
+#define CORESIGHT_CLAIM_MASK GENMASK(1, 0)
+#define CORESIGHT_CLAIM_FREE 0
+#define CORESIGHT_CLAIM_EXTERNAL 1
+#define CORESIGHT_CLAIM_SELF_HOSTED 2
+#define CORESIGHT_CLAIM_INVALID 3
#define TIMEOUT_US 100
#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
@@ -56,10 +60,8 @@ struct cs_off_attribute {
u32 off;
};
-extern ssize_t coresight_simple_show32(struct device *_dev,
- struct device_attribute *attr, char *buf);
-extern ssize_t coresight_simple_show_pair(struct device *_dev,
- struct device_attribute *attr, char *buf);
+ssize_t coresight_simple_show32(struct device *_dev, struct device_attribute *attr, char *buf);
+ssize_t coresight_simple_show_pair(struct device *_dev, struct device_attribute *attr, char *buf);
#define coresight_simple_reg32(name, offset) \
(&((struct cs_off_attribute[]) { \
@@ -156,8 +158,8 @@ void coresight_path_assign_trace_id(struct coresight_path *path,
enum cs_mode mode);
#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM3X)
-extern int etm_readl_cp14(u32 off, unsigned int *val);
-extern int etm_writel_cp14(u32 off, u32 val);
+int etm_readl_cp14(u32 off, unsigned int *val);
+int etm_writel_cp14(u32 off, u32 val);
#else
static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
@@ -168,8 +170,8 @@ struct cti_assoc_op {
void (*remove)(struct coresight_device *csdev);
};
-extern void coresight_set_cti_ops(const struct cti_assoc_op *cti_op);
-extern void coresight_remove_cti_ops(void);
+void coresight_set_cti_ops(const struct cti_assoc_op *cti_op);
+void coresight_remove_cti_ops(void);
/*
* Macros and inline functions to handle CoreSight UCI data and driver
@@ -249,5 +251,7 @@ void coresight_add_helper(struct coresight_device *csdev,
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
struct coresight_device *coresight_get_percpu_sink(int cpu);
void coresight_disable_source(struct coresight_device *csdev, void *data);
+void coresight_pause_source(struct coresight_device *csdev);
+int coresight_resume_source(struct coresight_device *csdev);
#endif
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index ee7ee79f6cf7..06efd2b01a0f 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -63,7 +63,7 @@ static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
/*
* replicator_reset : Reset the replicator configuration to sane values.
*/
-static inline void replicator_reset(struct replicator_drvdata *drvdata)
+static void replicator_reset(struct replicator_drvdata *drvdata)
{
if (drvdata->base)
dynamic_replicator_reset(drvdata);
@@ -262,6 +262,7 @@ static int replicator_probe(struct device *dev, struct resource *res)
drvdata->base = base;
desc.groups = replicator_groups;
desc.access = CSDEV_ACCESS_IOMEM(base);
+ coresight_clear_self_claim_tag(&desc.access);
}
if (fwnode_property_present(dev_fwnode(dev),
@@ -438,7 +439,8 @@ static struct amba_driver dynamic_replicator_driver = {
static int __init replicator_init(void)
{
- return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver);
+ return coresight_init_driver("replicator", &dynamic_replicator_driver, &replicator_driver,
+ THIS_MODULE);
}
static void __exit replicator_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 26f9339f38b9..e45c6c7204b4 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -301,7 +301,7 @@ static const struct coresight_ops stm_cs_ops = {
.source_ops = &stm_source_ops,
};
-static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes)
+static bool stm_addr_unaligned(const void *addr, u8 write_bytes)
{
return ((unsigned long)addr & (write_bytes - 1));
}
@@ -685,7 +685,7 @@ static int of_stm_get_stimulus_area(struct device *dev, struct resource *res)
return of_address_to_resource(np, index, res);
}
#else
-static inline int of_stm_get_stimulus_area(struct device *dev,
+static int of_stm_get_stimulus_area(struct device *dev,
struct resource *res)
{
return -ENOENT;
@@ -729,7 +729,7 @@ static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
return rc;
}
#else
-static inline int acpi_stm_get_stimulus_area(struct device *dev,
+static int acpi_stm_get_stimulus_area(struct device *dev,
struct resource *res)
{
return -ENOENT;
@@ -1058,7 +1058,7 @@ static struct platform_driver stm_platform_driver = {
static int __init stm_init(void)
{
- return coresight_init_driver("stm", &stm_driver, &stm_platform_driver);
+ return coresight_init_driver("stm", &stm_driver, &stm_platform_driver, THIS_MODULE);
}
static void __exit stm_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
index 213b4159b062..2b40e556be87 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c
@@ -10,7 +10,7 @@
#include "coresight-syscfg-configfs.h"
/* create a default ci_type. */
-static inline struct config_item_type *cscfg_create_ci_type(void)
+static struct config_item_type *cscfg_create_ci_type(void)
{
struct config_item_type *ci_type;
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index a70c1454b410..83dad24e0116 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -395,6 +395,8 @@ static void cscfg_remove_owned_csdev_configs(struct coresight_device *csdev, voi
if (list_empty(&csdev->config_csdev_list))
return;
+ guard(raw_spinlock_irqsave)(&csdev->cscfg_csdev_lock);
+
list_for_each_entry_safe(config_csdev, tmp, &csdev->config_csdev_list, node) {
if (config_csdev->config_desc->load_owner == load_owner)
list_del(&config_csdev->node);
@@ -867,6 +869,25 @@ unlock_exit:
}
EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats);
+static bool cscfg_config_desc_get(struct cscfg_config_desc *config_desc)
+{
+ if (!atomic_fetch_inc(&config_desc->active_cnt)) {
+ /* must ensure that config cannot be unloaded in use */
+ if (unlikely(cscfg_owner_get(config_desc->load_owner))) {
+ atomic_dec(&config_desc->active_cnt);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void cscfg_config_desc_put(struct cscfg_config_desc *config_desc)
+{
+ if (!atomic_dec_return(&config_desc->active_cnt))
+ cscfg_owner_put(config_desc->load_owner);
+}
+
/*
* This activate configuration for either perf or sysfs. Perf can have multiple
* active configs, selected per event, sysfs is limited to one.
@@ -890,22 +911,17 @@ static int _cscfg_activate_config(unsigned long cfg_hash)
if (config_desc->available == false)
return -EBUSY;
- /* must ensure that config cannot be unloaded in use */
- err = cscfg_owner_get(config_desc->load_owner);
- if (err)
+ if (!cscfg_config_desc_get(config_desc)) {
+ err = -EINVAL;
break;
+ }
+
/*
* increment the global active count - control changes to
* active configurations
*/
atomic_inc(&cscfg_mgr->sys_active_cnt);
- /*
- * mark the descriptor as active so enable config on a
- * device instance will use it
- */
- atomic_inc(&config_desc->active_cnt);
-
err = 0;
dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name);
break;
@@ -920,9 +936,8 @@ static void _cscfg_deactivate_config(unsigned long cfg_hash)
list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) {
if ((unsigned long)config_desc->event_ea->var == cfg_hash) {
- atomic_dec(&config_desc->active_cnt);
atomic_dec(&cscfg_mgr->sys_active_cnt);
- cscfg_owner_put(config_desc->load_owner);
+ cscfg_config_desc_put(config_desc);
dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name);
break;
}
@@ -1047,7 +1062,7 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
unsigned long cfg_hash, int preset)
{
struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item;
- const struct cscfg_config_desc *config_desc;
+ struct cscfg_config_desc *config_desc;
unsigned long flags;
int err = 0;
@@ -1062,8 +1077,8 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
raw_spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags);
list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) {
config_desc = config_csdev_item->config_desc;
- if ((atomic_read(&config_desc->active_cnt)) &&
- ((unsigned long)config_desc->event_ea->var == cfg_hash)) {
+ if (((unsigned long)config_desc->event_ea->var == cfg_hash) &&
+ cscfg_config_desc_get(config_desc)) {
config_csdev_active = config_csdev_item;
csdev->active_cscfg_ctxt = (void *)config_csdev_active;
break;
@@ -1097,7 +1112,11 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
err = -EBUSY;
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
}
+
+ if (err)
+ cscfg_config_desc_put(config_desc);
}
+
return err;
}
EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
@@ -1136,8 +1155,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
/* true if there was an enabled active config */
- if (config_csdev)
+ if (config_csdev) {
cscfg_csdev_disable_config(config_csdev);
+ cscfg_config_desc_put(config_csdev->config_desc);
+ }
}
EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config);
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index a7814e8e657b..88afb16bb6be 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -287,8 +287,8 @@ static int tmc_open(struct inode *inode, struct file *file)
return 0;
}
-static inline ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata,
- loff_t pos, size_t len, char **bufpp)
+static ssize_t tmc_get_sysfs_trace(struct tmc_drvdata *drvdata, loff_t pos, size_t len,
+ char **bufpp)
{
switch (drvdata->config_type) {
case TMC_CONFIG_TYPE_ETB:
@@ -591,7 +591,7 @@ static const struct attribute_group *coresight_etr_groups[] = {
NULL,
};
-static inline bool tmc_etr_can_use_sg(struct device *dev)
+static bool tmc_etr_can_use_sg(struct device *dev)
{
int ret;
u8 val_u8;
@@ -621,7 +621,7 @@ static inline bool tmc_etr_can_use_sg(struct device *dev)
return false;
}
-static inline bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
+static bool tmc_etr_has_non_secure_access(struct tmc_drvdata *drvdata)
{
u32 auth = readl_relaxed(drvdata->base + TMC_AUTHSTATUS);
@@ -869,6 +869,7 @@ static int __tmc_probe(struct device *dev, struct resource *res)
dev->platform_data = pdata;
desc.pdata = pdata;
+ coresight_clear_self_claim_tag(&desc.access);
drvdata->csdev = coresight_register(&desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
@@ -1060,7 +1061,7 @@ static struct platform_driver tmc_platform_driver = {
static int __init tmc_init(void)
{
- return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver);
+ return coresight_init_driver("tmc", &tmc_driver, &tmc_platform_driver, THIS_MODULE);
}
static void __exit tmc_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c
index d858740001c2..0f45ab5e5249 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etf.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c
@@ -482,6 +482,7 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
unsigned long offset, to_read = 0, flags;
struct cs_buffers *buf = sink_config;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ struct perf_event *event = handle->event;
if (!buf)
return 0;
@@ -586,6 +587,14 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
* is expected by the perf ring buffer.
*/
CS_LOCK(drvdata->base);
+
+ /*
+ * If the event is active, it is triggered during an AUX pause.
+ * Re-enable the sink so that it is ready when AUX resume is invoked.
+ */
+ if (!event->hw.state)
+ __tmc_etb_enable_hw(drvdata);
+
out:
raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -747,7 +756,6 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
char *buf = NULL;
enum tmc_mode mode;
unsigned long flags;
- int rc = 0;
/* config types are set a boot time and never change */
if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB &&
@@ -773,11 +781,11 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
* can't be NULL.
*/
memset(drvdata->buf, 0, drvdata->size);
- rc = __tmc_etb_enable_hw(drvdata);
- if (rc) {
- raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
- return rc;
- }
+ /*
+ * Ignore failures to enable the TMC to make sure, we don't
+ * leave the TMC in a "reading" state.
+ */
+ __tmc_etb_enable_hw(drvdata);
} else {
/*
* The ETB/ETF is not tracing and the buffer was just read.
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 76a8cb29b68a..b07fcdb3fe1a 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -125,7 +125,7 @@ struct etr_sg_table {
* If we spill over to a new page for mapping 1 entry, we could as
* well replace the link entry of the previous page with the last entry.
*/
-static inline unsigned long __attribute_const__
+static unsigned long __attribute_const__
tmc_etr_sg_table_entries(int nr_pages)
{
unsigned long nr_sgpages = nr_pages * ETR_SG_PAGES_PER_SYSPAGE;
@@ -239,13 +239,13 @@ err:
return -ENOMEM;
}
-static inline long
+static long
tmc_sg_get_data_page_offset(struct tmc_sg_table *sg_table, dma_addr_t addr)
{
return tmc_pages_get_offset(&sg_table->data_pages, addr);
}
-static inline void tmc_free_table_pages(struct tmc_sg_table *sg_table)
+static void tmc_free_table_pages(struct tmc_sg_table *sg_table)
{
if (sg_table->table_vaddr)
vunmap(sg_table->table_vaddr);
@@ -481,7 +481,7 @@ static void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table)
dev_dbg(sg_table->dev, "******* End of Table *****\n");
}
#else
-static inline void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table) {}
+static void tmc_etr_sg_table_dump(struct etr_sg_table *etr_table) {}
#endif
/*
@@ -886,10 +886,8 @@ void tmc_etr_remove_catu_ops(void)
}
EXPORT_SYMBOL_GPL(tmc_etr_remove_catu_ops);
-static inline int tmc_etr_mode_alloc_buf(int mode,
- struct tmc_drvdata *drvdata,
- struct etr_buf *etr_buf, int node,
- void **pages)
+static int tmc_etr_mode_alloc_buf(int mode, struct tmc_drvdata *drvdata, struct etr_buf *etr_buf,
+ int node, void **pages)
{
int rc = -EINVAL;
@@ -1009,7 +1007,7 @@ static ssize_t tmc_etr_buf_get_data(struct etr_buf *etr_buf,
return etr_buf->ops->get_data(etr_buf, (u64)offset, len, bufpp);
}
-static inline s64
+static s64
tmc_etr_buf_insert_barrier_packet(struct etr_buf *etr_buf, u64 offset)
{
ssize_t len;
@@ -1636,6 +1634,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etr_perf_buffer *etr_perf = config;
struct etr_buf *etr_buf = etr_perf->etr_buf;
+ struct perf_event *event = handle->event;
raw_spin_lock_irqsave(&drvdata->spinlock, flags);
@@ -1705,6 +1704,15 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
*/
smp_wmb();
+ /*
+ * If the event is active, it is triggered during an AUX pause.
+ * Re-enable the sink so that it is ready when AUX resume is invoked.
+ */
+ raw_spin_lock_irqsave(&drvdata->spinlock, flags);
+ if (csdev->refcnt && !event->hw.state)
+ __tmc_etr_enable_hw(drvdata);
+ raw_spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
out:
/*
* Don't set the TRUNCATED flag in snapshot mode because 1) the
diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c
index 97ef36f03ec2..3e0159288428 100644
--- a/drivers/hwtracing/coresight/coresight-tpiu.c
+++ b/drivers/hwtracing/coresight/coresight-tpiu.c
@@ -318,7 +318,7 @@ static struct platform_driver tpiu_platform_driver = {
static int __init tpiu_init(void)
{
- return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver);
+ return coresight_init_driver("tpiu", &tpiu_driver, &tpiu_platform_driver, THIS_MODULE);
}
static void __exit tpiu_exit(void)
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index fff67aac8418..8267dd1a2130 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -160,22 +160,22 @@ static void trbe_check_errata(struct trbe_cpudata *cpudata)
}
}
-static inline bool trbe_has_erratum(struct trbe_cpudata *cpudata, int i)
+static bool trbe_has_erratum(struct trbe_cpudata *cpudata, int i)
{
return (i < TRBE_ERRATA_MAX) && test_bit(i, cpudata->errata);
}
-static inline bool trbe_may_overwrite_in_fill_mode(struct trbe_cpudata *cpudata)
+static bool trbe_may_overwrite_in_fill_mode(struct trbe_cpudata *cpudata)
{
return trbe_has_erratum(cpudata, TRBE_WORKAROUND_OVERWRITE_FILL_MODE);
}
-static inline bool trbe_may_write_out_of_range(struct trbe_cpudata *cpudata)
+static bool trbe_may_write_out_of_range(struct trbe_cpudata *cpudata)
{
return trbe_has_erratum(cpudata, TRBE_WORKAROUND_WRITE_OUT_OF_RANGE);
}
-static inline bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata)
+static bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata)
{
/*
* Errata affected TRBE implementation will need TSB CSYNC and
@@ -185,7 +185,7 @@ static inline bool trbe_needs_drain_after_disable(struct trbe_cpudata *cpudata)
return trbe_has_erratum(cpudata, TRBE_NEEDS_DRAIN_AFTER_DISABLE);
}
-static inline bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudata)
+static bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudata)
{
/*
* Errata affected TRBE implementation will need an additional
@@ -196,7 +196,7 @@ static inline bool trbe_needs_ctxt_sync_after_enable(struct trbe_cpudata *cpudat
return trbe_has_erratum(cpudata, TRBE_NEEDS_CTXT_SYNC_AFTER_ENABLE);
}
-static inline bool trbe_is_broken(struct trbe_cpudata *cpudata)
+static bool trbe_is_broken(struct trbe_cpudata *cpudata)
{
return trbe_has_erratum(cpudata, TRBE_IS_BROKEN);
}
@@ -208,13 +208,13 @@ static int trbe_alloc_node(struct perf_event *event)
return cpu_to_node(event->cpu);
}
-static inline void trbe_drain_buffer(void)
+static void trbe_drain_buffer(void)
{
tsb_csync();
dsb(nsh);
}
-static inline void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr)
+static void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr)
{
/*
* Enable the TRBE without clearing LIMITPTR which
@@ -231,7 +231,7 @@ static inline void set_trbe_enabled(struct trbe_cpudata *cpudata, u64 trblimitr)
isb();
}
-static inline void set_trbe_disabled(struct trbe_cpudata *cpudata)
+static void set_trbe_disabled(struct trbe_cpudata *cpudata)
{
u64 trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
index bc6d634bd85c..7d482dd595fa 100644
--- a/drivers/iio/accel/adxl345.h
+++ b/drivers/iio/accel/adxl345.h
@@ -111,6 +111,10 @@
*/
#define ADXL375_USCALE 480000
+struct regmap;
+
+bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg);
+
struct adxl345_chip_info {
const char *name;
int uscale;
diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 375c27d16827..2e5fdd479e8d 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -8,6 +8,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -17,6 +18,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/kfifo_buf.h>
#include "adxl345.h"
@@ -31,18 +33,71 @@
#define ADXL345_INT1 0
#define ADXL345_INT2 1
+#define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0)
+#define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3)
+#define ADXL345_REG_TAP_SUPPRESS BIT(3)
+
+#define ADXL345_TAP_Z_EN BIT(0)
+#define ADXL345_TAP_Y_EN BIT(1)
+#define ADXL345_TAP_X_EN BIT(2)
+
+/* single/double tap */
+enum adxl345_tap_type {
+ ADXL345_SINGLE_TAP,
+ ADXL345_DOUBLE_TAP,
+};
+
+static const unsigned int adxl345_tap_int_reg[] = {
+ [ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP,
+ [ADXL345_DOUBLE_TAP] = ADXL345_INT_DOUBLE_TAP,
+};
+
+enum adxl345_tap_time_type {
+ ADXL345_TAP_TIME_LATENT,
+ ADXL345_TAP_TIME_WINDOW,
+ ADXL345_TAP_TIME_DUR,
+};
+
+static const unsigned int adxl345_tap_time_reg[] = {
+ [ADXL345_TAP_TIME_LATENT] = ADXL345_REG_LATENT,
+ [ADXL345_TAP_TIME_WINDOW] = ADXL345_REG_WINDOW,
+ [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR,
+};
+
struct adxl345_state {
const struct adxl345_chip_info *info;
struct regmap *regmap;
bool fifo_delay; /* delay: delay is needed for SPI */
int irq;
- u8 intio;
- u8 int_map;
u8 watermark;
u8 fifo_mode;
+
+ u32 tap_duration_us;
+ u32 tap_latent_us;
+ u32 tap_window_us;
+
__le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
};
+static struct iio_event_spec adxl345_events[] = {
+ {
+ /* single tap */
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_SINGLETAP,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_TIMEOUT),
+ },
+ {
+ /* double tap */
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_DOUBLETAP,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_RESET_TIMEOUT) |
+ BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
+ },
+};
+
#define ADXL345_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
@@ -59,6 +114,8 @@ struct adxl345_state {
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
+ .event_spec = adxl345_events, \
+ .num_event_specs = ARRAY_SIZE(adxl345_events), \
}
enum adxl345_chans {
@@ -76,6 +133,25 @@ static const unsigned long adxl345_scan_masks[] = {
0
};
+bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADXL345_REG_DATA_AXIS(0):
+ case ADXL345_REG_DATA_AXIS(1):
+ case ADXL345_REG_DATA_AXIS(2):
+ case ADXL345_REG_DATA_AXIS(3):
+ case ADXL345_REG_DATA_AXIS(4):
+ case ADXL345_REG_DATA_AXIS(5):
+ case ADXL345_REG_ACT_TAP_STATUS:
+ case ADXL345_REG_FIFO_STATUS:
+ case ADXL345_REG_INT_SOURCE:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(adxl345_is_volatile_reg, "IIO_ADXL345");
+
/**
* adxl345_set_measure_en() - Enable and disable measuring.
*
@@ -96,24 +172,215 @@ static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val);
}
-static int adxl345_set_interrupts(struct adxl345_state *st)
+/* tap */
+
+static int _adxl345_set_tap_int(struct adxl345_state *st,
+ enum adxl345_tap_type type, bool state)
{
+ unsigned int int_map = 0x00;
+ unsigned int tap_threshold;
+ bool axis_valid;
+ bool singletap_args_valid = false;
+ bool doubletap_args_valid = false;
+ bool en = false;
+ u32 axis_ctrl;
int ret;
- unsigned int int_enable = st->int_map;
- unsigned int int_map;
+
+ ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
+ if (ret)
+ return ret;
+
+ axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) > 0;
+
+ ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold);
+ if (ret)
+ return ret;
/*
- * Any bits set to 0 in the INT map register send their respective
- * interrupts to the INT1 pin, whereas bits set to 1 send their respective
- * interrupts to the INT2 pin. The intio shall convert this accordingly.
+ * Note: A value of 0 for threshold and/or dur may result in undesirable
+ * behavior if single tap/double tap interrupts are enabled.
*/
- int_map = st->intio ? st->int_map : ~st->int_map;
+ singletap_args_valid = tap_threshold > 0 && st->tap_duration_us > 0;
- ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, int_map);
+ if (type == ADXL345_SINGLE_TAP) {
+ en = axis_valid && singletap_args_valid;
+ } else {
+ /* doubletap: Window must be equal or greater than latent! */
+ doubletap_args_valid = st->tap_latent_us > 0 &&
+ st->tap_window_us > 0 &&
+ st->tap_window_us >= st->tap_latent_us;
+
+ en = axis_valid && singletap_args_valid && doubletap_args_valid;
+ }
+
+ if (state && en)
+ int_map |= adxl345_tap_int_reg[type];
+
+ return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE,
+ adxl345_tap_int_reg[type], int_map);
+}
+
+static int adxl345_is_tap_en(struct adxl345_state *st,
+ enum iio_modifier axis,
+ enum adxl345_tap_type type, bool *en)
+{
+ unsigned int regval;
+ u32 axis_ctrl;
+ int ret;
+
+ ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
if (ret)
return ret;
- return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, int_enable);
+ /* Verify if axis is enabled for the tap detection. */
+ switch (axis) {
+ case IIO_MOD_X:
+ *en = FIELD_GET(ADXL345_TAP_X_EN, axis_ctrl);
+ break;
+ case IIO_MOD_Y:
+ *en = FIELD_GET(ADXL345_TAP_Y_EN, axis_ctrl);
+ break;
+ case IIO_MOD_Z:
+ *en = FIELD_GET(ADXL345_TAP_Z_EN, axis_ctrl);
+ break;
+ default:
+ *en = false;
+ return -EINVAL;
+ }
+
+ if (*en) {
+ /*
+ * If axis allow for tap detection, verify if the interrupt is
+ * enabled for tap detection.
+ */
+ ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, &regval);
+ if (ret)
+ return ret;
+
+ *en = adxl345_tap_int_reg[type] & regval;
+ }
+
+ return 0;
+}
+
+static int adxl345_set_singletap_en(struct adxl345_state *st,
+ enum iio_modifier axis, bool en)
+{
+ int ret;
+ u32 axis_ctrl;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ axis_ctrl = ADXL345_TAP_X_EN;
+ break;
+ case IIO_MOD_Y:
+ axis_ctrl = ADXL345_TAP_Y_EN;
+ break;
+ case IIO_MOD_Z:
+ axis_ctrl = ADXL345_TAP_Z_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (en)
+ ret = regmap_set_bits(st->regmap, ADXL345_REG_TAP_AXIS,
+ axis_ctrl);
+ else
+ ret = regmap_clear_bits(st->regmap, ADXL345_REG_TAP_AXIS,
+ axis_ctrl);
+ if (ret)
+ return ret;
+
+ return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en);
+}
+
+static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en)
+{
+ int ret;
+
+ /*
+ * Generally suppress detection of spikes during the latency period as
+ * double taps here, this is fully optional for double tap detection
+ */
+ ret = regmap_update_bits(st->regmap, ADXL345_REG_TAP_AXIS,
+ ADXL345_REG_TAP_SUPPRESS_MSK,
+ en ? ADXL345_REG_TAP_SUPPRESS : 0x00);
+ if (ret)
+ return ret;
+
+ return _adxl345_set_tap_int(st, ADXL345_DOUBLE_TAP, en);
+}
+
+static int _adxl345_set_tap_time(struct adxl345_state *st,
+ enum adxl345_tap_time_type type, u32 val_us)
+{
+ unsigned int regval;
+
+ switch (type) {
+ case ADXL345_TAP_TIME_WINDOW:
+ st->tap_window_us = val_us;
+ break;
+ case ADXL345_TAP_TIME_LATENT:
+ st->tap_latent_us = val_us;
+ break;
+ case ADXL345_TAP_TIME_DUR:
+ st->tap_duration_us = val_us;
+ break;
+ }
+
+ /*
+ * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us.
+ * For tap_duration_us the scale factor is 625us / LSB.
+ */
+ if (type == ADXL345_TAP_TIME_DUR)
+ regval = DIV_ROUND_CLOSEST(val_us, 625);
+ else
+ regval = DIV_ROUND_CLOSEST(val_us, 1250);
+
+ return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval);
+}
+
+static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int,
+ u32 val_fract_us)
+{
+ /*
+ * Max value is 255 * 625 us = 0.159375 seconds
+ *
+ * Note: the scaling is similar to the scaling in the ADXL380
+ */
+ if (val_int || val_fract_us > 159375)
+ return -EINVAL;
+
+ return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us);
+}
+
+static int adxl345_set_tap_window(struct adxl345_state *st, u32 val_int,
+ u32 val_fract_us)
+{
+ /*
+ * Max value is 255 * 1250 us = 0.318750 seconds
+ *
+ * Note: the scaling is similar to the scaling in the ADXL380
+ */
+ if (val_int || val_fract_us > 318750)
+ return -EINVAL;
+
+ return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_WINDOW, val_fract_us);
+}
+
+static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
+ u32 val_fract_us)
+{
+ /*
+ * Max value is 255 * 1250 us = 0.318750 seconds
+ *
+ * Note: the scaling is similar to the scaling in the ADXL380
+ */
+ if (val_int || val_fract_us > 318750)
+ return -EINVAL;
+
+ return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
}
static int adxl345_read_raw(struct iio_dev *indio_dev,
@@ -136,7 +403,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
ret = regmap_bulk_read(st->regmap,
ADXL345_REG_DATA_AXIS(chan->address),
&accel, sizeof(accel));
- if (ret < 0)
+ if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(accel), 12);
@@ -148,7 +415,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(st->regmap,
ADXL345_REG_OFS_AXIS(chan->address), &regval);
- if (ret < 0)
+ if (ret)
return ret;
/*
* 8-bit resolution at +/- 2g, that is 4x accel data scale
@@ -159,7 +426,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, &regval);
- if (ret < 0)
+ if (ret)
return ret;
samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
@@ -201,6 +468,157 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+static int adxl345_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 adxl345_state *st = iio_priv(indio_dev);
+ bool int_en;
+ int ret;
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ ret = adxl345_is_tap_en(st, chan->channel2,
+ ADXL345_SINGLE_TAP, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ case IIO_EV_DIR_DOUBLETAP:
+ ret = adxl345_is_tap_en(st, chan->channel2,
+ ADXL345_DOUBLE_TAP, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl345_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ struct adxl345_state *st = iio_priv(indio_dev);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ return adxl345_set_singletap_en(st, chan->channel2, state);
+ case IIO_EV_DIR_DOUBLETAP:
+ return adxl345_set_doubletap_en(st, state);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl345_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct adxl345_state *st = iio_priv(indio_dev);
+ unsigned int tap_threshold;
+ int ret;
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ /*
+ * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but
+ * not applied here. In context of this general purpose sensor,
+ * what imports is rather signal intensity than the absolute
+ * measured g value.
+ */
+ ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP,
+ &tap_threshold);
+ if (ret)
+ return ret;
+ *val = sign_extend32(tap_threshold, 7);
+ return IIO_VAL_INT;
+ case IIO_EV_INFO_TIMEOUT:
+ *val = st->tap_duration_us;
+ *val2 = 1000000;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_EV_INFO_RESET_TIMEOUT:
+ *val = st->tap_window_us;
+ *val2 = 1000000;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_EV_INFO_TAP2_MIN_DELAY:
+ *val = st->tap_latent_us;
+ *val2 = 1000000;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl345_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct adxl345_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = adxl345_set_measure_en(st, false);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP,
+ min(val, 0xFF));
+ if (ret)
+ return ret;
+ break;
+ case IIO_EV_INFO_TIMEOUT:
+ ret = adxl345_set_tap_duration(st, val, val2);
+ if (ret)
+ return ret;
+ break;
+ case IIO_EV_INFO_RESET_TIMEOUT:
+ ret = adxl345_set_tap_window(st, val, val2);
+ if (ret)
+ return ret;
+ break;
+ case IIO_EV_INFO_TAP2_MIN_DELAY:
+ ret = adxl345_set_tap_latent(st, val, val2);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return adxl345_set_measure_en(st, true);
+}
+
static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
@@ -214,7 +632,7 @@ static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg,
static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value)
{
struct adxl345_state *st = iio_priv(indio_dev);
- unsigned int fifo_mask = 0x1F;
+ const unsigned int fifo_mask = 0x1F, watermark_mask = 0x02;
int ret;
value = min(value, ADXL345_FIFO_SIZE - 1);
@@ -224,9 +642,8 @@ static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value)
return ret;
st->watermark = value;
- st->int_map |= ADXL345_INT_WATERMARK;
-
- return 0;
+ return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE,
+ watermark_mask, ADXL345_INT_WATERMARK);
}
static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
@@ -265,21 +682,25 @@ static const struct attribute_group adxl345_attrs_group = {
static int adxl345_set_fifo(struct adxl345_state *st)
{
+ unsigned int intio;
int ret;
/* FIFO should only be configured while in standby mode */
ret = adxl345_set_measure_en(st, false);
- if (ret < 0)
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, ADXL345_REG_INT_MAP, &intio);
+ if (ret)
return ret;
ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK,
st->watermark) |
- FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK,
- st->intio) |
+ FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, intio) |
FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
st->fifo_mode));
- if (ret < 0)
+ if (ret)
return ret;
return adxl345_set_measure_en(st, true);
@@ -300,7 +721,7 @@ static int adxl345_get_samples(struct adxl345_state *st)
int ret;
ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, &regval);
- if (ret < 0)
+ if (ret)
return ret;
return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval);
@@ -328,7 +749,7 @@ static int adxl345_fifo_transfer(struct adxl345_state *st, int samples)
/* read 3x 2 byte elements from base address into next fifo_buf position */
ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE,
st->fifo_buf + (i * count / 2), count);
- if (ret < 0)
+ if (ret)
return ret;
/*
@@ -374,11 +795,6 @@ static void adxl345_fifo_reset(struct adxl345_state *st)
static int adxl345_buffer_postenable(struct iio_dev *indio_dev)
{
struct adxl345_state *st = iio_priv(indio_dev);
- int ret;
-
- ret = adxl345_set_interrupts(st);
- if (ret < 0)
- return ret;
st->fifo_mode = ADXL345_FIFO_STREAM;
return adxl345_set_fifo(st);
@@ -391,11 +807,10 @@ static int adxl345_buffer_predisable(struct iio_dev *indio_dev)
st->fifo_mode = ADXL345_FIFO_BYPASS;
ret = adxl345_set_fifo(st);
- if (ret < 0)
+ if (ret)
return ret;
- st->int_map = 0x00;
- return adxl345_set_interrupts(st);
+ return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
}
static const struct iio_buffer_setup_ops adxl345_buffer_ops = {
@@ -422,6 +837,48 @@ static int adxl345_fifo_push(struct iio_dev *indio_dev,
return 0;
}
+static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat,
+ enum iio_modifier tap_dir)
+{
+ s64 ts = iio_get_time_ns(indio_dev);
+ struct adxl345_state *st = iio_priv(indio_dev);
+ int samples;
+ int ret = -ENOENT;
+
+ if (FIELD_GET(ADXL345_INT_SINGLE_TAP, int_stat)) {
+ ret = iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_SINGLETAP),
+ ts);
+ if (ret)
+ return ret;
+ }
+
+ if (FIELD_GET(ADXL345_INT_DOUBLE_TAP, int_stat)) {
+ ret = iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_DOUBLETAP),
+ ts);
+ if (ret)
+ return ret;
+ }
+
+ if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) {
+ samples = adxl345_get_samples(st);
+ if (samples < 0)
+ return -EINVAL;
+
+ if (adxl345_fifo_push(indio_dev, samples) < 0)
+ return -EINVAL;
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
/**
* adxl345_irq_handler() - Handle irqs of the ADXL345.
* @irq: The irq being handled.
@@ -433,21 +890,35 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct adxl345_state *st = iio_priv(indio_dev);
+ unsigned int regval;
+ enum iio_modifier tap_dir = IIO_NO_MOD;
+ u32 axis_ctrl;
int int_stat;
- int samples;
+ int ret;
- if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat))
+ ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
+ if (ret)
return IRQ_NONE;
- if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) {
- samples = adxl345_get_samples(st);
- if (samples < 0)
- goto err;
-
- if (adxl345_fifo_push(indio_dev, samples) < 0)
- goto err;
+ if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl)) {
+ ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, &regval);
+ if (ret)
+ return IRQ_NONE;
+
+ if (FIELD_GET(ADXL345_TAP_Z_EN, regval))
+ tap_dir = IIO_MOD_Z;
+ else if (FIELD_GET(ADXL345_TAP_Y_EN, regval))
+ tap_dir = IIO_MOD_Y;
+ else if (FIELD_GET(ADXL345_TAP_X_EN, regval))
+ tap_dir = IIO_MOD_X;
}
+ if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat))
+ return IRQ_NONE;
+
+ if (adxl345_push_event(indio_dev, int_stat, tap_dir))
+ goto err;
+
if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat))
goto err;
@@ -464,6 +935,10 @@ static const struct iio_info adxl345_info = {
.read_raw = adxl345_read_raw,
.write_raw = adxl345_write_raw,
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
+ .read_event_config = adxl345_read_event_config,
+ .write_event_config = adxl345_write_event_config,
+ .read_event_value = adxl345_read_event_value,
+ .write_event_value = adxl345_write_event_value,
.debugfs_reg_access = &adxl345_reg_access,
.hwfifo_set_watermark = adxl345_set_watermark,
};
@@ -492,10 +967,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
struct adxl345_state *st;
struct iio_dev *indio_dev;
u32 regval;
+ u8 intio = ADXL345_INT1;
unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE |
ADXL345_DATA_FORMAT_JUSTIFY |
ADXL345_DATA_FORMAT_FULL_RES |
ADXL345_DATA_FORMAT_SELF_TEST);
+ unsigned int tap_threshold;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
@@ -509,6 +986,12 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
return -ENODEV;
st->fifo_delay = fifo_delay_default;
+ /* Init with reasonable values */
+ tap_threshold = 48; /* 48 [0x30] -> ~3g */
+ st->tap_duration_us = 16; /* 16 [0x10] -> .010 */
+ st->tap_window_us = 64; /* 64 [0x40] -> .080 */
+ st->tap_latent_us = 16; /* 16 [0x10] -> .020 */
+
indio_dev->name = st->info->name;
indio_dev->info = &adxl345_info;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -516,6 +999,11 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
indio_dev->available_scan_masks = adxl345_scan_masks;
+ /* Reset interrupts at start up */
+ ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
+ if (ret)
+ return ret;
+
if (setup) {
/* Perform optional initial bus specific configuration */
ret = setup(dev, st->regmap);
@@ -540,7 +1028,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
}
ret = regmap_read(st->regmap, ADXL345_REG_DEVID, &regval);
- if (ret < 0)
+ if (ret)
return dev_err_probe(dev, ret, "Error reading device ID\n");
if (regval != ADXL345_DEVID)
@@ -549,23 +1037,37 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
/* Enable measurement mode */
ret = adxl345_set_measure_en(st, true);
- if (ret < 0)
+ if (ret)
return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
ret = devm_add_action_or_reset(dev, adxl345_powerdown, st);
- if (ret < 0)
+ if (ret)
return ret;
- st->intio = ADXL345_INT1;
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
if (st->irq < 0) {
- st->intio = ADXL345_INT2;
+ intio = ADXL345_INT2;
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
if (st->irq < 0)
- st->intio = ADXL345_INT_NONE;
+ intio = ADXL345_INT_NONE;
}
- if (st->intio != ADXL345_INT_NONE) {
+ if (intio != ADXL345_INT_NONE) {
+ /*
+ * Any bits set to 0 in the INT map register send their respective
+ * interrupts to the INT1 pin, whereas bits set to 1 send their respective
+ * interrupts to the INT2 pin. The intio shall convert this accordingly.
+ */
+ regval = intio ? 0xff : 0;
+
+ ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold);
+ if (ret)
+ return ret;
+
/* FIFO_STREAM mode is going to be activated later */
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops);
if (ret)
@@ -581,7 +1083,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
ADXL345_FIFO_BYPASS));
- if (ret < 0)
+ if (ret)
return ret;
}
diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c
index 8c385dd6c01d..af84c0043c6c 100644
--- a/drivers/iio/accel/adxl345_i2c.c
+++ b/drivers/iio/accel/adxl345_i2c.c
@@ -17,6 +17,8 @@
static const struct regmap_config adxl345_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .volatile_reg = adxl345_is_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
};
static int adxl345_i2c_probe(struct i2c_client *client)
diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
index 7e518aea17bf..0315f4bfd69a 100644
--- a/drivers/iio/accel/adxl345_spi.c
+++ b/drivers/iio/accel/adxl345_spi.c
@@ -19,6 +19,8 @@ static const struct regmap_config adxl345_spi_regmap_config = {
.val_bits = 8,
/* Setting bits 7 and 6 enables multiple-byte read */
.read_flag_mask = BIT(7) | BIT(6),
+ .volatile_reg = adxl345_is_volatile_reg,
+ .cache_type = REGCACHE_MAPLE,
};
static int adxl345_spi_setup(struct device *dev, struct regmap *regmap)
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
index cbac622ef821..2e00fd51b4d5 100644
--- a/drivers/iio/accel/adxl355_core.c
+++ b/drivers/iio/accel/adxl355_core.c
@@ -666,8 +666,8 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p)
if (ret)
goto out_unlock_notify;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
+ sizeof(data->buffer), pf->timestamp);
out_unlock_notify:
mutex_unlock(&data->lock);
diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c
index 80f0b642b9b0..1c7d2eb054a2 100644
--- a/drivers/iio/accel/adxl367_i2c.c
+++ b/drivers/iio/accel/adxl367_i2c.c
@@ -68,7 +68,7 @@ MODULE_DEVICE_TABLE(i2c, adxl367_i2c_id);
static const struct of_device_id adxl367_of_match[] = {
{ .compatible = "adi,adxl367" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adxl367_of_match);
diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c
index 49d7c8fbe8ed..3fed56bb9054 100644
--- a/drivers/iio/accel/adxl367_spi.c
+++ b/drivers/iio/accel/adxl367_spi.c
@@ -139,13 +139,13 @@ static int adxl367_spi_probe(struct spi_device *spi)
static const struct spi_device_id adxl367_spi_id[] = {
{ "adxl367", 0 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(spi, adxl367_spi_id);
static const struct of_device_id adxl367_of_match[] = {
{ .compatible = "adi,adxl367" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adxl367_of_match);
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
index 43d5fd921be7..186d4fe9a556 100644
--- a/drivers/iio/accel/adxl372_i2c.c
+++ b/drivers/iio/accel/adxl372_i2c.c
@@ -43,7 +43,7 @@ static int adxl372_i2c_probe(struct i2c_client *client)
static const struct i2c_device_id adxl372_i2c_id[] = {
{ "adxl372" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
index 1ab1997a55b1..39941b519c3b 100644
--- a/drivers/iio/accel/adxl372_spi.c
+++ b/drivers/iio/accel/adxl372_spi.c
@@ -34,7 +34,7 @@ static int adxl372_spi_probe(struct spi_device *spi)
static const struct spi_device_id adxl372_spi_id[] = {
{ "adxl372", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
index aa664a923f91..93a868678722 100644
--- a/drivers/iio/accel/bma180.c
+++ b/drivers/iio/accel/bma180.c
@@ -887,7 +887,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
mutex_unlock(&data->mutex);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), time_ns);
err:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index 96ba028157ee..38f7498431ee 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -103,8 +103,8 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
mutex_unlock(&data->lock);
iio_trigger_notify_done(indio_dev->trig);
@@ -307,12 +307,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
static const struct spi_device_id bma220_spi_id[] = {
{"bma220", 0},
- {}
+ { }
};
static const struct acpi_device_id bma220_acpi_id[] = {
{"BMA0220", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bma220_spi_id);
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 23f5e1ce9cc4..85e23badf733 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -1591,8 +1591,9 @@ static irqreturn_t bma400_trigger_handler(int irq, void *p)
data->buffer.temperature = temp;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
+ sizeof(data->buffer),
+ iio_get_time_ns(indio_dev));
mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index 0d4ce6c38931..b4604f441553 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -240,7 +240,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BOSC0200"},
{"BSBA0150"},
{"DUAL250E"},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
@@ -255,7 +255,7 @@ static const struct i2c_device_id bmc150_accel_id[] = {
{"bmc150_accel"},
{"bmc156_accel", BOSCH_BMC156},
{"bmi055_accel"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
@@ -271,7 +271,7 @@ static const struct of_device_id bmc150_accel_of_match[] = {
{ .compatible = "bosch,bmc150_accel" },
{ .compatible = "bosch,bmc156_accel" },
{ .compatible = "bosch,bmi055_accel" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 70b3642656ab..26ce50b37716 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -48,7 +48,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
{"BMC150A"},
{"BMI055A"},
{"BSBA0150"},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
@@ -62,7 +62,7 @@ static const struct spi_device_id bmc150_accel_id[] = {
{"bmc150_accel"},
{"bmc156_accel", BOSCH_BMC156},
{"bmi055_accel"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c
index bd22bd0d3c25..310f863029bb 100644
--- a/drivers/iio/accel/bmi088-accel-i2c.c
+++ b/drivers/iio/accel/bmi088-accel-i2c.c
@@ -40,7 +40,7 @@ static const struct of_device_id bmi088_of_match[] = {
{ .compatible = "bosch,bmi085-accel" },
{ .compatible = "bosch,bmi088-accel" },
{ .compatible = "bosch,bmi090l-accel" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, bmi088_of_match);
@@ -48,7 +48,7 @@ static const struct i2c_device_id bmi088_accel_id[] = {
{ "bmi085-accel", BOSCH_BMI085 },
{ "bmi088-accel", BOSCH_BMI088 },
{ "bmi090l-accel", BOSCH_BMI090L },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmi088_accel_id);
diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c
index c9d51a74c07f..44cb50c76cb1 100644
--- a/drivers/iio/accel/bmi088-accel-spi.c
+++ b/drivers/iio/accel/bmi088-accel-spi.c
@@ -67,7 +67,7 @@ static const struct of_device_id bmi088_of_match[] = {
{ .compatible = "bosch,bmi085-accel" },
{ .compatible = "bosch,bmi088-accel" },
{ .compatible = "bosch,bmi090l-accel" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, bmi088_of_match);
@@ -75,7 +75,7 @@ static const struct spi_device_id bmi088_accel_id[] = {
{"bmi085-accel", BOSCH_BMI085},
{"bmi088-accel", BOSCH_BMI088},
{"bmi090l-accel", BOSCH_BMI090L},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bmi088_accel_id);
diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c
index 992286828844..c2dd123b9021 100644
--- a/drivers/iio/accel/da280.c
+++ b/drivers/iio/accel/da280.c
@@ -157,7 +157,7 @@ static const struct da280_match_data da280_match_data = { "da280", 3 };
static const struct acpi_device_id da280_acpi_match[] = {
{ "NSA2513", (kernel_ulong_t)&da217_match_data },
{ "MIRAACC", (kernel_ulong_t)&da280_match_data },
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
@@ -165,7 +165,7 @@ static const struct i2c_device_id da280_i2c_id[] = {
{ "da217", (kernel_ulong_t)&da217_match_data },
{ "da226", (kernel_ulong_t)&da226_match_data },
{ "da280", (kernel_ulong_t)&da280_match_data },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c
index 94f827acdd1c..e1df7b009d89 100644
--- a/drivers/iio/accel/da311.c
+++ b/drivers/iio/accel/da311.c
@@ -269,7 +269,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume);
static const struct i2c_device_id da311_i2c_id[] = {
{ "da311" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, da311_i2c_id);
diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c
index 35c0eefb741e..71cd1928baa6 100644
--- a/drivers/iio/accel/dmard10.c
+++ b/drivers/iio/accel/dmard10.c
@@ -232,7 +232,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend,
static const struct i2c_device_id dmard10_i2c_id[] = {
{ "dmard10" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id);
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index bf1d3923a181..12598feaa693 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -23,6 +23,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/types.h>
+#include <linux/units.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
@@ -439,8 +440,16 @@ static int fxls8962af_read_raw(struct iio_dev *indio_dev,
*val = FXLS8962AF_TEMP_CENTER_VAL;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = 0;
- return fxls8962af_read_full_scale(data, val2);
+ switch (chan->type) {
+ case IIO_TEMP:
+ *val = MILLIDEGREE_PER_DEGREE;
+ return IIO_VAL_INT;
+ case IIO_ACCEL:
+ *val = 0;
+ return fxls8962af_read_full_scale(data, val2);
+ default:
+ return -EINVAL;
+ }
case IIO_CHAN_INFO_SAMP_FREQ:
return fxls8962af_read_samp_freq(data, val, val2);
default:
@@ -736,9 +745,11 @@ static const struct iio_event_spec fxls8962af_event[] = {
.type = IIO_TEMP, \
.address = FXLS8962AF_TEMP_OUT, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET),\
.scan_index = -1, \
.scan_type = { \
+ .sign = 's', \
.realbits = 8, \
.storagebits = 8, \
}, \
@@ -983,8 +994,8 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
sizeof(data->scan.channels[0]));
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- tstamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan,
+ sizeof(data->scan), tstamp);
tstamp += sample_period;
}
diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c
index 1b9156b6b2e3..106198a12474 100644
--- a/drivers/iio/accel/fxls8962af-i2c.c
+++ b/drivers/iio/accel/fxls8962af-i2c.c
@@ -32,14 +32,14 @@ static const struct i2c_device_id fxls8962af_id[] = {
{ "fxls8964af", fxls8964af },
{ "fxls8967af", fxls8967af },
{ "fxls8974cf", fxls8974cf },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, fxls8962af_id);
static const struct of_device_id fxls8962af_of_match[] = {
{ .compatible = "nxp,fxls8962af" },
{ .compatible = "nxp,fxls8964af" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, fxls8962af_of_match);
diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c
index 46fc6e002714..bdafd1f615d9 100644
--- a/drivers/iio/accel/fxls8962af-spi.c
+++ b/drivers/iio/accel/fxls8962af-spi.c
@@ -30,14 +30,14 @@ static int fxls8962af_probe(struct spi_device *spi)
static const struct of_device_id fxls8962af_spi_of_match[] = {
{ .compatible = "nxp,fxls8962af" },
{ .compatible = "nxp,fxls8964af" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match);
static const struct spi_device_id fxls8962af_spi_id_table[] = {
{ "fxls8962af", fxls8962af },
{ "fxls8964af", fxls8964af },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 078fab2abb68..2ff591b3458f 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -228,7 +228,7 @@ static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
int len, int64_t timestamp)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, data, len, timestamp);
}
/* Callback handler to send event after all samples are received and captured */
@@ -440,7 +440,7 @@ static const struct platform_device_id hid_accel_3d_ids[] = {
{ /* gravity sensor */
.name = "HID-SENSOR-20007b",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index f2496cad8ec2..910d7b5716e1 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -674,8 +674,8 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
return 0;
}
-static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
- bool status)
+static int kxcjk1013_setup_interrupt(struct kxcjk1013_data *data,
+ bool status, bool is_new_data)
{
const struct kx_chipset_regs *regs = data->info->regs;
int ret;
@@ -690,69 +690,12 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
if (ret < 0)
return ret;
- ret = kxcjk1013_chip_update_thresholds(data);
- if (ret < 0)
- return ret;
-
- ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
- return ret;
- }
-
- if (status)
- ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEN;
- else
- ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
-
- ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
- return ret;
- }
-
- ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
- return ret;
- }
-
- if (status)
- ret |= KXCJK1013_REG_CTRL1_BIT_WUFE;
- else
- ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
-
- ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
- return ret;
- }
-
- if (store_mode == OPERATION) {
- ret = kxcjk1013_set_mode(data, OPERATION);
+ if (is_new_data == true) {
+ ret = kxcjk1013_chip_update_thresholds(data);
if (ret < 0)
return ret;
}
- return 0;
-}
-
-static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
- bool status)
-{
- const struct kx_chipset_regs *regs = data->info->regs;
- int ret;
- enum kxcjk1013_mode store_mode;
-
- ret = kxcjk1013_get_mode(data, &store_mode);
- if (ret < 0)
- return ret;
-
- /* This is requirement by spec to change state to STANDBY */
- ret = kxcjk1013_set_mode(data, STANDBY);
- if (ret < 0)
- return ret;
-
ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
@@ -776,10 +719,17 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
return ret;
}
- if (status)
- ret |= KXCJK1013_REG_CTRL1_BIT_DRDY;
- else
- ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
+ if (is_new_data) {
+ if (status)
+ ret |= KXCJK1013_REG_CTRL1_BIT_DRDY;
+ else
+ ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
+ } else {
+ if (status)
+ ret |= KXCJK1013_REG_CTRL1_BIT_WUFE;
+ else
+ ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
+ }
ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret);
if (ret < 0) {
@@ -1112,7 +1062,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev,
return ret;
}
- ret = kxcjk1013_setup_any_motion_interrupt(data, state);
+ ret = kxcjk1013_setup_interrupt(data, state, false);
if (ret < 0) {
kxcjk1013_set_power_state(data, false);
data->ev_enable_state = 0;
@@ -1253,8 +1203,8 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- data->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ data->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -1293,10 +1243,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
mutex_unlock(&data->mutex);
return ret;
}
- if (data->motion_trig == trig)
- ret = kxcjk1013_setup_any_motion_interrupt(data, state);
- else
- ret = kxcjk1013_setup_new_data_interrupt(data, state);
+ ret = kxcjk1013_setup_interrupt(data, state, data->motion_trig != trig);
if (ret < 0) {
kxcjk1013_set_power_state(data, false);
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c
index 3857d2edf250..1fa88b99149e 100644
--- a/drivers/iio/accel/kxsd9-i2c.c
+++ b/drivers/iio/accel/kxsd9-i2c.c
@@ -38,7 +38,7 @@ static void kxsd9_i2c_remove(struct i2c_client *client)
static const struct of_device_id kxsd9_of_match[] = {
{ .compatible = "kionix,kxsd9", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c
index a05f4467d94a..cbb6c6412665 100644
--- a/drivers/iio/accel/kxsd9-spi.c
+++ b/drivers/iio/accel/kxsd9-spi.c
@@ -38,7 +38,7 @@ static void kxsd9_spi_remove(struct spi_device *spi)
static const struct spi_device_id kxsd9_spi_id[] = {
{"kxsd9", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 0ededf8cfdca..cfc31265cdd0 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -229,9 +229,8 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
goto out;
}
- iio_push_to_buffers_with_timestamp(indio_dev,
- &hw_values,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &hw_values, sizeof(hw_values),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -273,7 +272,7 @@ kxsd9_get_mount_matrix(const struct iio_dev *indio_dev,
static const struct iio_chan_spec_ext_info kxsd9_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxsd9_get_mount_matrix),
- { },
+ { }
};
#define KXSD9_ACCEL_CHAN(axis, index) \
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
index 30746621052c..a2b5bdf14dde 100644
--- a/drivers/iio/accel/mma7455_core.c
+++ b/drivers/iio/accel/mma7455_core.c
@@ -103,8 +103,9 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p)
if (ret)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, &mma7455->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &mma7455->scan,
+ sizeof(mma7455->scan),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
index 2894aff80161..d0a16f227903 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -262,7 +262,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend,
static const struct i2c_device_id mma7660_i2c_id[] = {
{ "mma7660" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
@@ -274,7 +274,7 @@ MODULE_DEVICE_TABLE(of, mma7660_of_match);
static const struct acpi_device_id mma7660_acpi_id[] = {
{"MMA7660", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id);
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 05f5482f366e..aba444a980d9 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -1103,8 +1103,9 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
+ sizeof(data->buffer),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
index 1b96687da01a..b89bad9e6fe6 100644
--- a/drivers/iio/accel/mma9551.c
+++ b/drivers/iio/accel/mma9551.c
@@ -578,14 +578,14 @@ static const struct dev_pm_ops mma9551_pm_ops = {
static const struct acpi_device_id mma9551_acpi_match[] = {
{"MMA9551", 0},
- {},
+ { }
};
MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
static const struct i2c_device_id mma9551_id[] = {
{ "mma9551" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mma9551_id);
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 00e224efc8ed..1bbe660b254f 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -919,7 +919,7 @@ static const struct iio_enum mma9553_calibgender_enum = {
static const struct iio_chan_spec_ext_info mma9553_ext_info[] = {
IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum),
IIO_ENUM_AVAILABLE("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum),
- {},
+ { }
};
#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) { \
@@ -1216,14 +1216,14 @@ static const struct dev_pm_ops mma9553_pm_ops = {
static const struct acpi_device_id mma9553_acpi_match[] = {
{"MMA9553", 0},
- {},
+ { }
};
MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
static const struct i2c_device_id mma9553_id[] = {
{ "mma9553" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mma9553_id);
diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c
index d31c11fbbe68..c31c53abc3d0 100644
--- a/drivers/iio/accel/msa311.c
+++ b/drivers/iio/accel/msa311.c
@@ -919,8 +919,8 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p)
mutex_unlock(&msa311->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, &buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buf, sizeof(buf),
+ iio_get_time_ns(indio_dev));
notify_done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c
index cb5c4e354fc0..1075c8ce0e37 100644
--- a/drivers/iio/accel/mxc4005.c
+++ b/drivers/iio/accel/mxc4005.c
@@ -335,8 +335,8 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -573,14 +573,14 @@ static const struct acpi_device_id mxc4005_acpi_match[] = {
{"MXC4005", 0},
{"MXC6655", 0},
{"MDA6655", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
static const struct of_device_id mxc4005_of_match[] = {
{ .compatible = "memsic,mxc4005", },
{ .compatible = "memsic,mxc6655", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, mxc4005_of_match);
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index 3fb0f386c3db..aabe4491efd7 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -1541,7 +1541,7 @@ static const struct spi_device_id sca3000_id[] = {
{"sca3000_e02", e02},
{"sca3000_e04", e04},
{"sca3000_e05", e05},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, sca3000_id);
diff --git a/drivers/iio/accel/sca3300.c b/drivers/iio/accel/sca3300.c
index ca0ce83e42b2..67416a406e2f 100644
--- a/drivers/iio/accel/sca3300.c
+++ b/drivers/iio/accel/sca3300.c
@@ -58,15 +58,6 @@ enum sca3300_scan_indexes {
SCA3300_SCAN_MAX
};
-/*
- * Buffer size max case:
- * Three accel channels, two bytes per channel.
- * Temperature channel, two bytes.
- * Three incli channels, two bytes per channel.
- * Timestamp channel, eight bytes.
- */
-#define SCA3300_MAX_BUFFER_SIZE (ALIGN(sizeof(s16) * SCA3300_SCAN_MAX, sizeof(s64)) + sizeof(s64))
-
#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
@@ -193,9 +184,6 @@ struct sca3300_chip_info {
* @spi: SPI device structure
* @lock: Data buffer lock
* @chip: Sensor chip specific information
- * @buffer: Triggered buffer:
- * -SCA3300: 4 channel 16-bit data + 64-bit timestamp
- * -SCL3300: 7 channel 16-bit data + 64-bit timestamp
* @txbuf: Transmit buffer
* @rxbuf: Receive buffer
*/
@@ -203,7 +191,6 @@ struct sca3300_data {
struct spi_device *spi;
struct mutex lock;
const struct sca3300_chip_info *chip;
- u8 buffer[SCA3300_MAX_BUFFER_SIZE] __aligned(sizeof(s64));
u8 txbuf[4] __aligned(IIO_DMA_MINALIGN);
u8 rxbuf[4];
};
@@ -492,7 +479,7 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct sca3300_data *data = iio_priv(indio_dev);
int bit, ret, val, i = 0;
- s16 *channels = (s16 *)data->buffer;
+ IIO_DECLARE_BUFFER_WITH_TS(s16, channels, SCA3300_SCAN_MAX);
iio_for_each_active_channel(indio_dev, bit) {
ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val);
@@ -505,8 +492,8 @@ static irqreturn_t sca3300_trigger_handler(int irq, void *p)
channels[i++] = val;
}
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, channels, sizeof(channels),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -674,14 +661,14 @@ static int sca3300_probe(struct spi_device *spi)
static const struct of_device_id sca3300_dt_ids[] = {
{ .compatible = "murata,sca3300"},
{ .compatible = "murata,scl3300"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
static const struct spi_device_id sca3300_ids[] = {
{ "sca3300" },
{ "scl3300" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, sca3300_ids);
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index ab4fdba75a0a..f24449500533 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -126,14 +126,14 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,iis328dq",
.data = IIS328DQ_ACCEL_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
static const struct acpi_device_id st_accel_acpi_match[] = {
{"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME},
{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
@@ -164,7 +164,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303C_ACCEL_DEV_NAME },
{ SC7A20_ACCEL_DEV_NAME },
{ IIS328DQ_ACCEL_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 6146754fe47f..d8ec0555f42a 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -108,7 +108,7 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,iis328dq",
.data = IIS328DQ_ACCEL_DEV_NAME,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -167,7 +167,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LIS302DL_ACCEL_DEV_NAME },
{ LSM303C_ACCEL_DEV_NAME },
{ IIS328DQ_ACCEL_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index 471c154c3631..dfac2e44191f 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -460,8 +460,8 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
}
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -635,7 +635,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = {
/* Deprecated in favour of lowercase form */
{ "STK8312" },
{ "stk8312" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index cab592a68622..05d4fd540eb2 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -340,8 +340,8 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
data->scan.chans[i++] = ret;
}
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
mutex_unlock(&data->lock);
iio_trigger_notify_done(indio_dev->trig);
@@ -526,13 +526,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend,
static const struct i2c_device_id stk8ba50_i2c_id[] = {
{ "stk8ba50" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
static const struct acpi_device_id stk8ba50_acpi_id[] = {
{"STK8BA50", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id);
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 6529df1a498c..ea3ba1397392 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -6,6 +6,9 @@
menu "Analog to digital converters"
+config IIO_ADC_HELPER
+ tristate
+
config AB8500_GPADC
bool "ST-Ericsson AB8500 GPADC driver"
depends on AB8500_CORE && REGULATOR_AB8500
@@ -25,10 +28,15 @@ config AD4000
tristate "Analog Devices AD4000 ADC Driver"
depends on SPI
select IIO_BUFFER
+ select IIO_BUFFER_DMAENGINE
select IIO_TRIGGERED_BUFFER
+ select SPI_OFFLOAD
help
Say yes here to build support for Analog Devices AD4000 high speed
- SPI analog to digital converters (ADC).
+ SPI analog to digital converters (ADC). If intended to use with
+ SPI offloading support, it is recommended to enable
+ CONFIG_SPI_AXI_SPI_ENGINE, CONFIG_PWM_AXI_PWMGEN, and
+ CONFIG_SPI_OFFLOAD_TRIGGER_PWM.
To compile this driver as a module, choose M here: the module will be
called ad4000.
@@ -129,8 +137,9 @@ config AD7173
tristate "Analog Devices AD7173 driver"
depends on SPI_MASTER
select AD_SIGMA_DELTA
- select GPIO_REGMAP if GPIOLIB
- select REGMAP_SPI if GPIOLIB
+ select GPIOLIB
+ select GPIO_REGMAP
+ select REGMAP_SPI
help
Say yes here to build support for Analog Devices AD7173 and similar ADC
Currently supported models:
@@ -281,6 +290,8 @@ config AD7606_IFACE_SPI
tristate "Analog Devices AD7606 ADC driver with spi interface support"
depends on SPI
select AD7606
+ select IIO_BUFFER_DMAENGINE
+ select SPI_OFFLOAD
help
Say yes here to build spi interface support for Analog Devices:
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
@@ -319,6 +330,7 @@ config AD7766
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
+ select REGMAP_SPI
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
@@ -1092,6 +1104,17 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
+config NCT7201
+ tristate "Nuvoton Instruments NCT7201 and NCT7202 Power Monitor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Nuvoton NCT7201 and
+ NCT7202 Voltage Monitor.
+
+ This driver can also be built as a module. If so, the module
+ will be called nct7201.
+
config NPCM_ADC
tristate "Nuvoton NPCM ADC driver"
depends on ARCH_NPCM || COMPILE_TEST
@@ -1232,6 +1255,18 @@ config RN5T618_ADC
This driver can also be built as a module. If so, the module
will be called rn5t618-adc.
+config ROHM_BD79124
+ tristate "Rohm BD79124 ADC driver"
+ depends on I2C
+ select REGMAP_I2C
+ select IIO_ADC_HELPER
+ help
+ Say yes here to build support for the ROHM BD79124 ADC. The
+ ROHM BD79124 is a 12-bit, 8-channel, SAR ADC. The ADC supports
+ also an automatic measurement mode, with an alarm interrupt for
+ out-of-window measurements. The window is configurable for each
+ channel.
+
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST
@@ -1263,6 +1298,7 @@ config RICHTEK_RTQ6056
config RZG2L_ADC
tristate "Renesas RZ/G2L ADC driver"
depends on ARCH_RZG2L || COMPILE_TEST
+ select IIO_ADC_HELPER
help
Say yes here to build support for the ADC found in Renesas
RZ/G2L family.
@@ -1397,6 +1433,7 @@ config SUN4I_GPADC
config SUN20I_GPADC
tristate "Allwinner D1/T113s/T507/R329 and similar GPADCs driver"
depends on ARCH_SUNXI || COMPILE_TEST
+ select IIO_ADC_HELPER
help
Say yes here to build support for Allwinner (D1, T113, T507 and R329)
SoCs GPADC. This ADC provides up to 16 channels.
@@ -1440,18 +1477,6 @@ config TI_ADC084S021
This driver can also be built as a module. If so, the module will be
called ti-adc084s021.
-config TI_ADC12138
- tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
- depends on SPI
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- If you say yes here you get support for Texas Instruments ADC12130,
- ADC12132 and ADC12138 chips.
-
- This driver can also be built as a module. If so, the module will be
- called ti-adc12138.
-
config TI_ADC108S102
tristate "Texas Instruments ADC108S102 and ADC128S102 driver"
depends on SPI
@@ -1464,12 +1489,24 @@ config TI_ADC108S102
To compile this driver as a module, choose M here: the module will
be called ti-adc108s102.
+config TI_ADC12138
+ tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADC12130,
+ ADC12132 and ADC12138 chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-adc12138.
+
config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC128S052,
- ADC122S021 and ADC124S021 chips.
+ ADC122S021, ADC124S021 and ROHM Semiconductor BD79104 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
@@ -1499,6 +1536,16 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
+config TI_ADS1100
+ tristate "Texas Instruments ADS1100 and ADS1000 ADC"
+ depends on I2C
+ help
+ If you say yes here you get support for Texas Instruments ADS1100 and
+ ADS1000 ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads1100.
+
config TI_ADS1119
tristate "Texas Instruments ADS1119 ADC"
depends on I2C
@@ -1511,6 +1558,42 @@ config TI_ADS1119
This driver can also be built as a module. If so, the module will be
called ti-ads1119.
+config TI_ADS124S08
+ tristate "Texas Instruments ADS124S08"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADS124S08
+ and ADS124S06 ADC chips
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads124s08.
+
+config TI_ADS1298
+ tristate "Texas Instruments ADS1298"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ If you say yes here you get support for Texas Instruments ADS1298
+ medical ADC chips
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads1298.
+
+config TI_ADS131E08
+ tristate "Texas Instruments ADS131E08"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to get support for Texas Instruments ADS131E04, ADS131E06
+ and ADS131E08 chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads131e08.
+
config TI_ADS7138
tristate "Texas Instruments ADS7128 and ADS7138 ADC driver"
depends on I2C
@@ -1532,27 +1615,6 @@ config TI_ADS7924
This driver can also be built as a module. If so, the module will be
called ti-ads7924.
-config TI_ADS1100
- tristate "Texas Instruments ADS1100 and ADS1000 ADC"
- depends on I2C
- help
- If you say yes here you get support for Texas Instruments ADS1100 and
- ADS1000 ADC chips.
-
- This driver can also be built as a module. If so, the module will be
- called ti-ads1100.
-
-config TI_ADS1298
- tristate "Texas Instruments ADS1298"
- depends on SPI
- select IIO_BUFFER
- help
- If you say yes here you get support for Texas Instruments ADS1298
- medical ADC chips
-
- This driver can also be built as a module. If so, the module will be
- called ti-ads1298.
-
config TI_ADS7950
tristate "Texas Instruments ADS7950 ADC driver"
depends on SPI && GPIOLIB
@@ -1588,30 +1650,6 @@ config TI_ADS8688
This driver can also be built as a module. If so, the module will be
called ti-ads8688.
-config TI_ADS124S08
- tristate "Texas Instruments ADS124S08"
- depends on SPI
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- If you say yes here you get support for Texas Instruments ADS124S08
- and ADS124S06 ADC chips
-
- This driver can also be built as a module. If so, the module will be
- called ti-ads124s08.
-
-config TI_ADS131E08
- tristate "Texas Instruments ADS131E08"
- depends on SPI
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- Say yes here to get support for Texas Instruments ADS131E04, ADS131E06
- and ADS131E08 chips.
-
- This driver can also be built as a module. If so, the module will be
- called ti-ads131e08.
-
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC && HAS_DMA
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 3e918c3eec69..09ae6edb2650 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -3,6 +3,8 @@
# Makefile for IIO ADC drivers
#
+obj-$(CONFIG_IIO_ADC_HELPER) += industrialio-adc.o
+
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
@@ -97,6 +99,7 @@ obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
+obj-$(CONFIG_NCT7201) += nct7201.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
obj-$(CONFIG_PAC1921) += pac1921.o
obj-$(CONFIG_PAC1934) += pac1934.o
@@ -110,6 +113,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
+obj-$(CONFIG_ROHM_BD79124) += rohm-bd79124.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c
index 4fe8dee48da9..5609a7845b6f 100644
--- a/drivers/iio/adc/ad4000.c
+++ b/drivers/iio/adc/ad4000.c
@@ -15,12 +15,14 @@
#include <linux/mod_devicetable.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
+#include <linux/spi/offload/consumer.h>
#include <linux/spi/spi.h>
#include <linux/units.h>
#include <linux/util_macros.h>
-#include <linux/iio/iio.h>
+#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dmaengine.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
@@ -32,10 +34,11 @@
/* AD4000 Configuration Register programmable bits */
#define AD4000_CFG_SPAN_COMP BIT(3) /* Input span compression */
#define AD4000_CFG_HIGHZ BIT(2) /* High impedance mode */
+#define AD4000_CFG_TURBO BIT(1) /* Turbo mode */
#define AD4000_SCALE_OPTIONS 2
-#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access) \
+#define __AD4000_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access, _offl)\
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@@ -43,54 +46,65 @@
.channel = 0, \
.channel2 = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE), \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
.scan_index = 0, \
.scan_type = { \
.sign = _sign, \
.realbits = _real_bits, \
.storagebits = _storage_bits, \
- .shift = _storage_bits - _real_bits, \
- .endianness = IIO_BE, \
+ .shift = (_offl ? 0 : _storage_bits - _real_bits), \
+ .endianness = _offl ? IIO_CPU : IIO_BE \
}, \
}
-#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
+#define AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access, _offl) \
__AD4000_DIFF_CHANNEL((_sign), (_real_bits), \
- ((_real_bits) > 16 ? 32 : 16), (_reg_access))
+ (((_offl) || ((_real_bits) > 16)) ? 32 : 16), \
+ (_reg_access), (_offl))
+/*
+ * When SPI offload is configured, transfers are executed without CPU
+ * intervention so no soft timestamp can be recorded when transfers run.
+ * Because of that, the macros that set timestamp channel are only used when
+ * transfers are not offloaded.
+ */
#define AD4000_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
{ \
- AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
+ AD4000_DIFF_CHANNEL(_sign, _real_bits, _reg_access, 0), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}
-#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, _reg_access)\
+#define __AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _storage_bits, \
+ _reg_access, _offl) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_OFFSET), \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ (_offl ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0), \
.info_mask_separate_available = _reg_access ? BIT(IIO_CHAN_INFO_SCALE) : 0,\
.scan_index = 0, \
.scan_type = { \
.sign = _sign, \
.realbits = _real_bits, \
.storagebits = _storage_bits, \
- .shift = _storage_bits - _real_bits, \
- .endianness = IIO_BE, \
+ .shift = (_offl ? 0 : _storage_bits - _real_bits), \
+ .endianness = _offl ? IIO_CPU : IIO_BE \
}, \
}
-#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access) \
+#define AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access, _offl) \
__AD4000_PSEUDO_DIFF_CHANNEL((_sign), (_real_bits), \
- ((_real_bits) > 16 ? 32 : 16), (_reg_access))
+ (((_offl) || ((_real_bits) > 16)) ? 32 : 16),\
+ (_reg_access), (_offl))
#define AD4000_PSEUDO_DIFF_CHANNELS(_sign, _real_bits, _reg_access) \
{ \
- AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access), \
+ AD4000_PSEUDO_DIFF_CHANNEL(_sign, _real_bits, _reg_access, 0), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}
@@ -184,212 +198,298 @@ struct ad4000_chip_info {
const char *dev_name;
struct iio_chan_spec chan_spec[2];
struct iio_chan_spec reg_access_chan_spec[2];
+ struct iio_chan_spec offload_chan_spec;
+ struct iio_chan_spec reg_access_offload_chan_spec;
const struct ad4000_time_spec *time_spec;
bool has_hardware_gain;
+ int max_rate_hz;
};
static const struct ad4000_chip_info ad4000_chip_info = {
.dev_name = "ad4000",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info ad4001_chip_info = {
.dev_name = "ad4001",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info ad4002_chip_info = {
.dev_name = "ad4002",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info ad4003_chip_info = {
.dev_name = "ad4003",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info ad4004_chip_info = {
.dev_name = "ad4004",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad4005_chip_info = {
.dev_name = "ad4005",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad4006_chip_info = {
.dev_name = "ad4006",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad4007_chip_info = {
.dev_name = "ad4007",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad4008_chip_info = {
.dev_name = "ad4008",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad4010_chip_info = {
.dev_name = "ad4010",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 0),
.reg_access_chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 18, 1),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad4011_chip_info = {
.dev_name = "ad4011",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1),
.time_spec = &ad4000_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad4020_chip_info = {
.dev_name = "ad4020",
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1),
.time_spec = &ad4020_t_spec,
+ .max_rate_hz = 1800 * KILO,
};
static const struct ad4000_chip_info ad4021_chip_info = {
.dev_name = "ad4021",
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1),
.time_spec = &ad4020_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad4022_chip_info = {
.dev_name = "ad4022",
.chan_spec = AD4000_DIFF_CHANNELS('s', 20, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 20, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 20, 1, 1),
.time_spec = &ad4020_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info adaq4001_chip_info = {
.dev_name = "adaq4001",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 16, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 1, 1),
.time_spec = &ad4000_t_spec,
.has_hardware_gain = true,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info adaq4003_chip_info = {
.dev_name = "adaq4003",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
.reg_access_chan_spec = AD4000_DIFF_CHANNELS('s', 18, 1),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
+ .reg_access_offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 1, 1),
.time_spec = &ad4000_t_spec,
.has_hardware_gain = true,
+ .max_rate_hz = 2 * MEGA,
};
static const struct ad4000_chip_info ad7685_chip_info = {
.dev_name = "ad7685",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7687_t_spec,
+ .max_rate_hz = 250 * KILO,
};
static const struct ad4000_chip_info ad7686_chip_info = {
.dev_name = "ad7686",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7686_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad7687_chip_info = {
.dev_name = "ad7687",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
.time_spec = &ad7687_t_spec,
+ .max_rate_hz = 250 * KILO,
};
static const struct ad4000_chip_info ad7688_chip_info = {
.dev_name = "ad7688",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
.time_spec = &ad7686_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad7690_chip_info = {
.dev_name = "ad7690",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
.time_spec = &ad7690_t_spec,
+ .max_rate_hz = 400 * KILO,
};
static const struct ad4000_chip_info ad7691_chip_info = {
.dev_name = "ad7691",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
.time_spec = &ad7691_t_spec,
+ .max_rate_hz = 250 * KILO,
};
static const struct ad4000_chip_info ad7693_chip_info = {
.dev_name = "ad7693",
.chan_spec = AD4000_DIFF_CHANNELS('s', 16, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 16, 0, 1),
.time_spec = &ad7686_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad7942_chip_info = {
.dev_name = "ad7942",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 14, 0, 1),
.time_spec = &ad7687_t_spec,
+ .max_rate_hz = 250 * KILO,
};
static const struct ad4000_chip_info ad7946_chip_info = {
.dev_name = "ad7946",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 14, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 14, 0, 1),
.time_spec = &ad7686_t_spec,
+ .max_rate_hz = 500 * KILO,
};
static const struct ad4000_chip_info ad7980_chip_info = {
.dev_name = "ad7980",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7980_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad7982_chip_info = {
.dev_name = "ad7982",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
.time_spec = &ad7980_t_spec,
+ .max_rate_hz = 1 * MEGA,
};
static const struct ad4000_chip_info ad7983_chip_info = {
.dev_name = "ad7983",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7983_t_spec,
+ .max_rate_hz = 1 * MEGA + 333 * KILO + 333,
};
static const struct ad4000_chip_info ad7984_chip_info = {
.dev_name = "ad7984",
.chan_spec = AD4000_DIFF_CHANNELS('s', 18, 0),
+ .offload_chan_spec = AD4000_DIFF_CHANNEL('s', 18, 0, 1),
.time_spec = &ad7983_t_spec,
+ .max_rate_hz = 1 * MEGA + 333 * KILO + 333,
};
static const struct ad4000_chip_info ad7988_1_chip_info = {
.dev_name = "ad7988-1",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7988_1_t_spec,
+ .max_rate_hz = 100 * KILO,
};
static const struct ad4000_chip_info ad7988_5_chip_info = {
.dev_name = "ad7988-5",
.chan_spec = AD4000_PSEUDO_DIFF_CHANNELS('u', 16, 0),
+ .offload_chan_spec = AD4000_PSEUDO_DIFF_CHANNEL('u', 16, 0, 1),
.time_spec = &ad7686_t_spec,
+ .max_rate_hz = 500 * KILO,
+};
+
+static const struct spi_offload_config ad4000_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
};
struct ad4000_state {
@@ -397,6 +497,13 @@ struct ad4000_state {
struct gpio_desc *cnv_gpio;
struct spi_transfer xfers[2];
struct spi_message msg;
+ struct spi_transfer offload_xfer;
+ struct spi_message offload_msg;
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
+ bool using_offload;
+ unsigned long offload_trigger_hz;
+ int max_rate_hz;
struct mutex lock; /* Protect read modify write cycle */
int vref_mv;
enum ad4000_sdi sdi_pin;
@@ -411,8 +518,10 @@ struct ad4000_state {
*/
struct {
union {
- __be16 sample_buf16;
- __be32 sample_buf32;
+ __be16 sample_buf16_be;
+ __be32 sample_buf32_be;
+ u16 sample_buf16;
+ u32 sample_buf32;
} data;
aligned_s64 timestamp;
} scan __aligned(IIO_DMA_MINALIGN);
@@ -487,6 +596,25 @@ static int ad4000_read_reg(struct ad4000_state *st, unsigned int *val)
return ret;
}
+static int ad4000_set_sampling_freq(struct ad4000_state *st, int freq)
+{
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_PERIODIC,
+ .periodic = {
+ .frequency_hz = freq,
+ },
+ };
+ int ret;
+
+ ret = spi_offload_trigger_validate(st->offload_trigger, &config);
+ if (ret)
+ return ret;
+
+ st->offload_trigger_hz = config.periodic.frequency_hz;
+
+ return 0;
+}
+
static int ad4000_convert_and_acquire(struct ad4000_state *st)
{
int ret;
@@ -515,10 +643,17 @@ static int ad4000_single_conversion(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- if (chan->scan_type.storagebits > 16)
- sample = be32_to_cpu(st->scan.data.sample_buf32);
- else
- sample = be16_to_cpu(st->scan.data.sample_buf16);
+ if (chan->scan_type.endianness == IIO_BE) {
+ if (chan->scan_type.realbits > 16)
+ sample = be32_to_cpu(st->scan.data.sample_buf32_be);
+ else
+ sample = be16_to_cpu(st->scan.data.sample_buf16_be);
+ } else {
+ if (chan->scan_type.realbits > 16)
+ sample = st->scan.data.sample_buf32;
+ else
+ sample = st->scan.data.sample_buf16;
+ }
sample >>= chan->scan_type.shift;
@@ -555,6 +690,9 @@ static int ad4000_read_raw(struct iio_dev *indio_dev,
*val = mult_frac(st->vref_mv, 1, 10);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = st->offload_trigger_hz;
+ return IIO_VAL_INT;
default:
return -EINVAL;
}
@@ -620,6 +758,7 @@ static int ad4000_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
+ struct ad4000_state *st = iio_priv(indio_dev);
int ret;
switch (mask) {
@@ -629,6 +768,15 @@ static int ad4000_write_raw(struct iio_dev *indio_dev,
ret = __ad4000_write_raw(indio_dev, chan, val2);
iio_device_release_direct(indio_dev);
return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val < 1 || val > st->max_rate_hz)
+ return -EINVAL;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad4000_set_sampling_freq(st, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
default:
return -EINVAL;
}
@@ -645,7 +793,8 @@ static irqreturn_t ad4000_trigger_handler(int irq, void *p)
if (ret < 0)
goto err_out;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+ pf->timestamp);
err_out:
iio_trigger_notify_done(indio_dev->trig);
@@ -659,10 +808,114 @@ static const struct iio_info ad4000_reg_access_info = {
.write_raw_get_fmt = &ad4000_write_raw_get_fmt,
};
+static const struct iio_info ad4000_offload_info = {
+ .read_raw = &ad4000_read_raw,
+ .write_raw = &ad4000_write_raw,
+ .write_raw_get_fmt = &ad4000_write_raw_get_fmt,
+};
+
static const struct iio_info ad4000_info = {
.read_raw = &ad4000_read_raw,
};
+static int ad4000_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_PERIODIC,
+ .periodic = {
+ .frequency_hz = st->offload_trigger_hz,
+ },
+ };
+
+ return spi_offload_trigger_enable(st->offload, st->offload_trigger,
+ &config);
+}
+
+static int ad4000_offload_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4000_state *st = iio_priv(indio_dev);
+
+ spi_offload_trigger_disable(st->offload, st->offload_trigger);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad4000_offload_buffer_setup_ops = {
+ .postenable = &ad4000_offload_buffer_postenable,
+ .predisable = &ad4000_offload_buffer_predisable,
+};
+
+static int ad4000_spi_offload_setup(struct iio_dev *indio_dev,
+ struct ad4000_state *st)
+{
+ struct spi_device *spi = st->spi;
+ struct device *dev = &spi->dev;
+ struct dma_chan *rx_dma;
+ int ret;
+
+ st->offload_trigger = devm_spi_offload_trigger_get(dev, st->offload,
+ SPI_OFFLOAD_TRIGGER_PERIODIC);
+ if (IS_ERR(st->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(st->offload_trigger),
+ "Failed to get offload trigger\n");
+
+ ret = ad4000_set_sampling_freq(st, st->max_rate_hz);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set sampling frequency\n");
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev, st->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma),
+ "Failed to get offload RX DMA\n");
+
+ ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev, rx_dma,
+ IIO_BUFFER_DIRECTION_IN);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup DMA buffer\n");
+
+ return 0;
+}
+
+/*
+ * This executes a data sample transfer when using SPI offloading. The device
+ * connections should be in "3-wire" mode, selected either when the adi,sdi-pin
+ * device tree property is absent or set to "high". Also, the ADC CNV pin must
+ * be connected to a SPI controller CS (it can't be connected to a GPIO).
+ *
+ * In order to achieve the maximum sample rate, we only do one transfer per
+ * SPI offload trigger. Because the ADC output has a one sample latency (delay)
+ * when the device is wired in "3-wire" mode and only one transfer per sample is
+ * being made in turbo mode, the first data sample is not valid because it
+ * contains the output of an earlier conversion result. We also set transfer
+ * `bits_per_word` to achieve higher throughput by using the minimum number of
+ * SCLK cycles. Also, a delay is added to make sure we meet the minimum quiet
+ * time before releasing the CS line.
+ *
+ * Note that, with `bits_per_word` set to the number of ADC precision bits,
+ * transfers use larger word sizes that get stored in 'in-memory wordsizes' that
+ * are always in native CPU byte order. Because of that, IIO buffer elements
+ * ought to be read in CPU endianness which requires setting IIO scan_type
+ * endianness accordingly (i.e. IIO_CPU).
+ */
+static int ad4000_prepare_offload_message(struct ad4000_state *st,
+ const struct iio_chan_spec *chan)
+{
+ struct spi_transfer *xfer = &st->offload_xfer;
+
+ xfer->bits_per_word = chan->scan_type.realbits;
+ xfer->len = chan->scan_type.realbits > 16 ? 4 : 2;
+ xfer->delay.value = st->time_spec->t_quiet2_ns;
+ xfer->delay.unit = SPI_DELAY_UNIT_NSECS;
+ xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+
+ spi_message_init_with_transfers(&st->offload_msg, xfer, 1);
+ st->offload_msg.offload = st->offload;
+
+ return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->offload_msg);
+}
+
/*
* This executes a data sample transfer for when the device connections are
* in "3-wire" mode, selected when the adi,sdi-pin device tree property is
@@ -689,7 +942,16 @@ static int ad4000_prepare_3wire_mode_message(struct ad4000_state *st,
xfers[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
xfers[1].rx_buf = &st->scan.data;
- xfers[1].len = BITS_TO_BYTES(chan->scan_type.storagebits);
+ xfers[1].len = chan->scan_type.realbits > 16 ? 4 : 2;
+
+ /*
+ * If the device is set up for SPI offloading, IIO channel scan_type is
+ * set to IIO_CPU. When that is the case, use larger SPI word sizes for
+ * single-shot reads too. Thus, sample data can be correctly handled in
+ * ad4000_single_conversion() according to scan_type endianness.
+ */
+ if (chan->scan_type.endianness != IIO_BE)
+ xfers[1].bits_per_word = chan->scan_type.realbits;
xfers[1].delay.value = st->time_spec->t_quiet2_ns;
xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS;
@@ -733,6 +995,9 @@ static int ad4000_config(struct ad4000_state *st)
if (device_property_present(&st->spi->dev, "adi,high-z-input"))
reg_val |= FIELD_PREP(AD4000_CFG_HIGHZ, 1);
+ if (st->using_offload)
+ reg_val |= FIELD_PREP(AD4000_CFG_TURBO, 1);
+
return ad4000_write_reg(st, reg_val);
}
@@ -755,6 +1020,7 @@ static int ad4000_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->spi = spi;
st->time_spec = chip->time_spec;
+ st->max_rate_hz = chip->max_rate_hz;
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4000_power_supplies),
ad4000_power_supplies);
@@ -772,6 +1038,26 @@ static int ad4000_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(st->cnv_gpio),
"Failed to get CNV GPIO");
+ st->offload = devm_spi_offload_get(dev, spi, &ad4000_offload_config);
+ ret = PTR_ERR_OR_ZERO(st->offload);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get offload\n");
+
+ st->using_offload = !IS_ERR(st->offload);
+ if (st->using_offload) {
+ indio_dev->setup_ops = &ad4000_offload_buffer_setup_ops;
+ ret = ad4000_spi_offload_setup(indio_dev, st);
+ if (ret)
+ return ret;
+ } else {
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad4000_trigger_handler,
+ NULL);
+ if (ret)
+ return ret;
+ }
+
ret = device_property_match_property_string(dev, "adi,sdi-pin",
ad4000_sdi_pin,
ARRAY_SIZE(ad4000_sdi_pin));
@@ -784,7 +1070,6 @@ static int ad4000_probe(struct spi_device *spi)
switch (st->sdi_pin) {
case AD4000_SDI_MOSI:
indio_dev->info = &ad4000_reg_access_info;
- indio_dev->channels = chip->reg_access_chan_spec;
/*
* In "3-wire mode", the ADC SDI line must be kept high when
@@ -796,9 +1081,26 @@ static int ad4000_probe(struct spi_device *spi)
if (ret < 0)
return ret;
+ if (st->using_offload) {
+ indio_dev->channels = &chip->reg_access_offload_chan_spec;
+ indio_dev->num_channels = 1;
+ ret = ad4000_prepare_offload_message(st, indio_dev->channels);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI msg\n");
+ } else {
+ indio_dev->channels = chip->reg_access_chan_spec;
+ indio_dev->num_channels = ARRAY_SIZE(chip->reg_access_chan_spec);
+ }
+
+ /*
+ * Call ad4000_prepare_3wire_mode_message() so single-shot read
+ * SPI messages are always initialized.
+ */
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI msg\n");
ret = ad4000_config(st);
if (ret < 0)
@@ -806,19 +1108,38 @@ static int ad4000_probe(struct spi_device *spi)
break;
case AD4000_SDI_VIO:
- indio_dev->info = &ad4000_info;
- indio_dev->channels = chip->chan_spec;
+ if (st->using_offload) {
+ indio_dev->info = &ad4000_offload_info;
+ indio_dev->channels = &chip->offload_chan_spec;
+ indio_dev->num_channels = 1;
+
+ ret = ad4000_prepare_offload_message(st, indio_dev->channels);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI msg\n");
+ } else {
+ indio_dev->info = &ad4000_info;
+ indio_dev->channels = chip->chan_spec;
+ indio_dev->num_channels = ARRAY_SIZE(chip->chan_spec);
+ }
+
ret = ad4000_prepare_3wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI msg\n");
break;
case AD4000_SDI_CS:
+ if (st->using_offload)
+ return dev_err_probe(dev, -EPROTONOSUPPORT,
+ "Unsupported sdi-pin + offload config\n");
indio_dev->info = &ad4000_info;
indio_dev->channels = chip->chan_spec;
+ indio_dev->num_channels = ARRAY_SIZE(chip->chan_spec);
ret = ad4000_prepare_4wire_mode_message(st, &indio_dev->channels[0]);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "Failed to optimize SPI msg\n");
break;
case AD4000_SDI_GND:
@@ -830,7 +1151,6 @@ static int ad4000_probe(struct spi_device *spi)
}
indio_dev->name = chip->dev_name;
- indio_dev->num_channels = 2;
ret = devm_mutex_init(dev, &st->lock);
if (ret)
@@ -853,12 +1173,6 @@ static int ad4000_probe(struct spi_device *spi)
ad4000_fill_scale_tbl(st, &indio_dev->channels[0]);
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
- &iio_pollfunc_store_time,
- &ad4000_trigger_handler, NULL);
- if (ret)
- return ret;
-
return devm_iio_device_register(dev, indio_dev);
}
@@ -947,3 +1261,4 @@ module_spi_driver(ad4000_driver);
MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD4000 ADC driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c
index 9a020680885d..1bc2f9a22470 100644
--- a/drivers/iio/adc/ad4030.c
+++ b/drivers/iio/adc/ad4030.c
@@ -147,7 +147,6 @@ struct ad4030_state {
struct spi_device *spi;
struct regmap *regmap;
const struct ad4030_chip_info *chip;
- const struct iio_scan_type *current_scan_type;
struct gpio_desc *cnv_gpio;
int vref_uv;
int vio_uv;
@@ -245,7 +244,6 @@ static int ad4030_enter_config_mode(struct ad4030_state *st)
struct spi_transfer xfer = {
.tx_buf = st->tx_data,
- .bits_per_word = 8,
.len = 1,
.speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED,
};
@@ -261,7 +259,6 @@ static int ad4030_exit_config_mode(struct ad4030_state *st)
struct spi_transfer xfer = {
.tx_buf = st->tx_data,
- .bits_per_word = 8,
.len = 3,
.speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED,
};
@@ -277,7 +274,6 @@ static int ad4030_spi_read(void *context, const void *reg, size_t reg_size,
struct spi_transfer xfer = {
.tx_buf = st->tx_data,
.rx_buf = st->rx_data.raw,
- .bits_per_word = 8,
.len = reg_size + val_size,
.speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED,
};
@@ -312,7 +308,6 @@ static int ad4030_spi_write(void *context, const void *data, size_t count)
((u8 *)data)[2] == 0x81;
struct spi_transfer xfer = {
.tx_buf = st->tx_data,
- .bits_per_word = 8,
.len = count,
.speed_hz = AD4030_SPI_MAX_REG_XFER_SPEED,
};
@@ -390,16 +385,17 @@ static int ad4030_get_chan_scale(struct iio_dev *indio_dev,
struct ad4030_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
- if (chan->differential) {
- scan_type = iio_get_current_scan_type(indio_dev,
- st->chip->channels);
+ scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ if (chan->differential)
*val = (st->vref_uv * 2) / MILLI;
- *val2 = scan_type->realbits;
- return IIO_VAL_FRACTIONAL_LOG2;
- }
+ else
+ *val = st->vref_uv / MILLI;
+
+ *val2 = scan_type->realbits;
- *val = st->vref_uv / MILLI;
- *val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
@@ -561,11 +557,6 @@ static int ad4030_set_mode(struct iio_dev *indio_dev, unsigned long mask)
st->mode = AD4030_OUT_DATA_MD_DIFF;
}
- st->current_scan_type = iio_get_current_scan_type(indio_dev,
- st->chip->channels);
- if (IS_ERR(st->current_scan_type))
- return PTR_ERR(st->current_scan_type);
-
return regmap_update_bits(st->regmap, AD4030_REG_MODES,
AD4030_REG_MODES_MASK_OUT_DATA_MODE,
st->mode);
@@ -613,15 +604,20 @@ static void ad4030_extract_interleaved(u8 *src, u32 *ch0, u32 *ch1)
static int ad4030_conversion(struct iio_dev *indio_dev)
{
struct ad4030_state *st = iio_priv(indio_dev);
- unsigned char diff_realbytes =
- BITS_TO_BYTES(st->current_scan_type->realbits);
- unsigned char diff_storagebytes =
- BITS_TO_BYTES(st->current_scan_type->storagebits);
+ const struct iio_scan_type *scan_type;
+ unsigned char diff_realbytes, diff_storagebytes;
unsigned int bytes_to_read;
unsigned long cnv_nb = BIT(st->avg_log2);
unsigned int i;
int ret;
+ scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ diff_realbytes = BITS_TO_BYTES(scan_type->realbits);
+ diff_storagebytes = BITS_TO_BYTES(scan_type->storagebits);
+
/* Number of bytes for one differential channel */
bytes_to_read = diff_realbytes;
/* Add one byte if we are using a differential + common byte mode */
@@ -646,6 +642,12 @@ static int ad4030_conversion(struct iio_dev *indio_dev)
&st->rx_data.dual.diff[0],
&st->rx_data.dual.diff[1]);
+ /*
+ * If no common mode voltage channel is enabled, we can use the raw
+ * data as is. Otherwise, we need to rearrange the data a bit to match
+ * the natural alignment of the IIO buffer.
+ */
+
if (st->mode != AD4030_OUT_DATA_MD_16_DIFF_8_COM &&
st->mode != AD4030_OUT_DATA_MD_24_DIFF_8_COM)
return 0;
@@ -672,11 +674,6 @@ static int ad4030_single_conversion(struct iio_dev *indio_dev,
if (ret)
return ret;
- st->current_scan_type = iio_get_current_scan_type(indio_dev,
- st->chip->channels);
- if (IS_ERR(st->current_scan_type))
- return PTR_ERR(st->current_scan_type);
-
ret = ad4030_conversion(indio_dev);
if (ret)
return ret;
@@ -706,8 +703,8 @@ static irqreturn_t ad4030_trigger_handler(int irq, void *p)
if (ret)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, st->rx_data.raw,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &st->rx_data, sizeof(st->rx_data),
+ pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -867,6 +864,12 @@ static int ad4030_get_current_scan_type(const struct iio_dev *indio_dev,
return st->avg_log2 ? AD4030_SCAN_TYPE_AVG : AD4030_SCAN_TYPE_NORMAL;
}
+static int ad4030_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ return ad4030_set_mode(indio_dev, *scan_mask);
+}
+
static const struct iio_info ad4030_iio_info = {
.read_avail = ad4030_read_avail,
.read_raw = ad4030_read_raw,
@@ -874,13 +877,9 @@ static const struct iio_info ad4030_iio_info = {
.debugfs_reg_access = ad4030_reg_access,
.read_label = ad4030_read_label,
.get_current_scan_type = ad4030_get_current_scan_type,
+ .update_scan_mode = ad4030_update_scan_mode,
};
-static int ad4030_buffer_preenable(struct iio_dev *indio_dev)
-{
- return ad4030_set_mode(indio_dev, *indio_dev->active_scan_mask);
-}
-
static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
@@ -894,7 +893,6 @@ static bool ad4030_validate_scan_mask(struct iio_dev *indio_dev,
}
static const struct iio_buffer_setup_ops ad4030_buffer_setup_ops = {
- .preenable = ad4030_buffer_preenable,
.validate_scan_mask = ad4030_validate_scan_mask,
};
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index 0f4c9cd6c102..6cf790ff3eb5 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -522,15 +522,15 @@ static int ad4130_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
return GPIO_LINE_DIRECTION_OUT;
}
-static void ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
- int value)
+static int ad4130_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
{
struct ad4130_state *st = gpiochip_get_data(gc);
unsigned int mask = FIELD_PREP(AD4130_IO_CONTROL_GPIO_DATA_MASK,
BIT(offset));
- regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
- value ? mask : 0);
+ return regmap_update_bits(st->regmap, AD4130_IO_CONTROL_REG, mask,
+ value ? mask : 0);
}
static int ad4130_set_mode(struct ad4130_state *st, enum ad4130_mode mode)
@@ -2064,7 +2064,7 @@ static int ad4130_probe(struct spi_device *spi)
st->gc.can_sleep = true;
st->gc.init_valid_mask = ad4130_gpio_init_valid_mask;
st->gc.get_direction = ad4130_gpio_get_direction;
- st->gc.set = ad4130_gpio_set;
+ st->gc.set_rv = ad4130_gpio_set;
ret = devm_gpiochip_add_data(dev, &st->gc, st);
if (ret)
diff --git a/drivers/iio/adc/ad4695.c b/drivers/iio/adc/ad4695.c
index 8222c8ab2940..cda419638d9a 100644
--- a/drivers/iio/adc/ad4695.c
+++ b/drivers/iio/adc/ad4695.c
@@ -105,9 +105,7 @@
#define AD4695_REG_ACCESS_SCLK_HZ (10 * MEGA)
/* Max number of voltage input channels. */
-#define AD4695_MAX_CHANNELS 16
-/* Max size of 1 raw sample in bytes. */
-#define AD4695_MAX_CHANNEL_SIZE 2
+#define AD4695_MAX_VIN_CHANNELS 16
enum ad4695_in_pair {
AD4695_IN_PAIR_REFGND,
@@ -145,8 +143,8 @@ struct ad4695_state {
/* offload also requires separate gpio to manually control CNV */
struct gpio_desc *cnv_gpio;
/* voltages channels plus temperature and timestamp */
- struct iio_chan_spec iio_chan[AD4695_MAX_CHANNELS + 2];
- struct ad4695_channel_config channels_cfg[AD4695_MAX_CHANNELS];
+ struct iio_chan_spec iio_chan[AD4695_MAX_VIN_CHANNELS + 2];
+ struct ad4695_channel_config channels_cfg[AD4695_MAX_VIN_CHANNELS];
const struct ad4695_chip_info *chip_info;
int sample_freq_range[3];
/* Reference voltage. */
@@ -159,11 +157,10 @@ struct ad4695_state {
* to control CS and add a delay between the last SCLK and next
* CNV rising edges.
*/
- struct spi_transfer buf_read_xfer[AD4695_MAX_CHANNELS * 2 + 3];
+ struct spi_transfer buf_read_xfer[AD4695_MAX_VIN_CHANNELS * 2 + 3];
struct spi_message buf_read_msg;
/* Raw conversion data received. */
- u8 buf[ALIGN((AD4695_MAX_CHANNELS + 2) * AD4695_MAX_CHANNEL_SIZE,
- sizeof(s64)) + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
+ IIO_DECLARE_DMA_BUFFER_WITH_TS(u16, buf, AD4695_MAX_VIN_CHANNELS + 1);
u16 raw_data;
/* Commands to send for single conversion. */
u16 cnv_cmd;
@@ -660,9 +657,8 @@ static int ad4695_buffer_preenable(struct iio_dev *indio_dev)
iio_for_each_active_channel(indio_dev, bit) {
xfer = &st->buf_read_xfer[num_xfer];
xfer->bits_per_word = 16;
- xfer->rx_buf = &st->buf[rx_buf_offset];
+ xfer->rx_buf = &st->buf[rx_buf_offset++];
xfer->len = 2;
- rx_buf_offset += xfer->len;
if (bit == temp_chan_bit) {
temp_en = 1;
@@ -801,7 +797,8 @@ static irqreturn_t ad4695_trigger_handler(int irq, void *p)
if (ret)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, st->buf, pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, st->buf, sizeof(st->buf),
+ pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c
index 98ebc853db79..f1d2e2896f2a 100644
--- a/drivers/iio/adc/ad4851.c
+++ b/drivers/iio/adc/ad4851.c
@@ -1034,7 +1034,7 @@ static int ad4858_parse_channels(struct iio_dev *indio_dev)
struct device *dev = &st->spi->dev;
struct iio_chan_spec *ad4851_channels;
const struct iio_chan_spec ad4851_chan = AD4858_IIO_CHANNEL;
- int ret;
+ int ret, i = 0;
ret = ad4851_parse_channels_common(indio_dev, &ad4851_channels,
ad4851_chan);
@@ -1042,15 +1042,15 @@ static int ad4858_parse_channels(struct iio_dev *indio_dev)
return ret;
device_for_each_child_node_scoped(dev, child) {
- ad4851_channels->has_ext_scan_type = 1;
+ ad4851_channels[i].has_ext_scan_type = 1;
if (fwnode_property_read_bool(child, "bipolar")) {
- ad4851_channels->ext_scan_type = ad4851_scan_type_20_b;
- ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b);
+ ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_b;
+ ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b);
} else {
- ad4851_channels->ext_scan_type = ad4851_scan_type_20_u;
- ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u);
+ ad4851_channels[i].ext_scan_type = ad4851_scan_type_20_u;
+ ad4851_channels[i].num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u);
}
- ad4851_channels++;
+ i++;
}
indio_dev->channels = ad4851_channels;
diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
index 931ff71b2888..647a7852dd8d 100644
--- a/drivers/iio/adc/ad7091r-base.c
+++ b/drivers/iio/adc/ad7091r-base.c
@@ -387,13 +387,8 @@ EXPORT_SYMBOL_NS_GPL(ad7091r_writeable_reg, "IIO_AD7091R");
bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
{
- switch (reg) {
- case AD7091R_REG_RESULT:
- case AD7091R_REG_ALERT:
- return true;
- default:
- return false;
- }
+ /* The volatile ad7091r registers are also the only RO ones. */
+ return !ad7091r_writeable_reg(dev, reg);
}
EXPORT_SYMBOL_NS_GPL(ad7091r_volatile_reg, "IIO_AD7091R");
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 3ea81a98e455..92596f15e797 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -32,7 +32,7 @@
#define AD7124_IO_CONTROL_2 0x04
#define AD7124_ID 0x05
#define AD7124_ERROR 0x06
-#define AD7124_ERROR_EN 0x07
+#define AD7124_ERROR_EN 0x07
#define AD7124_MCLK_COUNT 0x08
#define AD7124_CHANNEL(x) (0x09 + (x))
#define AD7124_CONFIG(x) (0x19 + (x))
@@ -41,68 +41,58 @@
#define AD7124_GAIN(x) (0x31 + (x))
/* AD7124_STATUS */
-#define AD7124_STATUS_POR_FLAG_MSK BIT(4)
+#define AD7124_STATUS_POR_FLAG BIT(4)
/* AD7124_ADC_CONTROL */
-#define AD7124_ADC_STATUS_EN_MSK BIT(10)
-#define AD7124_ADC_STATUS_EN(x) FIELD_PREP(AD7124_ADC_STATUS_EN_MSK, x)
-#define AD7124_ADC_CTRL_REF_EN_MSK BIT(8)
-#define AD7124_ADC_CTRL_REF_EN(x) FIELD_PREP(AD7124_ADC_CTRL_REF_EN_MSK, x)
-#define AD7124_ADC_CTRL_PWR_MSK GENMASK(7, 6)
-#define AD7124_ADC_CTRL_PWR(x) FIELD_PREP(AD7124_ADC_CTRL_PWR_MSK, x)
-#define AD7124_ADC_CTRL_MODE_MSK GENMASK(5, 2)
-#define AD7124_ADC_CTRL_MODE(x) FIELD_PREP(AD7124_ADC_CTRL_MODE_MSK, x)
-
-#define AD7124_MODE_CAL_INT_ZERO 0x5 /* Internal Zero-Scale Calibration */
-#define AD7124_MODE_CAL_INT_FULL 0x6 /* Internal Full-Scale Calibration */
-#define AD7124_MODE_CAL_SYS_ZERO 0x7 /* System Zero-Scale Calibration */
-#define AD7124_MODE_CAL_SYS_FULL 0x8 /* System Full-Scale Calibration */
-
-/* AD7124 ID */
-#define AD7124_DEVICE_ID_MSK GENMASK(7, 4)
-#define AD7124_DEVICE_ID_GET(x) FIELD_GET(AD7124_DEVICE_ID_MSK, x)
-#define AD7124_SILICON_REV_MSK GENMASK(3, 0)
-#define AD7124_SILICON_REV_GET(x) FIELD_GET(AD7124_SILICON_REV_MSK, x)
-
-#define CHIPID_AD7124_4 0x0
-#define CHIPID_AD7124_8 0x1
+#define AD7124_ADC_CONTROL_MODE GENMASK(5, 2)
+#define AD7124_ADC_CONTROL_MODE_CONTINUOUS 0
+#define AD7124_ADC_CONTROL_MODE_SINGLE 1
+#define AD7124_ADC_CONTROL_MODE_STANDBY 2
+#define AD7124_ADC_CONTROL_MODE_POWERDOWN 3
+#define AD7124_ADC_CONTROL_MODE_IDLE 4
+#define AD7124_ADC_CONTROL_MODE_INT_OFFSET_CALIB 5 /* Internal Zero-Scale Calibration */
+#define AD7124_ADC_CONTROL_MODE_INT_GAIN_CALIB 6 /* Internal Full-Scale Calibration */
+#define AD7124_ADC_CONTROL_MODE_SYS_OFFSET_CALIB 7 /* System Zero-Scale Calibration */
+#define AD7124_ADC_CONTROL_MODE_SYS_GAIN_CALIB 8 /* System Full-Scale Calibration */
+#define AD7124_ADC_CONTROL_POWER_MODE GENMASK(7, 6)
+#define AD7124_ADC_CONTROL_POWER_MODE_LOW 0
+#define AD7124_ADC_CONTROL_POWER_MODE_MID 1
+#define AD7124_ADC_CONTROL_POWER_MODE_FULL 2
+#define AD7124_ADC_CONTROL_REF_EN BIT(8)
+#define AD7124_ADC_CONTROL_DATA_STATUS BIT(10)
+
+/* AD7124_ID */
+#define AD7124_ID_SILICON_REVISION GENMASK(3, 0)
+#define AD7124_ID_DEVICE_ID GENMASK(7, 4)
+#define AD7124_ID_DEVICE_ID_AD7124_4 0x0
+#define AD7124_ID_DEVICE_ID_AD7124_8 0x1
/* AD7124_CHANNEL_X */
-#define AD7124_CHANNEL_EN_MSK BIT(15)
-#define AD7124_CHANNEL_EN(x) FIELD_PREP(AD7124_CHANNEL_EN_MSK, x)
-#define AD7124_CHANNEL_SETUP_MSK GENMASK(14, 12)
-#define AD7124_CHANNEL_SETUP(x) FIELD_PREP(AD7124_CHANNEL_SETUP_MSK, x)
-#define AD7124_CHANNEL_AINP_MSK GENMASK(9, 5)
-#define AD7124_CHANNEL_AINP(x) FIELD_PREP(AD7124_CHANNEL_AINP_MSK, x)
-#define AD7124_CHANNEL_AINM_MSK GENMASK(4, 0)
-#define AD7124_CHANNEL_AINM(x) FIELD_PREP(AD7124_CHANNEL_AINM_MSK, x)
+#define AD7124_CHANNEL_ENABLE BIT(15)
+#define AD7124_CHANNEL_SETUP GENMASK(14, 12)
+#define AD7124_CHANNEL_AINP GENMASK(9, 5)
+#define AD7124_CHANNEL_AINM GENMASK(4, 0)
+#define AD7124_CHANNEL_AINx_TEMPSENSOR 16
+#define AD7124_CHANNEL_AINx_AVSS 17
/* AD7124_CONFIG_X */
-#define AD7124_CONFIG_BIPOLAR_MSK BIT(11)
-#define AD7124_CONFIG_BIPOLAR(x) FIELD_PREP(AD7124_CONFIG_BIPOLAR_MSK, x)
-#define AD7124_CONFIG_REF_SEL_MSK GENMASK(4, 3)
-#define AD7124_CONFIG_REF_SEL(x) FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
-#define AD7124_CONFIG_PGA_MSK GENMASK(2, 0)
-#define AD7124_CONFIG_PGA(x) FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
-#define AD7124_CONFIG_IN_BUFF_MSK GENMASK(6, 5)
-#define AD7124_CONFIG_IN_BUFF(x) FIELD_PREP(AD7124_CONFIG_IN_BUFF_MSK, x)
+#define AD7124_CONFIG_BIPOLAR BIT(11)
+#define AD7124_CONFIG_IN_BUFF GENMASK(6, 5)
+#define AD7124_CONFIG_AIN_BUFP BIT(6)
+#define AD7124_CONFIG_AIN_BUFM BIT(5)
+#define AD7124_CONFIG_REF_SEL GENMASK(4, 3)
+#define AD7124_CONFIG_PGA GENMASK(2, 0)
/* AD7124_FILTER_X */
-#define AD7124_FILTER_FS_MSK GENMASK(10, 0)
-#define AD7124_FILTER_FS(x) FIELD_PREP(AD7124_FILTER_FS_MSK, x)
-#define AD7124_FILTER_TYPE_MSK GENMASK(23, 21)
-#define AD7124_FILTER_TYPE_SEL(x) FIELD_PREP(AD7124_FILTER_TYPE_MSK, x)
+#define AD7124_FILTER_FS GENMASK(10, 0)
+#define AD7124_FILTER_FILTER GENMASK(23, 21)
+#define AD7124_FILTER_FILTER_SINC4 0
+#define AD7124_FILTER_FILTER_SINC3 2
-#define AD7124_SINC3_FILTER 2
-#define AD7124_SINC4_FILTER 0
-
-#define AD7124_CONF_ADDR_OFFSET 20
#define AD7124_MAX_CONFIGS 8
#define AD7124_MAX_CHANNELS 16
/* AD7124 input sources */
-#define AD7124_INPUT_TEMPSENSOR 16
-#define AD7124_INPUT_AVSS 17
enum ad7124_ids {
ID_AD7124_4,
@@ -206,12 +196,12 @@ struct ad7124_state {
static struct ad7124_chip_info ad7124_chip_info_tbl[] = {
[ID_AD7124_4] = {
.name = "ad7124-4",
- .chip_id = CHIPID_AD7124_4,
+ .chip_id = AD7124_ID_DEVICE_ID_AD7124_4,
.num_inputs = 8,
},
[ID_AD7124_8] = {
.name = "ad7124-8",
- .chip_id = CHIPID_AD7124_8,
+ .chip_id = AD7124_ID_DEVICE_ID_AD7124_8,
.num_inputs = 16,
},
};
@@ -260,8 +250,8 @@ static int ad7124_set_mode(struct ad_sigma_delta *sd,
{
struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
- st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK;
- st->adc_control |= AD7124_ADC_CTRL_MODE(mode);
+ st->adc_control &= ~AD7124_ADC_CONTROL_MODE;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, mode);
return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
}
@@ -300,41 +290,15 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
fadc = st->channels[channel].cfg.odr;
switch (st->channels[channel].cfg.filter_type) {
- case AD7124_SINC3_FILTER:
+ case AD7124_FILTER_FILTER_SINC3:
+ return DIV_ROUND_CLOSEST(fadc * 272, 1000);
+ case AD7124_FILTER_FILTER_SINC4:
return DIV_ROUND_CLOSEST(fadc * 230, 1000);
- case AD7124_SINC4_FILTER:
- return DIV_ROUND_CLOSEST(fadc * 262, 1000);
default:
return -EINVAL;
}
}
-static void ad7124_set_3db_filter_freq(struct ad7124_state *st, unsigned int channel,
- unsigned int freq)
-{
- unsigned int sinc4_3db_odr;
- unsigned int sinc3_3db_odr;
- unsigned int new_filter;
- unsigned int new_odr;
-
- sinc4_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 230);
- sinc3_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 262);
-
- if (sinc4_3db_odr > sinc3_3db_odr) {
- new_filter = AD7124_SINC3_FILTER;
- new_odr = sinc4_3db_odr;
- } else {
- new_filter = AD7124_SINC4_FILTER;
- new_odr = sinc3_3db_odr;
- }
-
- if (new_odr != st->channels[channel].cfg.odr)
- st->channels[channel].cfg.live = false;
-
- st->channels[channel].cfg.filter_type = new_filter;
- st->channels[channel].cfg.odr = new_odr;
-}
-
static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_state *st,
struct ad7124_channel_config *cfg)
{
@@ -413,8 +377,7 @@ static int ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channe
return 0;
case AD7124_INT_REF:
cfg->vref_mv = 2500;
- st->adc_control &= ~AD7124_ADC_CTRL_REF_EN_MSK;
- st->adc_control |= AD7124_ADC_CTRL_REF_EN(1);
+ st->adc_control |= AD7124_ADC_CONTROL_REF_EN;
return 0;
default:
return dev_err_probe(dev, -EINVAL, "Invalid reference %d\n", refsel);
@@ -438,18 +401,20 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
if (ret)
return ret;
- tmp = (cfg->buf_positive << 1) + cfg->buf_negative;
- val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) |
- AD7124_CONFIG_IN_BUFF(tmp) | AD7124_CONFIG_PGA(cfg->pga_bits);
+ val = FIELD_PREP(AD7124_CONFIG_BIPOLAR, cfg->bipolar) |
+ FIELD_PREP(AD7124_CONFIG_REF_SEL, cfg->refsel) |
+ (cfg->buf_positive ? AD7124_CONFIG_AIN_BUFP : 0) |
+ (cfg->buf_negative ? AD7124_CONFIG_AIN_BUFM : 0) |
+ FIELD_PREP(AD7124_CONFIG_PGA, cfg->pga_bits);
ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(cfg->cfg_slot), 2, val);
if (ret < 0)
return ret;
- tmp = AD7124_FILTER_TYPE_SEL(cfg->filter_type) |
- AD7124_FILTER_FS(cfg->odr_sel_bits);
+ tmp = FIELD_PREP(AD7124_FILTER_FILTER, cfg->filter_type) |
+ FIELD_PREP(AD7124_FILTER_FS, cfg->odr_sel_bits);
return ad7124_spi_write_mask(st, AD7124_FILTER(cfg->cfg_slot),
- AD7124_FILTER_TYPE_MSK | AD7124_FILTER_FS_MSK,
+ AD7124_FILTER_FILTER | AD7124_FILTER_FS,
tmp, 3);
}
@@ -514,7 +479,8 @@ static int ad7124_enable_channel(struct ad7124_state *st, struct ad7124_channel
{
ch->cfg.live = true;
return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(ch->nr), 2, ch->ain |
- AD7124_CHANNEL_SETUP(ch->cfg.cfg_slot) | AD7124_CHANNEL_EN(1));
+ FIELD_PREP(AD7124_CHANNEL_SETUP, ch->cfg.cfg_slot) |
+ AD7124_CHANNEL_ENABLE);
}
static int ad7124_prepare_read(struct ad7124_state *st, int address)
@@ -564,8 +530,10 @@ static int ad7124_append_status(struct ad_sigma_delta *sd, bool append)
unsigned int adc_control = st->adc_control;
int ret;
- adc_control &= ~AD7124_ADC_STATUS_EN_MSK;
- adc_control |= AD7124_ADC_STATUS_EN(append);
+ if (append)
+ adc_control |= AD7124_ADC_CONTROL_DATA_STATUS;
+ else
+ adc_control &= ~AD7124_ADC_CONTROL_DATA_STATUS;
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, adc_control);
if (ret < 0)
@@ -580,7 +548,7 @@ static int ad7124_disable_one(struct ad_sigma_delta *sd, unsigned int chan)
{
struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
- /* The relevant thing here is that AD7124_CHANNEL_EN_MSK is cleared. */
+ /* The relevant thing here is that AD7124_CHANNEL_ENABLE is cleared. */
return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(chan), 2, 0);
}
@@ -739,16 +707,8 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
st->channels[chan->address].cfg.pga_bits = res;
break;
- case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
- if (val2 != 0) {
- ret = -EINVAL;
- break;
- }
-
- ad7124_set_3db_filter_freq(st, chan->address, val);
- break;
default:
- ret = -EINVAL;
+ ret = -EINVAL;
}
mutex_unlock(&st->cfgs_lock);
@@ -802,7 +762,7 @@ static int ad7124_update_scan_mode(struct iio_dev *indio_dev,
if (bit_set)
ret = __ad7124_set_channel(&st->sd, i);
else
- ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_EN_MSK,
+ ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE,
0, 2);
if (ret < 0) {
mutex_unlock(&st->cfgs_lock);
@@ -843,14 +803,14 @@ static int ad7124_soft_reset(struct ad7124_state *st)
if (ret < 0)
return dev_err_probe(dev, ret, "Error reading status register\n");
- if (!(readval & AD7124_STATUS_POR_FLAG_MSK))
+ if (!(readval & AD7124_STATUS_POR_FLAG))
break;
/* The AD7124 requires typically 2ms to power up and settle */
usleep_range(100, 2000);
} while (--timeout);
- if (readval & AD7124_STATUS_POR_FLAG_MSK)
+ if (readval & AD7124_STATUS_POR_FLAG)
return dev_err_probe(dev, -EIO, "Soft reset failed\n");
ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->gain_default);
@@ -872,8 +832,8 @@ static int ad7124_check_chip_id(struct ad7124_state *st)
if (ret < 0)
return dev_err_probe(dev, ret, "Failure to read ID register\n");
- chip_id = AD7124_DEVICE_ID_GET(readval);
- silicon_rev = AD7124_SILICON_REV_GET(readval);
+ chip_id = FIELD_GET(AD7124_ID_DEVICE_ID, readval);
+ silicon_rev = FIELD_GET(AD7124_ID_SILICON_REVISION, readval);
if (chip_id != st->chip_info->chip_id)
return dev_err_probe(dev, -ENODEV,
@@ -901,7 +861,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
if (ch->syscalib_mode == AD7124_SYSCALIB_ZERO_SCALE) {
ch->cfg.calibration_offset = 0x800000;
- ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_SYS_ZERO,
+ ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_SYS_OFFSET_CALIB,
chan->address);
if (ret < 0)
return ret;
@@ -916,7 +876,7 @@ static int ad7124_syscalib_locked(struct ad7124_state *st, const struct iio_chan
} else {
ch->cfg.calibration_gain = st->gain_default;
- ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_SYS_FULL,
+ ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_SYS_GAIN_CALIB,
chan->address);
if (ret < 0)
return ret;
@@ -1031,7 +991,7 @@ static bool ad7124_valid_input_select(unsigned int ain, const struct ad7124_chip
if (ain >= info->num_inputs && ain < 16)
return false;
- return ain <= FIELD_MAX(AD7124_CHANNEL_AINM_MSK);
+ return ain <= FIELD_MAX(AD7124_CHANNEL_AINM);
}
static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
@@ -1096,8 +1056,8 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
"diff-channels property of %pfwP contains invalid data\n", child);
st->channels[channel].nr = channel;
- st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
- AD7124_CHANNEL_AINM(ain[1]);
+ st->channels[channel].ain = FIELD_PREP(AD7124_CHANNEL_AINP, ain[0]) |
+ FIELD_PREP(AD7124_CHANNEL_AINM, ain[1]);
cfg = &st->channels[channel].cfg;
cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
@@ -1123,8 +1083,8 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
if (num_channels < AD7124_MAX_CHANNELS) {
st->channels[num_channels] = (struct ad7124_channel) {
.nr = num_channels,
- .ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) |
- AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS),
+ .ain = FIELD_PREP(AD7124_CHANNEL_AINP, AD7124_CHANNEL_AINx_TEMPSENSOR) |
+ FIELD_PREP(AD7124_CHANNEL_AINM, AD7124_CHANNEL_AINx_AVSS),
.cfg = {
.bipolar = true,
},
@@ -1175,11 +1135,11 @@ static int ad7124_setup(struct ad7124_state *st)
}
/* Set the power mode */
- st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK;
- st->adc_control |= AD7124_ADC_CTRL_PWR(power_mode);
+ st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode);
- st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK;
- st->adc_control |= AD7124_ADC_CTRL_MODE(AD_SD_MODE_IDLE);
+ st->adc_control &= ~AD7124_ADC_CONTROL_MODE;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_MODE, AD_SD_MODE_IDLE);
mutex_init(&st->cfgs_lock);
INIT_KFIFO(st->live_cfgs_fifo);
@@ -1233,7 +1193,7 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio
* usual: first zero-scale then full-scale calibration.
*/
if (st->channels[i].cfg.pga_bits > 0) {
- ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_FULL, i);
+ ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_GAIN_CALIB, i);
if (ret < 0)
return ret;
@@ -1250,7 +1210,7 @@ static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio
return ret;
}
- ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_ZERO, i);
+ ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_OFFSET_CALIB, i);
if (ret < 0)
return ret;
@@ -1279,9 +1239,9 @@ static int ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio_d
* The resulting calibration is then also valid for high-speed, so just
* restore adc_control afterwards.
*/
- if (FIELD_GET(AD7124_ADC_CTRL_PWR_MSK, adc_control) >= AD7124_FULL_POWER) {
- st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK;
- st->adc_control |= AD7124_ADC_CTRL_PWR(AD7124_MID_POWER);
+ if (FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, adc_control) >= AD7124_FULL_POWER) {
+ st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
+ st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, AD7124_MID_POWER);
}
ret = __ad7124_calibrate_all(st, indio_dev);
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index 69de5886474c..b3e6bd2a55d7 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -230,10 +230,8 @@ struct ad7173_state {
unsigned long long *config_cnts;
struct clk *ext_clk;
struct clk_hw int_clk_hw;
-#if IS_ENABLED(CONFIG_GPIOLIB)
struct regmap *reg_gpiocon_regmap;
struct gpio_regmap *gpio_regmap;
-#endif
};
static unsigned int ad4115_sinc5_data_rates[] = {
@@ -288,8 +286,6 @@ static const char *const ad7173_clk_sel[] = {
"ext-clk", "xtal"
};
-#if IS_ENABLED(CONFIG_GPIOLIB)
-
static const struct regmap_range ad7173_range_gpio[] = {
regmap_reg_range(AD7173_REG_GPIO, AD7173_REG_GPIO),
};
@@ -543,12 +539,6 @@ static int ad7173_gpio_init(struct ad7173_state *st)
return 0;
}
-#else
-static int ad7173_gpio_init(struct ad7173_state *st)
-{
- return 0;
-}
-#endif /* CONFIG_GPIOLIB */
static struct ad7173_state *ad_sigma_delta_to_ad7173(struct ad_sigma_delta *sd)
{
@@ -1797,10 +1787,7 @@ static int ad7173_probe(struct spi_device *spi)
if (ret)
return ret;
- if (IS_ENABLED(CONFIG_GPIOLIB))
- return ad7173_gpio_init(st);
-
- return 0;
+ return ad7173_gpio_init(st);
}
static const struct of_device_id ad7173_of_match[] = {
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index 7fef2727f89e..3364ac6c4631 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -86,10 +86,9 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
int ret;
ret = spi_read(st->spi, st->data.sample, 4);
- if (ret == 0) {
- iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
- pf->timestamp);
- }
+ if (ret == 0)
+ iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
+ pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c
index f9f32737db80..dda2986ccda0 100644
--- a/drivers/iio/adc/ad7280a.c
+++ b/drivers/iio/adc/ad7280a.c
@@ -572,7 +572,7 @@ static const struct iio_chan_spec_ext_info ad7280_cell_ext_info[] = {
.write = ad7280_store_balance_timer,
.shared = IIO_SEPARATE,
},
- {}
+ { }
};
static const struct iio_event_spec ad7280_events[] = {
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 28b88092b4aa..7c0538ea15c8 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -155,8 +155,8 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
if (b_sent)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index aef85093eb16..d96bd12dfea6 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -13,6 +13,7 @@
* ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf
* ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf
* ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf
+ * ad7389-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7389-4.pdf
* adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf
* adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf
* adaq4381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4381-4.pdf
@@ -119,7 +120,8 @@ struct ad7380_chip_info {
const char * const *supplies;
unsigned int num_supplies;
bool external_ref_only;
- bool adaq_internal_ref_only;
+ bool internal_ref_only;
+ unsigned int internal_ref_mv;
const char * const *vcm_supplies;
unsigned int num_vcm_supplies;
const unsigned long *available_scan_masks;
@@ -609,6 +611,7 @@ static const struct ad7380_chip_info ad7380_chip_info = {
.num_simult_channels = 2,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
.max_conversion_rate_hz = 4 * MEGA,
@@ -622,6 +625,7 @@ static const struct ad7380_chip_info ad7381_chip_info = {
.num_simult_channels = 2,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
.max_conversion_rate_hz = 4 * MEGA,
@@ -637,6 +641,7 @@ static const struct ad7380_chip_info ad7383_chip_info = {
.num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
.max_conversion_rate_hz = 4 * MEGA,
@@ -652,6 +657,7 @@ static const struct ad7380_chip_info ad7384_chip_info = {
.num_supplies = ARRAY_SIZE(ad7380_supplies),
.vcm_supplies = ad7380_2_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_2_channel_vcm_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.available_scan_masks = ad7380_2_channel_scan_masks,
.timing_specs = &ad7380_timing,
.max_conversion_rate_hz = 4 * MEGA,
@@ -665,6 +671,7 @@ static const struct ad7380_chip_info ad7386_chip_info = {
.num_simult_channels = 2,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -679,6 +686,7 @@ static const struct ad7380_chip_info ad7387_chip_info = {
.num_simult_channels = 2,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -693,6 +701,7 @@ static const struct ad7380_chip_info ad7388_chip_info = {
.num_simult_channels = 2,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x2_channel_scan_masks,
.timing_specs = &ad7380_timing,
@@ -721,6 +730,7 @@ static const struct ad7380_chip_info ad7381_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
.max_conversion_rate_hz = 4 * MEGA,
@@ -734,6 +744,7 @@ static const struct ad7380_chip_info ad7383_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
@@ -749,6 +760,7 @@ static const struct ad7380_chip_info ad7384_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.vcm_supplies = ad7380_4_channel_vcm_supplies,
.num_vcm_supplies = ARRAY_SIZE(ad7380_4_channel_vcm_supplies),
.available_scan_masks = ad7380_4_channel_scan_masks,
@@ -764,6 +776,7 @@ static const struct ad7380_chip_info ad7386_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -778,6 +791,7 @@ static const struct ad7380_chip_info ad7387_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -792,12 +806,28 @@ static const struct ad7380_chip_info ad7388_4_chip_info = {
.num_simult_channels = 4,
.supplies = ad7380_supplies,
.num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
.has_mux = true,
.available_scan_masks = ad7380_2x4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
.max_conversion_rate_hz = 4 * MEGA,
};
+static const struct ad7380_chip_info ad7389_4_chip_info = {
+ .name = "ad7389-4",
+ .channels = ad7380_4_channels,
+ .offload_channels = ad7380_4_offload_channels,
+ .num_channels = ARRAY_SIZE(ad7380_4_channels),
+ .num_simult_channels = 4,
+ .supplies = ad7380_supplies,
+ .num_supplies = ARRAY_SIZE(ad7380_supplies),
+ .internal_ref_only = true,
+ .internal_ref_mv = AD7380_INTERNAL_REF_MV,
+ .available_scan_masks = ad7380_4_channel_scan_masks,
+ .timing_specs = &ad7380_4_timing,
+ .max_conversion_rate_hz = 4 * MEGA,
+};
+
static const struct ad7380_chip_info adaq4370_4_chip_info = {
.name = "adaq4370-4",
.channels = adaq4380_4_channels,
@@ -806,7 +836,8 @@ static const struct ad7380_chip_info adaq4370_4_chip_info = {
.num_simult_channels = 4,
.supplies = adaq4380_supplies,
.num_supplies = ARRAY_SIZE(adaq4380_supplies),
- .adaq_internal_ref_only = true,
+ .internal_ref_only = true,
+ .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV,
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -821,7 +852,8 @@ static const struct ad7380_chip_info adaq4380_4_chip_info = {
.num_simult_channels = 4,
.supplies = adaq4380_supplies,
.num_supplies = ARRAY_SIZE(adaq4380_supplies),
- .adaq_internal_ref_only = true,
+ .internal_ref_only = true,
+ .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV,
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -836,7 +868,8 @@ static const struct ad7380_chip_info adaq4381_4_chip_info = {
.num_simult_channels = 4,
.supplies = adaq4380_supplies,
.num_supplies = ARRAY_SIZE(adaq4380_supplies),
- .adaq_internal_ref_only = true,
+ .internal_ref_only = true,
+ .internal_ref_mv = ADAQ4380_INTERNAL_REF_MV,
.has_hardware_gain = true,
.available_scan_masks = ad7380_4_channel_scan_masks,
.timing_specs = &ad7380_4_timing,
@@ -876,8 +909,7 @@ struct ad7380_state {
* Make the buffer large enough for MAX_NUM_CHANNELS 32-bit samples and
* one 64-bit aligned 64-bit timestamp.
*/
- u8 scan_data[ALIGN(MAX_NUM_CHANNELS * sizeof(u32), sizeof(s64))
- + sizeof(s64)] __aligned(IIO_DMA_MINALIGN);
+ IIO_DECLARE_DMA_BUFFER_WITH_TS(u8, scan_data, MAX_NUM_CHANNELS * sizeof(u32));
/* buffers for reading/writing registers */
u16 tx;
u16 rx;
@@ -1327,8 +1359,8 @@ static irqreturn_t ad7380_trigger_handler(int irq, void *p)
if (ret)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->scan_data,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan_data, sizeof(st->scan_data),
+ pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -1859,7 +1891,7 @@ static int ad7380_probe(struct spi_device *spi)
"Failed to enable power supplies\n");
fsleep(T_POWERUP_US);
- if (st->chip_info->adaq_internal_ref_only) {
+ if (st->chip_info->internal_ref_only) {
/*
* ADAQ chips use fixed internal reference but still
* require a specific reference supply to power it.
@@ -1867,7 +1899,7 @@ static int ad7380_probe(struct spi_device *spi)
* in bulk_get_enable().
*/
- st->vref_mv = ADAQ4380_INTERNAL_REF_MV;
+ st->vref_mv = st->chip_info->internal_ref_mv;
/* these chips don't have a register bit for this */
external_ref_en = false;
@@ -1892,7 +1924,8 @@ static int ad7380_probe(struct spi_device *spi)
"Failed to get refio regulator\n");
external_ref_en = ret != -ENODEV;
- st->vref_mv = external_ref_en ? ret / 1000 : AD7380_INTERNAL_REF_MV;
+ st->vref_mv = external_ref_en ? ret / 1000
+ : st->chip_info->internal_ref_mv;
}
if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv))
@@ -2045,6 +2078,7 @@ static const struct of_device_id ad7380_of_match_table[] = {
{ .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info },
{ .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info },
{ .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info },
+ { .compatible = "adi,ad7389-4", .data = &ad7389_4_chip_info },
{ .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info },
{ .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info },
{ .compatible = "adi,adaq4381-4", .data = &adaq4381_4_chip_info },
@@ -2066,6 +2100,7 @@ static const struct spi_device_id ad7380_id_table[] = {
{ "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info },
{ "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info },
{ "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info },
+ { "ad7389-4", (kernel_ulong_t)&ad7389_4_chip_info },
{ "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info },
{ "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info },
{ "adaq4381-4", (kernel_ulong_t)&adaq4381_4_chip_info },
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 37b0515cf4fc..ddb607ac1860 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -99,8 +99,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
if (b_sent < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, st->data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, st->data, sizeof(st->data),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 703556eb7257..185243dee86e 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
@@ -94,121 +95,35 @@ static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128,
};
-static const struct iio_chan_spec ad7605_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(4),
- AD7605_CHANNEL(0),
- AD7605_CHANNEL(1),
- AD7605_CHANNEL(2),
- AD7605_CHANNEL(3),
-};
-
-static const struct iio_chan_spec ad7606_channels_16bit[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 16),
- AD7606_CHANNEL(1, 16),
- AD7606_CHANNEL(2, 16),
- AD7606_CHANNEL(3, 16),
- AD7606_CHANNEL(4, 16),
- AD7606_CHANNEL(5, 16),
- AD7606_CHANNEL(6, 16),
- AD7606_CHANNEL(7, 16),
-};
-
-static const struct iio_chan_spec ad7606_channels_18bit[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 18),
- AD7606_CHANNEL(1, 18),
- AD7606_CHANNEL(2, 18),
- AD7606_CHANNEL(3, 18),
- AD7606_CHANNEL(4, 18),
- AD7606_CHANNEL(5, 18),
- AD7606_CHANNEL(6, 18),
- AD7606_CHANNEL(7, 18),
-};
-
-static const struct iio_chan_spec ad7607_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 14),
- AD7606_CHANNEL(1, 14),
- AD7606_CHANNEL(2, 14),
- AD7606_CHANNEL(3, 14),
- AD7606_CHANNEL(4, 14),
- AD7606_CHANNEL(5, 14),
- AD7606_CHANNEL(6, 14),
- AD7606_CHANNEL(7, 14),
-};
-
-static const struct iio_chan_spec ad7608_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_CHANNEL(0, 18),
- AD7606_CHANNEL(1, 18),
- AD7606_CHANNEL(2, 18),
- AD7606_CHANNEL(3, 18),
- AD7606_CHANNEL(4, 18),
- AD7606_CHANNEL(5, 18),
- AD7606_CHANNEL(6, 18),
- AD7606_CHANNEL(7, 18),
-};
-
-/*
- * The current assumption that this driver makes for AD7616, is that it's
- * working in Hardware Mode with Serial, Burst and Sequencer modes activated.
- * To activate them, following pins must be pulled high:
- * -SER/PAR
- * -SEQEN
- * And following pins must be pulled low:
- * -WR/BURST
- * -DB4/SER1W
- */
-static const struct iio_chan_spec ad7616_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(16),
- AD7606_CHANNEL(0, 16),
- AD7606_CHANNEL(1, 16),
- AD7606_CHANNEL(2, 16),
- AD7606_CHANNEL(3, 16),
- AD7606_CHANNEL(4, 16),
- AD7606_CHANNEL(5, 16),
- AD7606_CHANNEL(6, 16),
- AD7606_CHANNEL(7, 16),
- AD7606_CHANNEL(8, 16),
- AD7606_CHANNEL(9, 16),
- AD7606_CHANNEL(10, 16),
- AD7606_CHANNEL(11, 16),
- AD7606_CHANNEL(12, 16),
- AD7606_CHANNEL(13, 16),
- AD7606_CHANNEL(14, 16),
- AD7606_CHANNEL(15, 16),
-};
-
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
static int ad7616_sw_mode_setup(struct iio_dev *indio_dev);
static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev);
const struct ad7606_chip_info ad7605_4_info = {
- .channels = ad7605_channels,
+ .max_samplerate = 300 * KILO,
.name = "ad7605-4",
+ .bits = 16,
.num_adc_channels = 4,
- .num_channels = 5,
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
};
EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_8_info = {
- .channels = ad7606_channels_16bit,
+ .max_samplerate = 200 * KILO,
.name = "ad7606-8",
+ .bits = 16,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
@@ -216,108 +131,116 @@ const struct ad7606_chip_info ad7606_8_info = {
EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_6_info = {
- .channels = ad7606_channels_16bit,
+ .max_samplerate = 200 * KILO,
.name = "ad7606-6",
+ .bits = 16,
.num_adc_channels = 6,
- .num_channels = 7,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606_4_info = {
- .channels = ad7606_channels_16bit,
+ .max_samplerate = 200 * KILO,
.name = "ad7606-4",
+ .bits = 16,
.num_adc_channels = 4,
- .num_channels = 5,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606b_info = {
- .channels = ad7606_channels_16bit,
.max_samplerate = 800 * KILO,
.name = "ad7606b",
+ .bits = 16,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606c_16_info = {
- .channels = ad7606_channels_16bit,
+ .max_samplerate = 1 * MEGA,
.name = "ad7606c16",
+ .bits = 16,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
const struct ad7606_chip_info ad7607_info = {
- .channels = ad7607_channels,
+ .max_samplerate = 200 * KILO,
.name = "ad7607",
+ .bits = 14,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7607_chan_scale_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606");
const struct ad7606_chip_info ad7608_info = {
- .channels = ad7608_channels,
+ .max_samplerate = 200 * KILO,
.name = "ad7608",
+ .bits = 18,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7608_chan_scale_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606");
const struct ad7606_chip_info ad7609_info = {
- .channels = ad7608_channels,
+ .max_samplerate = 200 * KILO,
.name = "ad7609",
+ .bits = 18,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7609_chan_scale_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606");
const struct ad7606_chip_info ad7606c_18_info = {
- .channels = ad7606_channels_18bit,
+ .max_samplerate = 1 * MEGA,
.name = "ad7606c18",
+ .bits = 18,
.num_adc_channels = 8,
- .num_channels = 9,
.oversampling_avail = ad7606_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
+ .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
const struct ad7606_chip_info ad7616_info = {
- .channels = ad7616_channels,
+ .max_samplerate = 1 * MEGA,
.init_delay_ms = 15,
.name = "ad7616",
+ .bits = 16,
.num_adc_channels = 16,
- .num_channels = 17,
.oversampling_avail = ad7616_oversampling_avail,
.oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
.os_req_reset = true,
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7616_sw_mode_setup,
+ .offload_storagebits = 16,
};
EXPORT_SYMBOL_NS_GPL(ad7616_info, "IIO_AD7606");
@@ -335,10 +258,10 @@ int ad7606_reset(struct ad7606_state *st)
EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606");
static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
if (!st->sw_mode_en) {
/* tied to logic low, analog input range is +/- 5V */
@@ -362,7 +285,6 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int num_channels = st->chip_info->num_adc_channels;
- unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels;
struct device *dev = st->dev;
int ret;
@@ -378,7 +300,7 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
continue;
/* channel number (here) is from 1 to num_channels */
- if (reg < offset || reg > num_channels) {
+ if (reg < 1 || reg > num_channels) {
dev_warn(dev,
"Invalid channel number (ignoring): %d\n", reg);
continue;
@@ -414,10 +336,10 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
}
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
bool bipolar, differential;
int ret;
@@ -428,7 +350,8 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
return 0;
}
- ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential);
+ ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
+ &differential);
if (ret)
return ret;
@@ -471,10 +394,10 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
}
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
bool bipolar, differential;
int ret;
@@ -485,7 +408,8 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
return 0;
}
- ret = ad7606_get_chan_config(indio_dev, ch, &bipolar, &differential);
+ ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
+ &differential);
if (ret)
return ret;
@@ -529,10 +453,10 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
}
static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7607_hw_scale_avail;
@@ -541,10 +465,10 @@ static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
}
static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7606_18bit_hw_scale_avail;
@@ -553,10 +477,10 @@ static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
}
static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch)
+ struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[ch];
+ struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
cs->range = 0;
cs->scale_avail = ad7609_hw_scale_avail;
@@ -599,7 +523,7 @@ static int ad7606_pwm_set_high(struct ad7606_state *st)
return ret;
}
-static int ad7606_pwm_set_low(struct ad7606_state *st)
+int ad7606_pwm_set_low(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
int ret;
@@ -612,8 +536,9 @@ static int ad7606_pwm_set_low(struct ad7606_state *st)
return ret;
}
+EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_low, "IIO_AD7606");
-static int ad7606_pwm_set_swing(struct ad7606_state *st)
+int ad7606_pwm_set_swing(struct ad7606_state *st)
{
struct pwm_state cnvst_pwm_state;
@@ -623,6 +548,7 @@ static int ad7606_pwm_set_swing(struct ad7606_state *st)
return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
}
+EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_swing, "IIO_AD7606");
static bool ad7606_pwm_is_swinging(struct ad7606_state *st)
{
@@ -679,8 +605,8 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p)
if (ret)
goto error_ret;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
+ iio_get_time_ns(indio_dev));
error_ret:
iio_trigger_notify_done(indio_dev->trig);
/* The rising edge of the CONVST signal starts a new conversion. */
@@ -693,8 +619,8 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
int *val)
{
struct ad7606_state *st = iio_priv(indio_dev);
- unsigned int realbits = st->chip_info->channels[1].scan_type.realbits;
const struct iio_chan_spec *chan;
+ unsigned int realbits;
int ret;
if (st->gpio_convst) {
@@ -711,7 +637,7 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
* will not happen because IIO_CHAN_INFO_RAW is not supported for the backend.
* TODO: Add support for reading a single value when the backend is used.
*/
- if (!st->back) {
+ if (st->trig) {
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(1000));
if (!ret) {
@@ -719,25 +645,30 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
goto error_ret;
}
} else {
- fsleep(1);
+ /*
+ * If the BUSY interrupt is not available, wait enough time for
+ * the longest possible conversion (max for the whole family is
+ * around 350us).
+ */
+ fsleep(400);
}
ret = ad7606_read_samples(st);
if (ret)
goto error_ret;
- chan = &indio_dev->channels[ch + 1];
- if (chan->scan_type.sign == 'u') {
- if (realbits > 16)
- *val = st->data.buf32[ch];
- else
- *val = st->data.buf16[ch];
- } else {
- if (realbits > 16)
- *val = sign_extend32(st->data.buf32[ch], realbits - 1);
- else
- *val = sign_extend32(st->data.buf16[ch], realbits - 1);
- }
+ chan = &indio_dev->channels[ch];
+ realbits = chan->scan_type.realbits;
+
+ if (realbits > 16)
+ *val = st->data.buf32[ch];
+ else
+ *val = st->data.buf16[ch];
+
+ *val &= GENMASK(realbits - 1, 0);
+
+ if (chan->scan_type.sign == 's')
+ *val = sign_extend32(*val, realbits - 1);
error_ret:
if (!st->gpio_convst) {
@@ -765,14 +696,14 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- ret = ad7606_scan_direct(indio_dev, chan->address, val);
+ ret = ad7606_scan_direct(indio_dev, chan->scan_index, val);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
- ch = chan->address;
+ ch = chan->scan_index;
cs = &st->chan_scales[ch];
*val = cs->scale_avail[cs->range][0];
*val2 = cs->scale_avail[cs->range][1];
@@ -781,10 +712,6 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
*val = st->oversampling;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
- /*
- * TODO: return the real frequency intead of the requested one once
- * pwm_get_state_hw comes upstream.
- */
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
*val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
return IIO_VAL_INT;
@@ -854,7 +781,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
- ch = chan->address;
+ ch = chan->scan_index;
cs = &st->chan_scales[ch];
for (i = 0; i < cs->num_scales; i++) {
scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
@@ -1061,7 +988,7 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
- ch = chan->address;
+ ch = chan->scan_index;
cs = &st->chan_scales[ch];
*vals = (int *)cs->scale_avail;
@@ -1276,29 +1203,91 @@ static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
return st->bops->sw_mode_config(indio_dev);
}
-static int ad7606_chan_scales_setup(struct iio_dev *indio_dev)
+static int ad7606_probe_channels(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
- unsigned int offset = indio_dev->num_channels - st->chip_info->num_adc_channels;
- struct iio_chan_spec *chans;
- size_t size;
- int ch, ret;
-
- /* Clone IIO channels, since some may be differential */
- size = indio_dev->num_channels * sizeof(*indio_dev->channels);
- chans = devm_kzalloc(st->dev, size, GFP_KERNEL);
- if (!chans)
+ struct device *dev = indio_dev->dev.parent;
+ struct iio_chan_spec *channels;
+ bool slow_bus;
+ int ret, i;
+
+ slow_bus = !(st->bops->iio_backend_config || st->offload_en);
+ indio_dev->num_channels = st->chip_info->num_adc_channels;
+
+ /* Slow buses also get 1 more channel for soft timestamp */
+ if (slow_bus)
+ indio_dev->num_channels++;
+
+ channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
+ GFP_KERNEL);
+ if (!channels)
return -ENOMEM;
- memcpy(chans, indio_dev->channels, size);
- indio_dev->channels = chans;
+ for (i = 0; i < st->chip_info->num_adc_channels; i++) {
+ struct iio_chan_spec *chan = &channels[i];
- for (ch = 0; ch < st->chip_info->num_adc_channels; ch++) {
- ret = st->chip_info->scale_setup_cb(indio_dev, &chans[ch + offset], ch);
+ chan->type = IIO_VOLTAGE;
+ chan->indexed = 1;
+ chan->channel = i;
+ chan->scan_index = i;
+ chan->scan_type.sign = 's';
+ chan->scan_type.realbits = st->chip_info->bits;
+ /*
+ * If in SPI offload mode, storagebits are set based
+ * on the spi-engine hw implementation.
+ */
+ chan->scan_type.storagebits = st->offload_en ?
+ st->chip_info->offload_storagebits :
+ (st->chip_info->bits > 16 ? 32 : 16);
+
+ chan->scan_type.endianness = IIO_CPU;
+
+ if (indio_dev->modes & INDIO_DIRECT_MODE)
+ chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);
+
+ if (st->sw_mode_en) {
+ chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
+ chan->info_mask_separate_available |=
+ BIT(IIO_CHAN_INFO_SCALE);
+
+ /*
+ * All chips with software mode support oversampling,
+ * so we skip the oversampling_available check. And the
+ * shared_by_type instead of shared_by_all on slow
+ * buses is for backward compatibility.
+ */
+ if (slow_bus)
+ chan->info_mask_shared_by_type |=
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+ else
+ chan->info_mask_shared_by_all |=
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+
+ chan->info_mask_shared_by_all_available |=
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+ } else {
+ chan->info_mask_shared_by_type |=
+ BIT(IIO_CHAN_INFO_SCALE);
+
+ if (st->chip_info->oversampling_avail)
+ chan->info_mask_shared_by_all |=
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+ }
+
+ if (!slow_bus)
+ chan->info_mask_shared_by_all |=
+ BIT(IIO_CHAN_INFO_SAMP_FREQ);
+
+ ret = st->chip_info->scale_setup_cb(indio_dev, chan);
if (ret)
return ret;
}
+ if (slow_bus)
+ channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);
+
+ indio_dev->channels = channels;
+
return 0;
}
@@ -1322,11 +1311,19 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
st->dev = dev;
- mutex_init(&st->lock);
st->bops = bops;
st->base_address = base_address;
st->oversampling = 1;
+ st->sw_mode_en = device_property_read_bool(dev, "adi,sw-mode");
+
+ if (st->sw_mode_en && !chip_info->sw_setup_cb)
+ return dev_err_probe(dev, -EINVAL,
+ "Software mode is not supported for this chip\n");
ret = devm_regulator_get_enable(dev, "avcc");
if (ret)
@@ -1355,10 +1352,21 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
else
indio_dev->info = &ad7606_info_no_os_or_range;
}
- indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* AXI ADC backend doesn't support single read. */
+ indio_dev->modes = st->bops->iio_backend_config ? 0 : INDIO_DIRECT_MODE;
indio_dev->name = chip_info->name;
- indio_dev->channels = st->chip_info->channels;
- indio_dev->num_channels = st->chip_info->num_channels;
+
+ /* Using spi-engine with offload support ? */
+ if (st->bops->offload_config) {
+ ret = st->bops->offload_config(dev, indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad7606_probe_channels(indio_dev);
+ if (ret)
+ return ret;
ret = ad7606_reset(st);
if (ret)
@@ -1371,7 +1379,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
}
/* If convst pin is not defined, setup PWM. */
- if (!st->gpio_convst) {
+ if (!st->gpio_convst || st->offload_en) {
st->cnvst_pwm = devm_pwm_get(dev, NULL);
if (IS_ERR(st->cnvst_pwm))
return PTR_ERR(st->cnvst_pwm);
@@ -1401,8 +1409,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
* If there is a backend, the PWM should not overpass the maximum sampling
* frequency the chip supports.
*/
- ret = ad7606_set_sampling_freq(st,
- chip_info->max_samplerate ? : 2 * KILO);
+ ret = ad7606_set_sampling_freq(st, chip_info->max_samplerate);
if (ret)
return ret;
@@ -1411,8 +1418,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return ret;
indio_dev->setup_ops = &ad7606_backend_buffer_ops;
- } else {
-
+ } else if (!st->offload_en) {
/* Reserve the PWM use only for backend (force gpio_convst definition) */
if (!st->gpio_convst)
return dev_err_probe(dev, -EINVAL,
@@ -1450,17 +1456,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->write_scale = ad7606_write_scale_hw;
st->write_os = ad7606_write_os_hw;
- st->sw_mode_en = st->chip_info->sw_setup_cb &&
- device_property_present(st->dev, "adi,sw-mode");
- if (st->sw_mode_en) {
+ /* Offload needs 1 DOUT line, applying this setting in sw_setup_cb. */
+ if (st->sw_mode_en || st->offload_en) {
indio_dev->info = &ad7606_info_sw_mode;
st->chip_info->sw_setup_cb(indio_dev);
}
- ret = ad7606_chan_scales_setup(indio_dev);
- if (ret)
- return ret;
-
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 71a30525eaab..441e62c521bc 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -40,119 +40,48 @@
#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
#define AD7606_OS_MODE 0x08
-#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all, \
- mask_sep_avail, mask_all_avail, bits) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = num, \
- .address = num, \
- .info_mask_separate = mask_sep, \
- .info_mask_separate_available = \
- mask_sep_avail, \
- .info_mask_shared_by_type = mask_type, \
- .info_mask_shared_by_all = mask_all, \
- .info_mask_shared_by_all_available = \
- mask_all_avail, \
- .scan_index = num, \
- .scan_type = { \
- .sign = 's', \
- .realbits = (bits), \
- .storagebits = (bits) > 16 ? 32 : 16, \
- .endianness = IIO_CPU, \
- }, \
-}
-
-#define AD7606_SW_CHANNEL(num, bits) \
- AD760X_CHANNEL(num, \
- /* mask separate */ \
- BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE), \
- /* mask type */ \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- /* mask all */ \
- 0, \
- /* mask separate available */ \
- BIT(IIO_CHAN_INFO_SCALE), \
- /* mask all available */ \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- bits)
-
-#define AD7605_CHANNEL(num) \
- AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
- BIT(IIO_CHAN_INFO_SCALE), 0, 0, 0, 16)
-
-#define AD7606_CHANNEL(num, bits) \
- AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
- BIT(IIO_CHAN_INFO_SCALE), \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- 0, 0, bits)
-
-#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16)
-
-#define AD7606_BI_CHANNEL(num) \
- AD760X_CHANNEL(num, 0, \
- BIT(IIO_CHAN_INFO_SCALE), \
- BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- 0, 0, 16)
-
-#define AD7606_BI_SW_CHANNEL(num) \
- AD760X_CHANNEL(num, \
- /* mask separate */ \
- BIT(IIO_CHAN_INFO_SCALE), \
- /* mask type */ \
- 0, \
- /* mask all */ \
- BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- /* mask separate available */ \
- BIT(IIO_CHAN_INFO_SCALE), \
- /* mask all available */ \
- BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
- 16)
-
struct ad7606_state;
typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev,
- struct iio_chan_spec *chan, int ch);
+ struct iio_chan_spec *chan);
typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
/**
* struct ad7606_chip_info - chip specific information
- * @channels: channel specification
- * @max_samplerate: maximum supported samplerate
- * @name device name
- * @num_channels: number of channels
- * @num_adc_channels the number of channels the ADC actually inputs.
+ * @max_samplerate: maximum supported sample rate
+ * @name: device name
+ * @bits: data width in bits
+ * @num_adc_channels: the number of physical voltage inputs
* @scale_setup_cb: callback to setup the scales for each channel
* @sw_setup_cb: callback to setup the software mode if available.
- * @oversampling_avail pointer to the array which stores the available
+ * @oversampling_avail: pointer to the array which stores the available
* oversampling ratios.
- * @oversampling_num number of elements stored in oversampling_avail array
- * @os_req_reset some devices require a reset to update oversampling
- * @init_delay_ms required delay in milliseconds for initialization
+ * @oversampling_num: number of elements stored in oversampling_avail array
+ * @os_req_reset: some devices require a reset to update oversampling
+ * @init_delay_ms: required delay in milliseconds for initialization
* after a restart
+ * @offload_storagebits: storage bits used by the offload hw implementation
*/
struct ad7606_chip_info {
- const struct iio_chan_spec *channels;
unsigned int max_samplerate;
const char *name;
+ unsigned int bits;
unsigned int num_adc_channels;
- unsigned int num_channels;
ad7606_scale_setup_cb_t scale_setup_cb;
ad7606_sw_setup_cb_t sw_setup_cb;
const unsigned int *oversampling_avail;
unsigned int oversampling_num;
bool os_req_reset;
unsigned long init_delay_ms;
+ u8 offload_storagebits;
};
/**
* struct ad7606_chan_scale - channel scale configuration
- * @scale_avail pointer to the array which stores the available scales
- * @num_scales number of elements stored in the scale_avail array
- * @range voltage range selection, selects which scale to apply
- * @reg_offset offset for the register value, to be applied when
+ * @scale_avail: pointer to the array which stores the available scales
+ * @num_scales: number of elements stored in the scale_avail array
+ * @range: voltage range selection, selects which scale to apply
+ * @reg_offset: offset for the register value, to be applied when
* writing the value of 'range' to the register value
*/
struct ad7606_chan_scale {
@@ -165,32 +94,35 @@ struct ad7606_chan_scale {
/**
* struct ad7606_state - driver instance specific data
- * @dev pointer to kernel device
- * @chip_info entry in the table of chips that describes this device
- * @bops bus operations (SPI or parallel)
- * @chan_scales scale configuration for channels
- * @oversampling oversampling selection
- * @cnvst_pwm pointer to the PWM device connected to the cnvst pin
- * @base_address address from where to read data in parallel operation
- * @sw_mode_en software mode enabled
- * @oversampling_avail pointer to the array which stores the available
+ * @dev: pointer to kernel device
+ * @chip_info: entry in the table of chips that describes this device
+ * @bops: bus operations (SPI or parallel)
+ * @chan_scales: scale configuration for channels
+ * @oversampling: oversampling selection
+ * @cnvst_pwm: pointer to the PWM device connected to the cnvst pin
+ * @base_address: address from where to read data in parallel operation
+ * @sw_mode_en: software mode enabled
+ * @oversampling_avail: pointer to the array which stores the available
* oversampling ratios.
- * @num_os_ratios number of elements stored in oversampling_avail array
- * @write_scale pointer to the function which writes the scale
- * @write_os pointer to the function which writes the os
- * @lock protect sensor state from concurrent accesses to GPIOs
- * @gpio_convst GPIO descriptor for conversion start signal (CONVST)
- * @gpio_reset GPIO descriptor for device hard-reset
- * @gpio_range GPIO descriptor for range selection
- * @gpio_standby GPIO descriptor for stand-by signal (STBY),
+ * @num_os_ratios: number of elements stored in oversampling_avail array
+ * @back: pointer to the iio_backend structure, if used
+ * @write_scale: pointer to the function which writes the scale
+ * @write_os: pointer to the function which writes the os
+ * @lock: protect sensor state from concurrent accesses to GPIOs
+ * @gpio_convst: GPIO descriptor for conversion start signal (CONVST)
+ * @gpio_reset: GPIO descriptor for device hard-reset
+ * @gpio_range: GPIO descriptor for range selection
+ * @gpio_standby: GPIO descriptor for stand-by signal (STBY),
* controls power-down mode of device
- * @gpio_frstdata GPIO descriptor for reading from device when data
+ * @gpio_frstdata: GPIO descriptor for reading from device when data
* is being read on the first channel
- * @gpio_os GPIO descriptors to control oversampling on the device
- * @complete completion to indicate end of conversion
- * @trig The IIO trigger associated with the device.
- * @data buffer for reading data from the device
- * @d16 be16 buffer for reading data from the device
+ * @gpio_os: GPIO descriptors to control oversampling on the device
+ * @trig: The IIO trigger associated with the device.
+ * @completion: completion to indicate end of conversion
+ * @data: buffer for reading data from the device
+ * @offload_en: SPI offload enabled
+ * @bus_data: bus-specific variables
+ * @d16: be16 buffer for reading data from the device
*/
struct ad7606_state {
struct device *dev;
@@ -217,36 +149,44 @@ struct ad7606_state {
struct iio_trigger *trig;
struct completion completion;
+ bool offload_en;
+ void *bus_data;
+
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
- * 16 * 16-bit samples + 64-bit timestamp - for AD7616
- * 8 * 32-bit samples + 64-bit timestamp - for AD7616C-18 (and similar)
+ * 16 * 16-bit samples for AD7616
+ * 8 * 32-bit samples for AD7616C-18 (and similar)
*/
- union {
- u16 buf16[20];
- u32 buf32[10];
+ struct {
+ union {
+ u16 buf16[16];
+ u32 buf32[8];
+ };
+ aligned_s64 timestamp;
} data __aligned(IIO_DMA_MINALIGN);
__be16 d16[2];
};
/**
* struct ad7606_bus_ops - driver bus operations
- * @iio_backend_config function pointer for configuring the iio_backend for
+ * @iio_backend_config: function pointer for configuring the iio_backend for
* the compatibles that use it
- * @read_block function pointer for reading blocks of data
+ * @read_block: function pointer for reading blocks of data
* @sw_mode_config: pointer to a function which configured the device
* for software mode
- * @reg_read function pointer for reading spi register
- * @reg_write function pointer for writing spi register
- * @write_mask function pointer for write spi register with mask
- * @update_scan_mode function pointer for handling the calls to iio_info's update_scan
- * mode when enabling/disabling channels.
- * @rd_wr_cmd pointer to the function which calculates the spi address
+ * @offload_config: function pointer for configuring offload support,
+ * where any
+ * @reg_read: function pointer for reading spi register
+ * @reg_write: function pointer for writing spi register
+ * @update_scan_mode: function pointer for handling the calls to iio_info's
+ * update_scan mode when enabling/disabling channels.
+ * @rd_wr_cmd: pointer to the function which calculates the spi address
*/
struct ad7606_bus_ops {
/* more methods added in future? */
int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev);
+ int (*offload_config)(struct device *dev, struct iio_dev *indio_dev);
int (*read_block)(struct device *dev, int num, void *data);
int (*sw_mode_config)(struct iio_dev *indio_dev);
int (*reg_read)(struct ad7606_state *st, unsigned int addr);
@@ -254,13 +194,13 @@ struct ad7606_bus_ops {
unsigned int addr,
unsigned int val);
int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask);
- u16 (*rd_wr_cmd)(int addr, char isWriteOp);
+ u16 (*rd_wr_cmd)(int addr, char is_write_op);
};
/**
- * struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops
- * @chip_info entry in the table of chips that describes this device
- * @bops bus operations (SPI or parallel)
+ * struct ad7606_bus_info - aggregate ad7606_chip_info and ad7606_bus_ops
+ * @chip_info: entry in the table of chips that describes this device
+ * @bops: bus operations (SPI or parallel)
*/
struct ad7606_bus_info {
const struct ad7606_chip_info *chip_info;
@@ -272,6 +212,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const struct ad7606_bus_ops *bops);
int ad7606_reset(struct ad7606_state *st);
+int ad7606_pwm_set_swing(struct ad7606_state *st);
+int ad7606_pwm_set_low(struct ad7606_state *st);
extern const struct ad7606_chip_info ad7605_4_info;
extern const struct ad7606_chip_info ad7606_8_info;
diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c
index 335fb481bfde..634852c4bbd2 100644
--- a/drivers/iio/adc/ad7606_par.c
+++ b/drivers/iio/adc/ad7606_par.c
@@ -21,28 +21,6 @@
#include "ad7606.h"
#include "ad7606_bus_iface.h"
-static const struct iio_chan_spec ad7606b_bi_channels[] = {
- AD7606_BI_CHANNEL(0),
- AD7606_BI_CHANNEL(1),
- AD7606_BI_CHANNEL(2),
- AD7606_BI_CHANNEL(3),
- AD7606_BI_CHANNEL(4),
- AD7606_BI_CHANNEL(5),
- AD7606_BI_CHANNEL(6),
- AD7606_BI_CHANNEL(7),
-};
-
-static const struct iio_chan_spec ad7606b_bi_sw_channels[] = {
- AD7606_BI_SW_CHANNEL(0),
- AD7606_BI_SW_CHANNEL(1),
- AD7606_BI_SW_CHANNEL(2),
- AD7606_BI_SW_CHANNEL(3),
- AD7606_BI_SW_CHANNEL(4),
- AD7606_BI_SW_CHANNEL(5),
- AD7606_BI_SW_CHANNEL(6),
- AD7606_BI_SW_CHANNEL(7),
-};
-
static int ad7606_par_bus_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
@@ -94,9 +72,6 @@ static int ad7606_par_bus_setup_iio_backend(struct device *dev,
return ret;
}
- indio_dev->channels = ad7606b_bi_channels;
- indio_dev->num_channels = 8;
-
return 0;
}
@@ -120,19 +95,11 @@ static int ad7606_par_bus_reg_write(struct ad7606_state *st, unsigned int addr,
return pdata->bus_reg_write(st->back, addr, val);
}
-static int ad7606_par_bus_sw_mode_config(struct iio_dev *indio_dev)
-{
- indio_dev->channels = ad7606b_bi_sw_channels;
-
- return 0;
-}
-
static const struct ad7606_bus_ops ad7606_bi_bops = {
.iio_backend_config = ad7606_par_bus_setup_iio_backend,
.update_scan_mode = ad7606_par_bus_update_scan_mode,
.reg_read = ad7606_par_bus_reg_read,
.reg_write = ad7606_par_bus_reg_write,
- .sw_mode_config = ad7606_par_bus_sw_mode_config,
};
static int ad7606_par16_read_block(struct device *dev,
@@ -255,6 +222,8 @@ static const struct platform_device_id ad7606_driver_ids[] = {
{ .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, },
{ .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, },
{ .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, },
+ { .name = "ad7606c-16", .driver_data = (kernel_ulong_t)&ad7606c_16_info },
+ { .name = "ad7606c-18", .driver_data = (kernel_ulong_t)&ad7606c_18_info },
{ .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, },
{ .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, },
{ .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, },
@@ -268,6 +237,8 @@ static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7606-6", .data = &ad7606_6_info },
{ .compatible = "adi,ad7606-8", .data = &ad7606_8_info },
{ .compatible = "adi,ad7606b", .data = &ad7606b_info },
+ { .compatible = "adi,ad7606c-16", .data = &ad7606c_16_info },
+ { .compatible = "adi,ad7606c-18", .data = &ad7606c_18_info },
{ .compatible = "adi,ad7607", .data = &ad7607_info },
{ .compatible = "adi,ad7608", .data = &ad7608_info },
{ .compatible = "adi,ad7609", .data = &ad7609_info },
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index 179115e90988..f28e4ca37707 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -5,70 +5,43 @@
* Copyright 2011 Analog Devices Inc.
*/
+#include <linux/bitmap.h>
#include <linux/err.h>
+#include <linux/math.h>
#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/offload/provider.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
+#include <linux/units.h>
+#include <linux/iio/buffer-dmaengine.h>
#include <linux/iio/iio.h>
-#include "ad7606.h"
-#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
+#include <dt-bindings/iio/adc/adi,ad7606.h>
-static const struct iio_chan_spec ad7616_sw_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(16),
- AD7616_CHANNEL(0),
- AD7616_CHANNEL(1),
- AD7616_CHANNEL(2),
- AD7616_CHANNEL(3),
- AD7616_CHANNEL(4),
- AD7616_CHANNEL(5),
- AD7616_CHANNEL(6),
- AD7616_CHANNEL(7),
- AD7616_CHANNEL(8),
- AD7616_CHANNEL(9),
- AD7616_CHANNEL(10),
- AD7616_CHANNEL(11),
- AD7616_CHANNEL(12),
- AD7616_CHANNEL(13),
- AD7616_CHANNEL(14),
- AD7616_CHANNEL(15),
-};
+#include "ad7606.h"
-static const struct iio_chan_spec ad7606b_sw_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_SW_CHANNEL(0, 16),
- AD7606_SW_CHANNEL(1, 16),
- AD7606_SW_CHANNEL(2, 16),
- AD7606_SW_CHANNEL(3, 16),
- AD7606_SW_CHANNEL(4, 16),
- AD7606_SW_CHANNEL(5, 16),
- AD7606_SW_CHANNEL(6, 16),
- AD7606_SW_CHANNEL(7, 16),
-};
+#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
-static const struct iio_chan_spec ad7606c_18_sw_channels[] = {
- IIO_CHAN_SOFT_TIMESTAMP(8),
- AD7606_SW_CHANNEL(0, 18),
- AD7606_SW_CHANNEL(1, 18),
- AD7606_SW_CHANNEL(2, 18),
- AD7606_SW_CHANNEL(3, 18),
- AD7606_SW_CHANNEL(4, 18),
- AD7606_SW_CHANNEL(5, 18),
- AD7606_SW_CHANNEL(6, 18),
- AD7606_SW_CHANNEL(7, 18),
+struct spi_bus_data {
+ struct spi_offload *offload;
+ struct spi_offload_trigger *offload_trigger;
+ struct spi_transfer offload_xfer;
+ struct spi_message offload_msg;
};
-static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
+static u16 ad7616_spi_rd_wr_cmd(int addr, char is_write_op)
{
/*
* The address of register consist of one w/r bit
* 6 bits of address followed by one reserved bit.
*/
- return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7);
+ return ((addr & 0x7F) << 1) | ((is_write_op & 0x1) << 7);
}
-static u16 ad7606B_spi_rd_wr_cmd(int addr, char is_write_op)
+static u16 ad7606b_spi_rd_wr_cmd(int addr, char is_write_op)
{
/*
* The address of register consists of one bit which
@@ -155,87 +128,275 @@ static int ad7606_spi_reg_write(struct ad7606_state *st,
struct spi_device *spi = to_spi_device(st->dev);
st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) |
- (val & 0x1FF));
+ (val & 0xFF));
return spi_write(spi, &st->d16[0], sizeof(st->d16[0]));
}
-static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
+static int ad7606b_sw_mode_config(struct iio_dev *indio_dev)
{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ /* Configure device spi to output on a single channel */
+ return st->bops->reg_write(st, AD7606_CONFIGURATION_REGISTER,
+ AD7606_SINGLE_DOUT);
+}
+
+static const struct spi_offload_config ad7606_spi_offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
+};
+
+static int ad7606_spi_offload_buffer_postenable(struct iio_dev *indio_dev)
+{
+ const struct iio_scan_type *scan_type;
+ struct ad7606_state *st = iio_priv(indio_dev);
+ struct spi_bus_data *bus_data = st->bus_data;
+ struct spi_transfer *xfer = &bus_data->offload_xfer;
+ struct spi_device *spi = to_spi_device(st->dev);
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_DATA_READY,
+ };
+ int ret;
+
+ scan_type = &indio_dev->channels[0].scan_type;
+
+ xfer->bits_per_word = scan_type->realbits;
+ xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
/*
- * Scale can be configured individually for each channel
- * in software mode.
+ * Using SPI offload, storagebits are related to the spi-engine
+ * hw implementation, can be 16 or 32, so can't be used to compute
+ * struct spi_transfer.len. Using realbits instead.
*/
- indio_dev->channels = ad7616_sw_channels;
+ xfer->len = (scan_type->realbits > 16 ? 4 : 2) *
+ st->chip_info->num_adc_channels;
+
+ spi_message_init_with_transfers(&bus_data->offload_msg, xfer, 1);
+ bus_data->offload_msg.offload = bus_data->offload;
+
+ ret = spi_optimize_message(spi, &bus_data->offload_msg);
+ if (ret) {
+ dev_err(st->dev, "failed to prepare offload, err: %d\n", ret);
+ return ret;
+ }
+
+ ret = spi_offload_trigger_enable(bus_data->offload,
+ bus_data->offload_trigger,
+ &config);
+ if (ret)
+ goto err_unoptimize_message;
+
+ ret = ad7606_pwm_set_swing(st);
+ if (ret)
+ goto err_offload_exit_conversion_mode;
return 0;
+
+err_offload_exit_conversion_mode:
+ spi_offload_trigger_disable(bus_data->offload,
+ bus_data->offload_trigger);
+
+err_unoptimize_message:
+ spi_unoptimize_message(&bus_data->offload_msg);
+
+ return ret;
}
-static int ad7606B_sw_mode_config(struct iio_dev *indio_dev)
+static int ad7606_spi_offload_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
+ struct spi_bus_data *bus_data = st->bus_data;
+ int ret;
- /* Configure device spi to output on a single channel */
- st->bops->reg_write(st,
- AD7606_CONFIGURATION_REGISTER,
- AD7606_SINGLE_DOUT);
+ ret = ad7606_pwm_set_low(st);
+ if (ret)
+ return ret;
+
+ spi_offload_trigger_disable(bus_data->offload,
+ bus_data->offload_trigger);
+ spi_unoptimize_message(&bus_data->offload_msg);
+
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad7606_offload_buffer_setup_ops = {
+ .postenable = ad7606_spi_offload_buffer_postenable,
+ .predisable = ad7606_spi_offload_buffer_predisable,
+};
+
+static bool ad7606_spi_offload_trigger_match(
+ struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ if (type != SPI_OFFLOAD_TRIGGER_DATA_READY)
+ return false;
/*
- * Scale can be configured individually for each channel
- * in software mode.
+ * Requires 1 arg:
+ * args[0] is the trigger event.
*/
- indio_dev->channels = ad7606b_sw_channels;
+ if (nargs != 1 || args[0] != AD7606_TRIGGER_EVENT_BUSY)
+ return false;
+
+ return true;
+}
+
+static int ad7606_spi_offload_trigger_request(
+ struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ /* Should already be validated by match, but just in case. */
+ if (nargs != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ad7606_spi_offload_trigger_validate(
+ struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ if (config->type != SPI_OFFLOAD_TRIGGER_DATA_READY)
+ return -EINVAL;
return 0;
}
-static int ad7606c_18_sw_mode_config(struct iio_dev *indio_dev)
+static const struct spi_offload_trigger_ops ad7606_offload_trigger_ops = {
+ .match = ad7606_spi_offload_trigger_match,
+ .request = ad7606_spi_offload_trigger_request,
+ .validate = ad7606_spi_offload_trigger_validate,
+};
+
+static int ad7606_spi_offload_probe(struct device *dev,
+ struct iio_dev *indio_dev)
{
+ struct ad7606_state *st = iio_priv(indio_dev);
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_bus_data *bus_data;
+ struct dma_chan *rx_dma;
+ struct spi_offload_trigger_info trigger_info = {
+ .fwnode = dev_fwnode(dev),
+ .ops = &ad7606_offload_trigger_ops,
+ .priv = st,
+ };
int ret;
- ret = ad7606B_sw_mode_config(indio_dev);
+ bus_data = devm_kzalloc(dev, sizeof(*bus_data), GFP_KERNEL);
+ if (!bus_data)
+ return -ENOMEM;
+ st->bus_data = bus_data;
+
+ bus_data->offload = devm_spi_offload_get(dev, spi,
+ &ad7606_spi_offload_config);
+ ret = PTR_ERR_OR_ZERO(bus_data->offload);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to get SPI offload\n");
+ /* Allow main ad7606_probe function to continue. */
+ if (ret == -ENODEV)
+ return 0;
+
+ ret = devm_spi_offload_trigger_register(dev, &trigger_info);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret,
+ "failed to register offload trigger\n");
+
+ bus_data->offload_trigger = devm_spi_offload_trigger_get(dev,
+ bus_data->offload, SPI_OFFLOAD_TRIGGER_DATA_READY);
+ if (IS_ERR(bus_data->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(bus_data->offload_trigger),
+ "failed to get offload trigger\n");
+
+ /* TODO: PWM setup should be ok, done for the backend. PWM mutex ? */
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev,
+ bus_data->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma),
+ "failed to get offload RX DMA\n");
+
+ ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
+ rx_dma, IIO_BUFFER_DIRECTION_IN);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to setup offload RX DMA\n");
+
+ /* Use offload ops. */
+ indio_dev->setup_ops = &ad7606_offload_buffer_setup_ops;
- indio_dev->channels = ad7606c_18_sw_channels;
+ st->offload_en = true;
+
+ return 0;
+}
+
+static int ad7606_spi_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct ad7606_state *st = iio_priv(indio_dev);
+
+ if (st->offload_en) {
+ unsigned int num_adc_ch = st->chip_info->num_adc_channels;
+
+ /*
+ * SPI offload requires that all channels are enabled since
+ * there isn't a way to selectively disable channels that get
+ * read (this is simultaneous sampling ADC) and the DMA buffer
+ * has no way of demuxing the data to filter out unwanted
+ * channels.
+ */
+ if (bitmap_weight(scan_mask, num_adc_ch) != num_adc_ch)
+ return -EINVAL;
+ }
return 0;
}
static const struct ad7606_bus_ops ad7606_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_ops ad7607_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block14to16,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_ops ad7608_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block18to32,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_ops ad7616_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
.rd_wr_cmd = ad7616_spi_rd_wr_cmd,
- .sw_mode_config = ad7616_sw_mode_config,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_ops ad7606b_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
- .rd_wr_cmd = ad7606B_spi_rd_wr_cmd,
- .sw_mode_config = ad7606B_sw_mode_config,
+ .rd_wr_cmd = ad7606b_spi_rd_wr_cmd,
+ .sw_mode_config = ad7606b_sw_mode_config,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_ops ad7606c_18_spi_bops = {
+ .offload_config = ad7606_spi_offload_probe,
.read_block = ad7606_spi_read_block18to32,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
- .rd_wr_cmd = ad7606B_spi_rd_wr_cmd,
- .sw_mode_config = ad7606c_18_sw_mode_config,
+ .rd_wr_cmd = ad7606b_spi_rd_wr_cmd,
+ .sw_mode_config = ad7606b_sw_mode_config,
+ .update_scan_mode = ad7606_spi_update_scan_mode,
};
static const struct ad7606_bus_info ad7605_4_bus_info = {
@@ -348,3 +509,4 @@ MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("IIO_AD7606");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 5e0be36af0c5..51134023534a 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -4,14 +4,17 @@
*
* Copyright 2017 Analog Devices Inc.
*/
+#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
-#include <linux/kernel.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
@@ -53,12 +56,15 @@
#define AD7768_REG_SPI_DIAG_ENABLE 0x28
#define AD7768_REG_ADC_DIAG_ENABLE 0x29
#define AD7768_REG_DIG_DIAG_ENABLE 0x2A
-#define AD7768_REG_ADC_DATA 0x2C
+#define AD7768_REG24_ADC_DATA 0x2C
#define AD7768_REG_MASTER_STATUS 0x2D
#define AD7768_REG_SPI_DIAG_STATUS 0x2E
#define AD7768_REG_ADC_DIAG_STATUS 0x2F
#define AD7768_REG_DIG_DIAG_STATUS 0x30
#define AD7768_REG_MCLK_COUNTER 0x31
+#define AD7768_REG_COEFF_CONTROL 0x32
+#define AD7768_REG24_COEFF_DATA 0x33
+#define AD7768_REG_ACCESS_KEY 0x34
/* AD7768_REG_POWER_CLOCK */
#define AD7768_PWR_MCLK_DIV_MSK GENMASK(5, 4)
@@ -76,9 +82,6 @@
#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
-#define AD7768_RD_FLAG_MSK(x) (BIT(6) | ((x) & 0x3F))
-#define AD7768_WR_FLAG_MSK(x) ((x) & 0x3F)
-
enum ad7768_conv_mode {
AD7768_CONTINUOUS,
AD7768_ONE_SHOT,
@@ -153,6 +156,8 @@ static const struct iio_chan_spec ad7768_channels[] = {
struct ad7768_state {
struct spi_device *spi;
+ struct regmap *regmap;
+ struct regmap *regmap24;
struct regulator *vref;
struct clk *mclk;
unsigned int mclk_freq;
@@ -160,6 +165,7 @@ struct ad7768_state {
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
+ struct gpio_desc *gpio_reset;
const char *labels[ARRAY_SIZE(ad7768_channels)];
/*
* DMA (thus cache coherency maintenance) may require the
@@ -175,46 +181,82 @@ struct ad7768_state {
} data __aligned(IIO_DMA_MINALIGN);
};
-static int ad7768_spi_reg_read(struct ad7768_state *st, unsigned int addr,
- unsigned int len)
-{
- unsigned int shift;
- int ret;
+static const struct regmap_range ad7768_regmap_rd_ranges[] = {
+ regmap_reg_range(AD7768_REG_CHIP_TYPE, AD7768_REG_CHIP_GRADE),
+ regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD),
+ regmap_reg_range(AD7768_REG_VENDOR_L, AD7768_REG_VENDOR_H),
+ regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GAIN_LO),
+ regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE),
+ regmap_reg_range(AD7768_REG_MASTER_STATUS, AD7768_REG_COEFF_CONTROL),
+ regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY),
+};
- shift = 32 - (8 * len);
- st->data.d8[0] = AD7768_RD_FLAG_MSK(addr);
+static const struct regmap_access_table ad7768_regmap_rd_table = {
+ .yes_ranges = ad7768_regmap_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_rd_ranges),
+};
- ret = spi_write_then_read(st->spi, st->data.d8, 1,
- &st->data.d32, len);
- if (ret < 0)
- return ret;
+static const struct regmap_range ad7768_regmap_wr_ranges[] = {
+ regmap_reg_range(AD7768_REG_SCRATCH_PAD, AD7768_REG_SCRATCH_PAD),
+ regmap_reg_range(AD7768_REG_INTERFACE_FORMAT, AD7768_REG_GPIO_WRITE),
+ regmap_reg_range(AD7768_REG_OFFSET_HI, AD7768_REG_GAIN_LO),
+ regmap_reg_range(AD7768_REG_SPI_DIAG_ENABLE, AD7768_REG_DIG_DIAG_ENABLE),
+ regmap_reg_range(AD7768_REG_SPI_DIAG_STATUS, AD7768_REG_SPI_DIAG_STATUS),
+ regmap_reg_range(AD7768_REG_COEFF_CONTROL, AD7768_REG_COEFF_CONTROL),
+ regmap_reg_range(AD7768_REG_ACCESS_KEY, AD7768_REG_ACCESS_KEY),
+};
- return (be32_to_cpu(st->data.d32) >> shift);
-}
+static const struct regmap_access_table ad7768_regmap_wr_table = {
+ .yes_ranges = ad7768_regmap_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad7768_regmap_wr_ranges),
+};
-static int ad7768_spi_reg_write(struct ad7768_state *st,
- unsigned int addr,
- unsigned int val)
-{
- st->data.d8[0] = AD7768_WR_FLAG_MSK(addr);
- st->data.d8[1] = val & 0xFF;
+static const struct regmap_config ad7768_regmap_config = {
+ .name = "ad7768-1-8",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = BIT(6),
+ .rd_table = &ad7768_regmap_rd_table,
+ .wr_table = &ad7768_regmap_wr_table,
+ .max_register = AD7768_REG_ACCESS_KEY,
+ .use_single_write = true,
+ .use_single_read = true,
+};
- return spi_write(st->spi, st->data.d8, 2);
-}
+static const struct regmap_range ad7768_regmap24_rd_ranges[] = {
+ regmap_reg_range(AD7768_REG24_ADC_DATA, AD7768_REG24_ADC_DATA),
+ regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA),
+};
-static int ad7768_set_mode(struct ad7768_state *st,
- enum ad7768_conv_mode mode)
-{
- int regval;
+static const struct regmap_access_table ad7768_regmap24_rd_table = {
+ .yes_ranges = ad7768_regmap24_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_rd_ranges),
+};
- regval = ad7768_spi_reg_read(st, AD7768_REG_CONVERSION, 1);
- if (regval < 0)
- return regval;
+static const struct regmap_range ad7768_regmap24_wr_ranges[] = {
+ regmap_reg_range(AD7768_REG24_COEFF_DATA, AD7768_REG24_COEFF_DATA),
+};
- regval &= ~AD7768_CONV_MODE_MSK;
- regval |= AD7768_CONV_MODE(mode);
+static const struct regmap_access_table ad7768_regmap24_wr_table = {
+ .yes_ranges = ad7768_regmap24_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad7768_regmap24_wr_ranges),
+};
- return ad7768_spi_reg_write(st, AD7768_REG_CONVERSION, regval);
+static const struct regmap_config ad7768_regmap24_config = {
+ .name = "ad7768-1-24",
+ .reg_bits = 8,
+ .val_bits = 24,
+ .read_flag_mask = BIT(6),
+ .rd_table = &ad7768_regmap24_rd_table,
+ .wr_table = &ad7768_regmap24_wr_table,
+ .max_register = AD7768_REG24_COEFF_DATA,
+};
+
+static int ad7768_set_mode(struct ad7768_state *st,
+ enum ad7768_conv_mode mode)
+{
+ return regmap_update_bits(st->regmap, AD7768_REG_CONVERSION,
+ AD7768_CONV_MODE_MSK, AD7768_CONV_MODE(mode));
}
static int ad7768_scan_direct(struct iio_dev *indio_dev)
@@ -233,9 +275,10 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
if (!ret)
return -ETIMEDOUT;
- readval = ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3);
- if (readval < 0)
- return readval;
+ ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval);
+ if (ret)
+ return ret;
+
/*
* Any SPI configuration of the AD7768-1 can only be
* performed in continuous conversion mode.
@@ -258,16 +301,23 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
+ ret = -EINVAL;
if (readval) {
- ret = ad7768_spi_reg_read(st, reg, 1);
- if (ret < 0)
- goto err_release;
- *readval = ret;
- ret = 0;
+ if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_rd_table))
+ ret = regmap_read(st->regmap, reg, readval);
+
+ if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_rd_table))
+ ret = regmap_read(st->regmap24, reg, readval);
+
} else {
- ret = ad7768_spi_reg_write(st, reg, writeval);
+ if (regmap_check_range_table(st->regmap, reg, &ad7768_regmap_wr_table))
+ ret = regmap_write(st->regmap, reg, writeval);
+
+ if (regmap_check_range_table(st->regmap24, reg, &ad7768_regmap24_wr_table))
+ ret = regmap_write(st->regmap24, reg, writeval);
+
}
-err_release:
+
iio_device_release_direct(indio_dev);
return ret;
@@ -284,7 +334,7 @@ static int ad7768_set_dig_fil(struct ad7768_state *st,
else
mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
- ret = ad7768_spi_reg_write(st, AD7768_REG_DIGITAL_FILTER, mode);
+ ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode);
if (ret < 0)
return ret;
@@ -321,7 +371,7 @@ static int ad7768_set_freq(struct ad7768_state *st,
*/
pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
- ret = ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK, pwr_mode);
+ ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode);
if (ret < 0)
return ret;
@@ -440,19 +490,30 @@ static int ad7768_setup(struct ad7768_state *st)
{
int ret;
- /*
- * Two writes to the SPI_RESET[1:0] bits are required to initiate
- * a software reset. The bits must first be set to 11, and then
- * to 10. When the sequence is detected, the reset occurs.
- * See the datasheet, page 70.
- */
- ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x3);
- if (ret)
- return ret;
+ st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->gpio_reset))
+ return PTR_ERR(st->gpio_reset);
- ret = ad7768_spi_reg_write(st, AD7768_REG_SYNC_RESET, 0x2);
- if (ret)
- return ret;
+ if (st->gpio_reset) {
+ fsleep(10);
+ gpiod_set_value_cansleep(st->gpio_reset, 0);
+ fsleep(200);
+ } else {
+ /*
+ * Two writes to the SPI_RESET[1:0] bits are required to initiate
+ * a software reset. The bits must first be set to 11, and then
+ * to 10. When the sequence is detected, the reset occurs.
+ * See the datasheet, page 70.
+ */
+ ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x3);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x2);
+ if (ret)
+ return ret;
+ }
st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in",
GPIOD_OUT_LOW);
@@ -474,8 +535,9 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p)
if (ret < 0)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->data.scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->data.scan,
+ sizeof(st->data.scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -505,18 +567,19 @@ static int ad7768_buffer_postenable(struct iio_dev *indio_dev)
* continuous read mode. Subsequent data reads do not require an
* initial 8-bit write to query the ADC_DATA register.
*/
- return ad7768_spi_reg_write(st, AD7768_REG_INTERFACE_FORMAT, 0x01);
+ return regmap_write(st->regmap, AD7768_REG_INTERFACE_FORMAT, 0x01);
}
static int ad7768_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int unused;
/*
* To exit continuous read mode, perform a single read of the ADC_DATA
* reg (0x2C), which allows further configuration of the device.
*/
- return ad7768_spi_reg_read(st, AD7768_REG_ADC_DATA, 3);
+ return regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &unused);
}
static const struct iio_buffer_setup_ops ad7768_buffer_ops = {
@@ -559,6 +622,31 @@ static int ad7768_set_channel_label(struct iio_dev *indio_dev,
return 0;
}
+static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ st->trig = devm_iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad7768_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(indio_dev->dev.parent, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad7768_trigger_handler,
+ &ad7768_buffer_ops);
+}
+
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
@@ -587,6 +675,16 @@ static int ad7768_probe(struct spi_device *spi)
st->spi = spi;
+ st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "Failed to initialize regmap");
+
+ st->regmap24 = devm_regmap_init_spi(spi, &ad7768_regmap24_config);
+ if (IS_ERR(st->regmap24))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap24),
+ "Failed to initialize regmap24");
+
st->vref = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->vref))
return PTR_ERR(st->vref);
@@ -619,20 +717,6 @@ static int ad7768_probe(struct spi_device *spi)
return ret;
}
- st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
- indio_dev->name,
- iio_device_id(indio_dev));
- if (!st->trig)
- return -ENOMEM;
-
- st->trig->ops = &ad7768_trigger_ops;
- iio_trigger_set_drvdata(st->trig, indio_dev);
- ret = devm_iio_trigger_register(&spi->dev, st->trig);
- if (ret)
- return ret;
-
- indio_dev->trig = iio_trigger_get(st->trig);
-
init_completion(&st->completion);
ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels));
@@ -646,10 +730,7 @@ static int ad7768_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
- &iio_pollfunc_store_time,
- &ad7768_trigger_handler,
- &ad7768_buffer_ops);
+ ret = ad7768_triggered_buffer_alloc(indio_dev);
if (ret)
return ret;
@@ -658,7 +739,7 @@ static int ad7768_probe(struct spi_device *spi)
static const struct spi_device_id ad7768_id_table[] = {
{ "ad7768-1", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad7768_id_table);
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
index a5d87faa5e12..845adc510239 100644
--- a/drivers/iio/adc/ad7779.c
+++ b/drivers/iio/adc/ad7779.c
@@ -595,7 +595,8 @@ static irqreturn_t ad7779_trigger_handler(int irq, void *p)
goto exit_handler;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
+ pf->timestamp);
exit_handler:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index 597c2686ffa4..041fc25e3209 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -464,7 +464,7 @@ static const struct spi_device_id ad7791_spi_ids[] = {
{ "ad7789", AD7789 },
{ "ad7790", AD7790 },
{ "ad7791", AD7791 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad7791_spi_ids);
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index 87945efb940b..0369151c7db1 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -207,8 +207,8 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p)
if (b_sent)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c
index 2f949fe55873..7722cf9e8214 100644
--- a/drivers/iio/adc/ad7944.c
+++ b/drivers/iio/adc/ad7944.c
@@ -190,11 +190,6 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
struct spi_transfer *xfers = adc->xfers;
/*
- * NB: can get better performance from some SPI controllers if we use
- * the same bits_per_word in every transfer.
- */
- xfers[0].bits_per_word = chan->scan_type.realbits;
- /*
* CS is tied to CNV and we need a low to high transition to start the
* conversion, so place CNV low for t_QUIET to prepare for this.
*/
@@ -208,7 +203,6 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc *
xfers[1].cs_off = 1;
xfers[1].delay.value = t_conv_ns;
xfers[1].delay.unit = SPI_DELAY_UNIT_NSECS;
- xfers[1].bits_per_word = chan->scan_type.realbits;
/* Then we can read the data during the acquisition phase */
xfers[2].rx_buf = &adc->sample.raw;
@@ -228,11 +222,6 @@ static int ad7944_4wire_mode_init_msg(struct device *dev, struct ad7944_adc *adc
struct spi_transfer *xfers = adc->xfers;
/*
- * NB: can get better performance from some SPI controllers if we use
- * the same bits_per_word in every transfer.
- */
- xfers[0].bits_per_word = chan->scan_type.realbits;
- /*
* CS has to be high for full conversion time to avoid triggering the
* busy indication.
*/
@@ -377,6 +366,8 @@ static int ad7944_single_conversion(struct ad7944_adc *adc,
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, chan->scan_type.realbits - 1);
+ else
+ *val &= GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
}
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 993f4651b73a..9c02f9199139 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -958,7 +958,7 @@ static const struct i2c_device_id ad799x_id[] = {
{ "ad7994", ad7994 },
{ "ad7997", ad7997 },
{ "ad7998", ad7998 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad799x_id);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 6c37f8e21120..4c5f8d29a559 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -587,6 +587,10 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
* byte set to zero. */
ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]);
break;
+
+ default:
+ dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size);
+ goto irq_handled;
}
/*
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index cf942c043457..4116c44197b8 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -702,7 +702,7 @@ static const struct of_device_id adi_axi_adc_of_match[] = {
{ .compatible = "adi,axi-adc-10.0.a", .data = &adc_generic },
{ .compatible = "adi,axi-ad485x", .data = &adi_axi_ad485x },
{ .compatible = "adi,axi-ad7606x", .data = &adc_ad7606 },
- { /* end of list */ }
+ { }
};
MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match);
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 414610afcb2c..c3450246730e 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -586,15 +586,6 @@ struct at91_adc_temp {
u16 saved_oversampling;
};
-/*
- * Buffer size requirements:
- * No channels * bytes_per_channel(2) + timestamp bytes (8)
- * Divided by 2 because we need half words.
- * We assume 32 channels for now, has to be increased if needed.
- * Nobody minds a buffer being too big.
- */
-#define AT91_BUFFER_MAX_HWORDS ((32 * 2 + 8) / 2)
-
struct at91_adc_state {
void __iomem *base;
int irq;
@@ -616,8 +607,8 @@ struct at91_adc_state {
struct at91_adc_temp temp_st;
struct iio_dev *indio_dev;
struct device *dev;
- /* Ensure naturally aligned timestamp */
- u16 buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8);
+ /* We assume 32 channels for now, has to be increased if needed. */
+ IIO_DECLARE_BUFFER_WITH_TS(u16, buffer, 32);
/*
* lock to prevent concurrent 'single conversion' requests through
* sysfs.
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 9fd7027623d0..71584ffd3632 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -163,14 +163,14 @@ static const struct iio_map axp20x_maps[] = {
IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"),
IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"),
IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"),
- { /* sentinel */ }
+ { }
};
static const struct iio_map axp22x_maps[] = {
IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"),
IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"),
IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"),
- { /* sentinel */ }
+ { }
};
static struct iio_map axp717_maps[] = {
@@ -1074,7 +1074,7 @@ static const struct of_device_id axp20x_adc_of_match[] = {
{ .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, },
{ .compatible = "x-powers,axp717-adc", .data = (void *)&axp717_data, },
{ .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, axp20x_adc_of_match);
@@ -1084,7 +1084,7 @@ static const struct platform_device_id axp20x_adc_id_match[] = {
{ .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, },
{ .name = "axp717-adc", .driver_data = (kernel_ulong_t)&axp717_data, },
{ .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, },
- { /* sentinel */ },
+ { }
};
MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match);
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
index 45542efc3ece..c8283279c477 100644
--- a/drivers/iio/adc/axp288_adc.c
+++ b/drivers/iio/adc/axp288_adc.c
@@ -110,7 +110,7 @@ static const struct iio_map axp288_adc_default_maps[] = {
IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
- {},
+ { }
};
static int axp288_adc_read_channel(int *val, unsigned long address,
@@ -207,7 +207,7 @@ static const struct dmi_system_id axp288_adc_ts_bias_override[] = {
},
.driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA,
},
- {}
+ { }
};
static int axp288_adc_initialize(struct axp288_adc_info *info)
diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c
index c218acf6c9c6..ba7cbd3b4822 100644
--- a/drivers/iio/adc/cpcap-adc.c
+++ b/drivers/iio/adc/cpcap-adc.c
@@ -942,7 +942,7 @@ static const struct of_device_id cpcap_adc_id_table[] = {
.compatible = "motorola,mapphone-cpcap-adc",
.data = &mapphone_adc,
},
- { /* sentinel */ },
+ { }
};
MODULE_DEVICE_TABLE(of, cpcap_adc_id_table);
diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
index 0290345ade84..b99291ce2a45 100644
--- a/drivers/iio/adc/da9150-gpadc.c
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -296,7 +296,7 @@ static const struct iio_map da9150_gpadc_default_maps[] = {
IIO_MAP("VBUS", "da9150-charger", "CHAN_VBUS"),
IIO_MAP("TJUNC_CORE", "da9150-charger", "CHAN_TJUNC"),
IIO_MAP("VBAT", "da9150-charger", "CHAN_VBAT"),
- {},
+ { }
};
static int da9150_gpadc_probe(struct platform_device *pdev)
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 359e26e3f5bc..9dbd2c87938c 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -488,8 +488,8 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
(void *)dev_data.values + t->from, t->length);
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c
index e911c25d106d..5b16fe737659 100644
--- a/drivers/iio/adc/envelope-detector.c
+++ b/drivers/iio/adc/envelope-detector.c
@@ -305,7 +305,7 @@ static const struct iio_chan_spec_ext_info envelope_detector_ext_info[] = {
{ .name = "compare_interval",
.read = envelope_show_comp_interval,
.write = envelope_store_comp_interval, },
- { /* sentinel */ }
+ { }
};
static const struct iio_chan_spec envelope_detector_iio_channel = {
@@ -390,7 +390,7 @@ static int envelope_detector_probe(struct platform_device *pdev)
static const struct of_device_id envelope_detector_match[] = {
{ .compatible = "axentia,tse850-envelope-detector", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, envelope_detector_match);
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
index b3f037510e35..f8c220f6a7b4 100644
--- a/drivers/iio/adc/fsl-imx25-gcq.c
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -372,7 +372,7 @@ static int mx25_gcq_probe(struct platform_device *pdev)
static const struct of_device_id mx25_gcq_ids[] = {
{ .compatible = "fsl,imx25-gcq", },
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mx25_gcq_ids);
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index 689e34f06987..b4562aae8477 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -351,7 +351,7 @@ static const struct iio_enum hi8435_sensing_mode = {
static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
IIO_ENUM_AVAILABLE("sensing_mode", IIO_SHARED_BY_TYPE, &hi8435_sensing_mode),
- {},
+ { }
};
#define HI8435_VOLTAGE_CHANNEL(num) \
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 8da0419ecfa3..7235fa9e13d5 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -87,7 +87,10 @@ struct hx711_data {
* triggered buffer
* 2x32-bit channel + 64-bit naturally aligned timestamp
*/
- u32 buffer[4] __aligned(8);
+ struct {
+ u32 channel[2];
+ aligned_s64 timestamp;
+ } buffer;
/*
* delay after a rising edge on SCK until the data is ready DOUT
* this is dependent on the hx711 where the datasheet tells a
@@ -361,15 +364,15 @@ static irqreturn_t hx711_trigger(int irq, void *p)
mutex_lock(&hx711_data->lock);
- memset(hx711_data->buffer, 0, sizeof(hx711_data->buffer));
+ memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer));
iio_for_each_active_channel(indio_dev, i) {
- hx711_data->buffer[j] = hx711_reset_read(hx711_data,
+ hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data,
indio_dev->channels[i].channel);
j++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, hx711_data->buffer,
+ iio_push_to_buffers_with_timestamp(indio_dev, &hx711_data->buffer,
pf->timestamp);
mutex_unlock(&hx711_data->lock);
diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c
index 828d3fea6d43..09ce71f6e941 100644
--- a/drivers/iio/adc/imx7d_adc.c
+++ b/drivers/iio/adc/imx7d_adc.c
@@ -413,7 +413,7 @@ static const struct iio_info imx7d_adc_iio_info = {
static const struct of_device_id imx7d_adc_match[] = {
{ .compatible = "fsl,imx7d-adc", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, imx7d_adc_match);
diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c
index 3d19d7d744aa..be13a6ed7e00 100644
--- a/drivers/iio/adc/imx8qxp-adc.c
+++ b/drivers/iio/adc/imx8qxp-adc.c
@@ -481,7 +481,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(imx8qxp_adc_pm_ops,
static const struct of_device_id imx8qxp_adc_match[] = {
{ .compatible = "nxp,imx8qxp-adc", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c
index 002eb19587d6..7feaafd2316f 100644
--- a/drivers/iio/adc/imx93_adc.c
+++ b/drivers/iio/adc/imx93_adc.c
@@ -464,7 +464,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(imx93_adc_pm_ops,
static const struct of_device_id imx93_adc_match[] = {
{ .compatible = "nxp,imx93-adc", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, imx93_adc_match);
diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c
index 40d14faa71c5..857e1b69d6cd 100644
--- a/drivers/iio/adc/ina2xx-adc.c
+++ b/drivers/iio/adc/ina2xx-adc.c
@@ -766,7 +766,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
chip->scan.chan[i++] = val;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &chip->scan, time);
+ iio_push_to_buffers_with_ts(indio_dev, &chip->scan, sizeof(chip->scan), time);
return 0;
};
diff --git a/drivers/iio/adc/industrialio-adc.c b/drivers/iio/adc/industrialio-adc.c
new file mode 100644
index 000000000000..b4057230e749
--- /dev/null
+++ b/drivers/iio/adc/industrialio-adc.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Helpers for parsing common ADC information from a firmware node.
+ *
+ * Copyright (c) 2025 Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/types.h>
+
+#include <linux/iio/adc-helpers.h>
+#include <linux/iio/iio.h>
+
+/**
+ * devm_iio_adc_device_alloc_chaninfo_se - allocate and fill iio_chan_spec for ADC
+ *
+ * Scan the device node for single-ended ADC channel information. Channel ID is
+ * expected to be found from the "reg" property. Allocate and populate the
+ * iio_chan_spec structure corresponding to channels that are found. The memory
+ * for iio_chan_spec structure will be freed upon device detach.
+ *
+ * @dev: Pointer to the ADC device.
+ * @template: Template iio_chan_spec from which the fields of all
+ * found and allocated channels are initialized.
+ * @max_chan_id: Maximum value of a channel ID. Use negative value if no
+ * checking is required.
+ * @cs: Location where pointer to allocated iio_chan_spec
+ * should be stored.
+ *
+ * Return: Number of found channels on success. Negative value to indicate
+ * failure. Specifically, -ENOENT if no channel nodes were found.
+ */
+int devm_iio_adc_device_alloc_chaninfo_se(struct device *dev,
+ const struct iio_chan_spec *template,
+ int max_chan_id,
+ struct iio_chan_spec **cs)
+{
+ struct iio_chan_spec *chan_array, *chan;
+ int num_chan, ret;
+
+ num_chan = iio_adc_device_num_channels(dev);
+ if (num_chan < 0)
+ return num_chan;
+
+ if (!num_chan)
+ return -ENOENT;
+
+ chan_array = devm_kcalloc(dev, num_chan, sizeof(*chan_array),
+ GFP_KERNEL);
+ if (!chan_array)
+ return -ENOMEM;
+
+ chan = &chan_array[0];
+
+ device_for_each_named_child_node_scoped(dev, child, "channel") {
+ u32 ch;
+
+ ret = fwnode_property_read_u32(child, "reg", &ch);
+ if (ret)
+ return ret;
+
+ if (max_chan_id >= 0 && ch > max_chan_id)
+ return -ERANGE;
+
+ *chan = *template;
+ chan->channel = ch;
+ chan++;
+ }
+
+ *cs = chan_array;
+
+ return num_chan;
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_adc_device_alloc_chaninfo_se, "IIO_DRIVER");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("IIO ADC fwnode parsing helpers");
diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c
index c178850eaaab..101c1a0ce591 100644
--- a/drivers/iio/adc/intel_mrfld_adc.c
+++ b/drivers/iio/adc/intel_mrfld_adc.c
@@ -174,7 +174,7 @@ static const struct iio_map iio_maps[] = {
IIO_MAP("CH6", "bcove-temp", "SYSTEMP0"),
IIO_MAP("CH7", "bcove-temp", "SYSTEMP1"),
IIO_MAP("CH8", "bcove-temp", "SYSTEMP2"),
- {}
+ { }
};
static int mrfld_adc_probe(struct platform_device *pdev)
@@ -222,7 +222,7 @@ static int mrfld_adc_probe(struct platform_device *pdev)
static const struct platform_device_id mrfld_adc_id_table[] = {
{ .name = "mrfld_bcove_adc" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table);
diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c
index 450a243d1f7c..7e5d181ff702 100644
--- a/drivers/iio/adc/lpc18xx_adc.c
+++ b/drivers/iio/adc/lpc18xx_adc.c
@@ -188,7 +188,7 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
static const struct of_device_id lpc18xx_adc_match[] = {
{ .compatible = "nxp,lpc1850-adc" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, lpc18xx_adc_match);
diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c
index 97c417c3a4eb..a579107fd5c9 100644
--- a/drivers/iio/adc/ltc2471.c
+++ b/drivers/iio/adc/ltc2471.c
@@ -138,7 +138,7 @@ static int ltc2471_i2c_probe(struct i2c_client *client)
static const struct i2c_device_id ltc2471_i2c_id[] = {
{ "ltc2471", ltc2471 },
{ "ltc2473", ltc2473 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id);
diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c
index 565ca2e21c0c..7d7001e8e3d9 100644
--- a/drivers/iio/adc/max1118.c
+++ b/drivers/iio/adc/max1118.c
@@ -188,8 +188,8 @@ static irqreturn_t max1118_trigger_handler(int irq, void *p)
adc->scan.channels[i] = ret;
i++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan),
+ iio_get_time_ns(indio_dev));
out:
mutex_unlock(&adc->lock);
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
index 437d9f24b5a1..511b2f14dfaf 100644
--- a/drivers/iio/adc/max11410.c
+++ b/drivers/iio/adc/max11410.c
@@ -632,8 +632,8 @@ static irqreturn_t max11410_trigger_handler(int irq, void *p)
goto out;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 35717ec082ce..a7e9912fb44a 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1498,8 +1498,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
if (b_sent < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
@@ -1551,7 +1551,7 @@ static const struct of_device_id max1363_of_match[] = {
MAX1363_COMPATIBLE("maxim,max11645", max11645),
MAX1363_COMPATIBLE("maxim,max11646", max11646),
MAX1363_COMPATIBLE("maxim,max11647", max11647),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, max1363_of_match);
@@ -1672,7 +1672,7 @@ static const struct i2c_device_id max1363_id[] = {
MAX1363_ID_TABLE("max11645", max11645),
MAX1363_ID_TABLE("max11646", max11646),
MAX1363_ID_TABLE("max11647", max11647),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, max1363_id);
diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c
index 21d024bde16b..0aa04d143ad4 100644
--- a/drivers/iio/adc/max77541-adc.c
+++ b/drivers/iio/adc/max77541-adc.c
@@ -176,7 +176,7 @@ static int max77541_adc_probe(struct platform_device *pdev)
static const struct platform_device_id max77541_adc_platform_id[] = {
{ "max77541-adc" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id);
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index 6748b44d568d..a6f21791c685 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -6,11 +6,13 @@
* Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
*/
#include <linux/bitfield.h>
-#include <linux/bits.h>
+#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dev_printk.h>
#include <linux/err.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
@@ -79,6 +81,8 @@
#define MCP3910_CONFIG1_CLKEXT BIT(6)
#define MCP3910_CONFIG1_VREFEXT BIT(7)
+#define MCP3910_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch))
+
#define MCP3910_REG_OFFCAL_CH0 0x0f
#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6)
@@ -110,6 +114,7 @@ struct mcp3911_chip_info {
int (*get_offset)(struct mcp3911 *adc, int channel, int *val);
int (*set_offset)(struct mcp3911 *adc, int channel, int val);
int (*set_scale)(struct mcp3911 *adc, int channel, u32 val);
+ int (*get_raw)(struct mcp3911 *adc, int channel, int *val);
};
struct mcp3911 {
@@ -170,6 +175,18 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len
return mcp3911_write(adc, reg, val, len);
}
+static int mcp3911_read_s24(struct mcp3911 *const adc, u8 const reg, s32 *const val)
+{
+ u32 uval;
+ int const ret = mcp3911_read(adc, reg, &uval, 3);
+
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(uval, 23);
+ return ret;
+}
+
static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable)
{
unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL;
@@ -194,6 +211,11 @@ static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val)
return adc->chip->enable_offset(adc, 1);
}
+static int mcp3910_get_raw(struct mcp3911 *adc, int channel, s32 *val)
+{
+ return mcp3911_read_s24(adc, MCP3910_CHANNEL(channel), val);
+}
+
static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable)
{
unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL;
@@ -218,6 +240,11 @@ static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val)
return adc->chip->enable_offset(adc, 1);
}
+static int mcp3911_get_raw(struct mcp3911 *adc, int channel, s32 *val)
+{
+ return mcp3911_read_s24(adc, MCP3911_CHANNEL(channel), val);
+}
+
static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val)
{
int ret;
@@ -321,12 +348,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
guard(mutex)(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = mcp3911_read(adc,
- MCP3911_CHANNEL(channel->channel), val, 3);
+ ret = adc->chip->get_raw(adc, channel->channel, val);
if (ret)
return ret;
-
- *val = sign_extend32(*val, 23);
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
ret = adc->chip->get_offset(adc, channel->channel, val);
@@ -516,8 +540,8 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
adc->scan.channels[i] = get_unaligned_be24(&adc->rx_buf[scan_chan->channel * 3]);
i++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -684,6 +708,7 @@ static const struct iio_trigger_ops mcp3911_trigger_ops = {
static int mcp3911_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
+ struct gpio_desc *gpio_reset;
struct iio_dev *indio_dev;
struct mcp3911 *adc;
bool external_vref;
@@ -728,6 +753,22 @@ static int mcp3911_probe(struct spi_device *spi)
}
dev_dbg(dev, "use device address %i\n", adc->dev_addr);
+ gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpio_reset))
+ return dev_err_probe(dev, PTR_ERR(gpio_reset),
+ "Cannot get reset GPIO\n");
+
+ if (gpio_reset) {
+ gpiod_set_value_cansleep(gpio_reset, 0);
+
+ /*
+ * Settling time after Hard Reset Mode (determined experimentally):
+ * 330 micro-seconds are too few; 470 micro-seconds are sufficient.
+ * Just in case, we add some safety factor...
+ */
+ fsleep(600);
+ }
+
ret = adc->chip->config(adc, external_vref);
if (ret)
return ret;
@@ -799,6 +840,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3911] = {
.channels = mcp3911_channels,
@@ -810,6 +852,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3911_get_offset,
.set_offset = mcp3911_set_offset,
.set_scale = mcp3911_set_scale,
+ .get_raw = mcp3911_get_raw,
},
[MCP3912] = {
.channels = mcp3912_channels,
@@ -821,6 +864,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3913] = {
.channels = mcp3913_channels,
@@ -832,6 +876,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3914] = {
.channels = mcp3914_channels,
@@ -843,6 +888,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3918] = {
.channels = mcp3918_channels,
@@ -854,6 +900,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3919] = {
.channels = mcp3919_channels,
@@ -865,6 +912,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
};
static const struct of_device_id mcp3911_dt_ids[] = {
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
index 997def4a4d2f..4ff88603e4fc 100644
--- a/drivers/iio/adc/meson_saradc.c
+++ b/drivers/iio/adc/meson_saradc.c
@@ -160,6 +160,11 @@
#define MESON_SAR_ADC_REG11_EOC BIT(1)
#define MESON_SAR_ADC_REG11_VREF_SEL BIT(0)
+#define MESON_SAR_ADC_REG12 0x30
+ #define MESON_SAR_ADC_REG12_MPLL0_UNKNOWN BIT(0)
+ #define MESON_SAR_ADC_REG12_MPLL1_UNKNOWN BIT(1)
+ #define MESON_SAR_ADC_REG12_MPLL2_UNKNOWN BIT(2)
+
#define MESON_SAR_ADC_REG13 0x34
#define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8)
@@ -326,6 +331,7 @@ struct meson_sar_adc_param {
u8 cmv_select;
u8 adc_eoc;
enum meson_sar_adc_vref_sel vref_voltage;
+ bool enable_mpll_clock_workaround;
};
struct meson_sar_adc_data {
@@ -995,6 +1001,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
priv->param->cmv_select);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
MESON_SAR_ADC_REG11_CMV_SEL, regval);
+
+ if (priv->param->enable_mpll_clock_workaround) {
+ dev_warn(dev,
+ "Enabling unknown bits to make the MPLL clocks work. This may change so always update dtbs and kernel together\n");
+ regmap_write(priv->regmap, MESON_SAR_ADC_REG12,
+ MESON_SAR_ADC_REG12_MPLL0_UNKNOWN |
+ MESON_SAR_ADC_REG12_MPLL1_UNKNOWN |
+ MESON_SAR_ADC_REG12_MPLL2_UNKNOWN);
+ }
}
ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
@@ -1219,6 +1234,17 @@ static const struct meson_sar_adc_param meson_sar_adc_gxl_param = {
.cmv_select = 1,
};
+static const struct meson_sar_adc_param meson_sar_adc_gxlx_param = {
+ .has_bl30_integration = true,
+ .clock_rate = 1200000,
+ .regmap_config = &meson_sar_adc_regmap_config_gxbb,
+ .resolution = 12,
+ .disable_ring_counter = 1,
+ .vref_voltage = 1,
+ .cmv_select = true,
+ .enable_mpll_clock_workaround = true,
+};
+
static const struct meson_sar_adc_param meson_sar_adc_axg_param = {
.has_bl30_integration = true,
.clock_rate = 1200000,
@@ -1267,6 +1293,11 @@ static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
.name = "meson-gxl-saradc",
};
+static const struct meson_sar_adc_data meson_sar_adc_gxlx_data = {
+ .param = &meson_sar_adc_gxlx_param,
+ .name = "meson-gxlx-saradc",
+};
+
static const struct meson_sar_adc_data meson_sar_adc_gxm_data = {
.param = &meson_sar_adc_gxl_param,
.name = "meson-gxm-saradc",
@@ -1299,6 +1330,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
.compatible = "amlogic,meson-gxl-saradc",
.data = &meson_sar_adc_gxl_data,
}, {
+ .compatible = "amlogic,meson-gxlx-saradc",
+ .data = &meson_sar_adc_gxlx_data,
+ }, {
.compatible = "amlogic,meson-gxm-saradc",
.data = &meson_sar_adc_gxm_data,
}, {
@@ -1308,7 +1342,7 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
.compatible = "amlogic,meson-g12a-saradc",
.data = &meson_sar_adc_g12a_data,
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match);
diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c
index a4970cfb49a5..eecf88b05c6f 100644
--- a/drivers/iio/adc/mt6359-auxadc.c
+++ b/drivers/iio/adc/mt6359-auxadc.c
@@ -588,7 +588,7 @@ static const struct of_device_id mt6359_auxadc_of_match[] = {
{ .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
{ .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
{ .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index 4eb2455d6ffa..f8e98b6fa7e9 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -263,8 +263,8 @@ static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p)
struct mt6360_adc_data *mad = iio_priv(indio_dev);
struct {
u16 values[MT6360_CHAN_MAX];
- int64_t timestamp;
- } data __aligned(8);
+ aligned_s64 timestamp;
+ } data;
int i = 0, bit, val, ret;
memset(&data, 0, sizeof(data));
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
index 0bc112135bca..7c71fe5e8d31 100644
--- a/drivers/iio/adc/mt6370-adc.c
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -336,7 +336,7 @@ static int mt6370_adc_probe(struct platform_device *pdev)
static const struct of_device_id mt6370_adc_of_id[] = {
{ .compatible = "mediatek,mt6370-adc", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c
index 152cbe265e1a..92baf3f5f560 100644
--- a/drivers/iio/adc/mxs-lradc-adc.c
+++ b/drivers/iio/adc/mxs-lradc-adc.c
@@ -141,9 +141,8 @@ static int mxs_lradc_adc_read_single(struct iio_dev *iio_dev, int chan,
* the same time, yet the code becomes horribly complicated. Therefore I
* applied KISS principle here.
*/
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
reinit_completion(&adc->completion);
@@ -192,7 +191,7 @@ err:
writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
adc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return ret;
}
@@ -275,9 +274,8 @@ static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev,
adc->scale_avail[chan->channel];
int ret;
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
switch (m) {
case IIO_CHAN_INFO_SCALE:
@@ -300,7 +298,7 @@ static int mxs_lradc_adc_write_raw(struct iio_dev *iio_dev,
break;
}
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return ret;
}
@@ -427,7 +425,8 @@ static irqreturn_t mxs_lradc_adc_trigger_handler(int irq, void *p)
j++;
}
- iio_push_to_buffers_with_timestamp(iio, adc->buffer, pf->timestamp);
+ iio_push_to_buffers_with_ts(iio, adc->buffer, sizeof(adc->buffer),
+ pf->timestamp);
iio_trigger_notify_done(iio->trig);
diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c
new file mode 100644
index 000000000000..d87824e5490f
--- /dev/null
+++ b/drivers/iio/adc/nct7201.c
@@ -0,0 +1,501 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Nuvoton nct7201 and nct7202 power monitor chips.
+ *
+ * Copyright (c) 2024-2025 Nuvoton Technology corporation.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+
+#define NCT7201_REG_INTERRUPT_STATUS 0x0C
+#define NCT7201_REG_VOLT_LOW_BYTE 0x0F
+#define NCT7201_REG_CONFIGURATION 0x10
+#define NCT7201_BIT_CONFIGURATION_START BIT(0)
+#define NCT7201_BIT_CONFIGURATION_ALERT_MSK BIT(1)
+#define NCT7201_BIT_CONFIGURATION_CONV_RATE BIT(2)
+#define NCT7201_BIT_CONFIGURATION_RESET BIT(7)
+
+#define NCT7201_REG_ADVANCED_CONFIGURATION 0x11
+#define NCT7201_BIT_ADVANCED_CONF_MOD_ALERT BIT(0)
+#define NCT7201_BIT_ADVANCED_CONF_MOD_STS BIT(1)
+#define NCT7201_BIT_ADVANCED_CONF_FAULT_QUEUE BIT(2)
+#define NCT7201_BIT_ADVANCED_CONF_EN_DEEP_SHUTDOWN BIT(4)
+#define NCT7201_BIT_ADVANCED_CONF_EN_SMB_TIMEOUT BIT(5)
+#define NCT7201_BIT_ADVANCED_CONF_MOD_RSTIN BIT(7)
+
+#define NCT7201_REG_CHANNEL_INPUT_MODE 0x12
+#define NCT7201_REG_CHANNEL_ENABLE 0x13
+#define NCT7201_REG_INTERRUPT_MASK_1 0x15
+#define NCT7201_REG_INTERRUPT_MASK_2 0x16
+#define NCT7201_REG_BUSY_STATUS 0x1E
+#define NCT7201_BIT_BUSY BIT(0)
+#define NCT7201_BIT_PWR_UP BIT(1)
+#define NCT7201_REG_ONE_SHOT 0x1F
+#define NCT7201_REG_SMUS_ADDRESS 0xFC
+#define NCT7201_REG_VIN_MASK GENMASK(15, 3)
+
+#define NCT7201_REG_VIN(i) (0x00 + i)
+#define NCT7201_REG_VIN_HIGH_LIMIT(i) (0x20 + (i) * 2)
+#define NCT7201_REG_VIN_LOW_LIMIT(i) (0x21 + (i) * 2)
+#define NCT7201_MAX_CHANNEL 12
+
+static const struct regmap_range nct7201_read_reg_range[] = {
+ regmap_reg_range(NCT7201_REG_INTERRUPT_STATUS, NCT7201_REG_BUSY_STATUS),
+ regmap_reg_range(NCT7201_REG_SMUS_ADDRESS, NCT7201_REG_SMUS_ADDRESS),
+};
+
+static const struct regmap_access_table nct7201_readable_regs_tbl = {
+ .yes_ranges = nct7201_read_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(nct7201_read_reg_range),
+};
+
+static const struct regmap_range nct7201_write_reg_range[] = {
+ regmap_reg_range(NCT7201_REG_CONFIGURATION, NCT7201_REG_INTERRUPT_MASK_2),
+ regmap_reg_range(NCT7201_REG_ONE_SHOT, NCT7201_REG_ONE_SHOT),
+};
+
+static const struct regmap_access_table nct7201_writeable_regs_tbl = {
+ .yes_ranges = nct7201_write_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(nct7201_write_reg_range),
+};
+
+static const struct regmap_range nct7201_read_vin_reg_range[] = {
+ regmap_reg_range(NCT7201_REG_VIN(0), NCT7201_REG_VIN(NCT7201_MAX_CHANNEL - 1)),
+ regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0),
+ NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)),
+};
+
+static const struct regmap_access_table nct7201_readable_vin_regs_tbl = {
+ .yes_ranges = nct7201_read_vin_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(nct7201_read_vin_reg_range),
+};
+
+static const struct regmap_range nct7201_write_vin_reg_range[] = {
+ regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0),
+ NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)),
+};
+
+static const struct regmap_access_table nct7201_writeable_vin_regs_tbl = {
+ .yes_ranges = nct7201_write_vin_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(nct7201_write_vin_reg_range),
+};
+
+static const struct regmap_config nct7201_regmap8_config = {
+ .name = "vin-data-read-byte",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = 0xff,
+ .rd_table = &nct7201_readable_regs_tbl,
+ .wr_table = &nct7201_writeable_regs_tbl,
+};
+
+static const struct regmap_config nct7201_regmap16_config = {
+ .name = "vin-data-read-word",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 0xff,
+ .rd_table = &nct7201_readable_vin_regs_tbl,
+ .wr_table = &nct7201_writeable_vin_regs_tbl,
+};
+
+struct nct7201_chip_info {
+ struct regmap *regmap;
+ struct regmap *regmap16;
+ int num_vin_channels;
+ __le16 vin_mask;
+};
+
+struct nct7201_adc_model_data {
+ const char *model_name;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+ int num_vin_channels;
+};
+
+static const struct iio_event_spec nct7201_events[] = {
+ {
+ .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 NCT7201_VOLTAGE_CHANNEL(num) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = num + 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .address = num, \
+ .event_spec = nct7201_events, \
+ .num_event_specs = ARRAY_SIZE(nct7201_events), \
+ }
+
+static const struct iio_chan_spec nct7201_channels[] = {
+ NCT7201_VOLTAGE_CHANNEL(0),
+ NCT7201_VOLTAGE_CHANNEL(1),
+ NCT7201_VOLTAGE_CHANNEL(2),
+ NCT7201_VOLTAGE_CHANNEL(3),
+ NCT7201_VOLTAGE_CHANNEL(4),
+ NCT7201_VOLTAGE_CHANNEL(5),
+ NCT7201_VOLTAGE_CHANNEL(6),
+ NCT7201_VOLTAGE_CHANNEL(7),
+};
+
+static const struct iio_chan_spec nct7202_channels[] = {
+ NCT7201_VOLTAGE_CHANNEL(0),
+ NCT7201_VOLTAGE_CHANNEL(1),
+ NCT7201_VOLTAGE_CHANNEL(2),
+ NCT7201_VOLTAGE_CHANNEL(3),
+ NCT7201_VOLTAGE_CHANNEL(4),
+ NCT7201_VOLTAGE_CHANNEL(5),
+ NCT7201_VOLTAGE_CHANNEL(6),
+ NCT7201_VOLTAGE_CHANNEL(7),
+ NCT7201_VOLTAGE_CHANNEL(8),
+ NCT7201_VOLTAGE_CHANNEL(9),
+ NCT7201_VOLTAGE_CHANNEL(10),
+ NCT7201_VOLTAGE_CHANNEL(11),
+};
+
+static int nct7201_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct nct7201_chip_info *chip = iio_priv(indio_dev);
+ unsigned int value;
+ int err;
+
+ if (chan->type != IIO_VOLTAGE)
+ return -EOPNOTSUPP;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ err = regmap_read(chip->regmap16, NCT7201_REG_VIN(chan->address), &value);
+ if (err)
+ return err;
+ *val = FIELD_GET(NCT7201_REG_VIN_MASK, value);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* From the datasheet, we have to multiply by 0.0004995 */
+ *val = 0;
+ *val2 = 499500;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int nct7201_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct nct7201_chip_info *chip = iio_priv(indio_dev);
+ unsigned int value;
+ int err;
+
+ if (chan->type != IIO_VOLTAGE)
+ return -EOPNOTSUPP;
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EINVAL;
+
+ if (dir == IIO_EV_DIR_FALLING)
+ err = regmap_read(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address),
+ &value);
+ else
+ err = regmap_read(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address),
+ &value);
+ if (err)
+ return err;
+
+ *val = FIELD_GET(NCT7201_REG_VIN_MASK, value);
+
+ return IIO_VAL_INT;
+}
+
+static int nct7201_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct nct7201_chip_info *chip = iio_priv(indio_dev);
+ int err;
+
+ if (chan->type != IIO_VOLTAGE)
+ return -EOPNOTSUPP;
+
+ if (info != IIO_EV_INFO_VALUE)
+ return -EOPNOTSUPP;
+
+ if (dir == IIO_EV_DIR_FALLING)
+ err = regmap_write(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address),
+ FIELD_PREP(NCT7201_REG_VIN_MASK, val));
+ else
+ err = regmap_write(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address),
+ FIELD_PREP(NCT7201_REG_VIN_MASK, val));
+
+ return err;
+}
+
+static int nct7201_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 nct7201_chip_info *chip = iio_priv(indio_dev);
+
+ if (chan->type != IIO_VOLTAGE)
+ return -EOPNOTSUPP;
+
+ return !!(le16_to_cpu(chip->vin_mask) & BIT(chan->address));
+}
+
+static int nct7201_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ struct nct7201_chip_info *chip = iio_priv(indio_dev);
+ __le16 mask = cpu_to_le16(BIT(chan->address));
+ int err;
+
+ if (chan->type != IIO_VOLTAGE)
+ return -EOPNOTSUPP;
+
+ if (state)
+ chip->vin_mask |= mask;
+ else
+ chip->vin_mask &= ~mask;
+
+ if (chip->num_vin_channels <= 8)
+ err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE,
+ le16_to_cpu(chip->vin_mask));
+ else
+ err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE,
+ &chip->vin_mask, sizeof(chip->vin_mask));
+
+ return err;
+}
+
+static const struct iio_info nct7201_info = {
+ .read_raw = nct7201_read_raw,
+ .read_event_config = nct7201_read_event_config,
+ .write_event_config = nct7201_write_event_config,
+ .read_event_value = nct7201_read_event_value,
+ .write_event_value = nct7201_write_event_value,
+};
+
+static const struct iio_info nct7201_info_no_irq = {
+ .read_raw = nct7201_read_raw,
+};
+
+static const struct nct7201_adc_model_data nct7201_model_data = {
+ .model_name = "nct7201",
+ .channels = nct7201_channels,
+ .num_channels = ARRAY_SIZE(nct7201_channels),
+ .num_vin_channels = 8,
+};
+
+static const struct nct7201_adc_model_data nct7202_model_data = {
+ .model_name = "nct7202",
+ .channels = nct7202_channels,
+ .num_channels = ARRAY_SIZE(nct7202_channels),
+ .num_vin_channels = 12,
+};
+
+static int nct7201_init_chip(struct nct7201_chip_info *chip)
+{
+ struct device *dev = regmap_get_device(chip->regmap);
+ __le16 data = cpu_to_le16(GENMASK(chip->num_vin_channels - 1, 0));
+ unsigned int value;
+ int err;
+
+ err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION,
+ NCT7201_BIT_CONFIGURATION_RESET);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to reset chip\n");
+
+ /*
+ * After about 25 msecs, the device should be ready and then the power-up
+ * bit will be set to 1.
+ */
+ fsleep(25 * USEC_PER_MSEC);
+
+ err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to read busy status\n");
+ if (!(value & NCT7201_BIT_PWR_UP))
+ return dev_err_probe(dev, -EIO, "Failed to power up after reset\n");
+
+ /* Enable Channels */
+ if (chip->num_vin_channels <= 8)
+ err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE,
+ le16_to_cpu(data));
+ else
+ err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE,
+ &data, sizeof(data));
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable channels\n");
+
+ err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE,
+ &chip->vin_mask, sizeof(chip->vin_mask));
+ if (err)
+ return dev_err_probe(dev, err,
+ "Failed to read channel enable register\n");
+
+ /* Start monitoring if needed */
+ err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION,
+ NCT7201_BIT_CONFIGURATION_START);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to start monitoring\n");
+
+ return 0;
+}
+
+static irqreturn_t nct7201_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct nct7201_chip_info *chip = iio_priv(indio_dev);
+ __le16 data;
+ int err;
+
+ err = regmap_bulk_read(chip->regmap, NCT7201_REG_INTERRUPT_STATUS,
+ &data, sizeof(data));
+ if (err)
+ return IRQ_NONE;
+
+ if (data)
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns(indio_dev));
+
+ return IRQ_HANDLED;
+}
+
+static int nct7201_probe(struct i2c_client *client)
+{
+ const struct nct7201_adc_model_data *model_data;
+ struct device *dev = &client->dev;
+ struct nct7201_chip_info *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ model_data = i2c_get_match_data(client);
+ if (!model_data)
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+ chip = iio_priv(indio_dev);
+
+ chip->regmap = devm_regmap_init_i2c(client, &nct7201_regmap8_config);
+ if (IS_ERR(chip->regmap))
+ return dev_err_probe(dev, PTR_ERR(chip->regmap),
+ "Failed to init regmap\n");
+
+ chip->regmap16 = devm_regmap_init_i2c(client, &nct7201_regmap16_config);
+ if (IS_ERR(chip->regmap16))
+ return dev_err_probe(dev, PTR_ERR(chip->regmap16),
+ "Failed to init regmap16\n");
+
+ chip->num_vin_channels = model_data->num_vin_channels;
+
+ ret = nct7201_init_chip(chip);
+ if (ret)
+ return ret;
+
+ indio_dev->name = model_data->model_name;
+ indio_dev->channels = model_data->channels;
+ indio_dev->num_channels = model_data->num_channels;
+ if (client->irq) {
+ /* Enable alert function */
+ ret = regmap_clear_bits(chip->regmap, NCT7201_REG_CONFIGURATION,
+ NCT7201_BIT_CONFIGURATION_ALERT_MSK);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable alert function\n");
+
+ ret = devm_request_threaded_irq(dev, client->irq,
+ NULL, nct7201_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->name, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to assign interrupt.\n");
+
+ indio_dev->info = &nct7201_info;
+ } else {
+ indio_dev->info = &nct7201_info_no_irq;
+ }
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id nct7201_id[] = {
+ { .name = "nct7201", .driver_data = (kernel_ulong_t)&nct7201_model_data },
+ { .name = "nct7202", .driver_data = (kernel_ulong_t)&nct7202_model_data },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nct7201_id);
+
+static const struct of_device_id nct7201_of_match[] = {
+ {
+ .compatible = "nuvoton,nct7201",
+ .data = &nct7201_model_data,
+ },
+ {
+ .compatible = "nuvoton,nct7202",
+ .data = &nct7202_model_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nct7201_of_match);
+
+static struct i2c_driver nct7201_driver = {
+ .driver = {
+ .name = "nct7201",
+ .of_match_table = nct7201_of_match,
+ },
+ .probe = nct7201_probe,
+ .id_table = nct7201_id,
+};
+module_i2c_driver(nct7201_driver);
+
+MODULE_AUTHOR("Eason Yang <j2anfernee@gmail.com>");
+MODULE_DESCRIPTION("Nuvoton NCT7201 voltage monitor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c
index 7c1511ee3a4b..c8283873cdee 100644
--- a/drivers/iio/adc/npcm_adc.c
+++ b/drivers/iio/adc/npcm_adc.c
@@ -196,7 +196,7 @@ static const struct iio_info npcm_adc_iio_info = {
static const struct of_device_id npcm_adc_match[] = {
{ .compatible = "nuvoton,npcm750-adc", .data = &npxm7xx_adc_info},
{ .compatible = "nuvoton,npcm845-adc", .data = &npxm8xx_adc_info},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, npcm_adc_match);
diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c
index beb5511c4504..72aa4ca2e5a4 100644
--- a/drivers/iio/adc/pac1921.c
+++ b/drivers/iio/adc/pac1921.c
@@ -900,7 +900,7 @@ static ssize_t pac1921_read_scale_avail(struct iio_dev *indio_dev,
static const struct iio_chan_spec_ext_info pac1921_ext_info_voltage[] = {
PAC1921_EXT_INFO_SCALE_AVAIL,
- {}
+ { }
};
static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] = {
@@ -911,7 +911,7 @@ static const struct iio_chan_spec_ext_info pac1921_ext_info_current[] = {
.write = pac1921_write_shunt_resistor,
.shared = IIO_SEPARATE,
},
- {}
+ { }
};
static const struct iio_event_spec pac1921_overflow_event[] = {
@@ -1044,7 +1044,8 @@ static irqreturn_t pac1921_trigger_handler(int irq, void *p)
priv->scan.chan[ch++] = val;
}
- iio_push_to_buffers_with_timestamp(idev, &priv->scan, pf->timestamp);
+ iio_push_to_buffers_with_ts(idev, &priv->scan, sizeof(priv->scan),
+ pf->timestamp);
done:
iio_trigger_notify_done(idev->trig);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 20802b7f49ea..09fe88eb3fb0 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -1081,7 +1081,7 @@ static int pac1934_chip_identify(struct pac1934_chip_info *info)
/*
* documentation related to the ACPI device definition
- * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
*/
static int pac1934_acpi_parse_channel_config(struct i2c_client *client,
struct pac1934_chip_info *info)
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
index d283ee8fb1d2..7c01e33be04c 100644
--- a/drivers/iio/adc/palmas_gpadc.c
+++ b/drivers/iio/adc/palmas_gpadc.c
@@ -1164,7 +1164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pm_ops, palmas_gpadc_suspend,
static const struct of_device_id of_palmas_gpadc_match_tbl[] = {
{ .compatible = "ti,palmas-gpadc", },
- { /* end */ }
+ { }
};
MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl);
diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c
index 11170b5852d1..cc326f21d398 100644
--- a/drivers/iio/adc/rcar-gyroadc.c
+++ b/drivers/iio/adc/rcar-gyroadc.c
@@ -199,13 +199,12 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
if (!consumer)
return -EINVAL;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = rcar_gyroadc_set_power(priv, true);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -213,7 +212,7 @@ static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
*val &= BIT(priv->sample_width) - 1;
ret = rcar_gyroadc_set_power(priv, false);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -308,7 +307,7 @@ static const struct of_device_id rcar_gyroadc_child_match[] __maybe_unused = {
.compatible = "maxim,max11100",
.data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162,
},
- { /* sentinel */ }
+ { }
};
static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c
index b33536157adc..d6f6b351f2af 100644
--- a/drivers/iio/adc/rn5t618-adc.c
+++ b/drivers/iio/adc/rn5t618-adc.c
@@ -188,7 +188,7 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
static const struct iio_map rn5t618_maps[] = {
IIO_MAP("VADP", "rn5t618-power", "vadp"),
IIO_MAP("VUSB", "rn5t618-power", "vusb"),
- { /* sentinel */ }
+ { }
};
static int rn5t618_adc_probe(struct platform_device *pdev)
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 5e28bd28b81a..325e3747a134 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -425,7 +425,8 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
j++;
}
- iio_push_to_buffers_with_timestamp(i_dev, &data, iio_get_time_ns(i_dev));
+ iio_push_to_buffers_with_ts(i_dev, &data, sizeof(data),
+ iio_get_time_ns(i_dev));
out:
mutex_unlock(&info->lock);
diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c
new file mode 100644
index 000000000000..bb7c93ae4055
--- /dev/null
+++ b/drivers/iio/adc/rohm-bd79124.c
@@ -0,0 +1,1146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ROHM ADC driver for BD79124 ADC/GPO device
+ * https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79124muf-c-e.pdf
+ *
+ * Copyright (c) 2025, ROHM Semiconductor.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/adc-helpers.h>
+
+#define BD79124_I2C_MULTI_READ 0x30
+#define BD79124_I2C_MULTI_WRITE 0x28
+#define BD79124_REG_MAX 0xaf
+
+#define BD79124_REG_SYSTEM_STATUS 0x00
+#define BD79124_REG_GEN_CFG 0x01
+#define BD79124_REG_OPMODE_CFG 0x04
+#define BD79124_REG_PINCFG 0x05
+#define BD79124_REG_GPO_VAL 0x0B
+#define BD79124_REG_SEQ_CFG 0x10
+#define BD79124_REG_MANUAL_CHANNELS 0x11
+#define BD79124_REG_AUTO_CHANNELS 0x12
+#define BD79124_REG_ALERT_CH_SEL 0x14
+#define BD79124_REG_EVENT_FLAG 0x18
+#define BD79124_REG_EVENT_FLAG_HI 0x1a
+#define BD79124_REG_EVENT_FLAG_LO 0x1c
+#define BD79124_REG_HYSTERESIS_CH0 0x20
+#define BD79124_REG_EVENTCOUNT_CH0 0x22
+#define BD79124_REG_RECENT_CH0_LSB 0xa0
+#define BD79124_REG_RECENT_CH7_MSB 0xaf
+
+#define BD79124_ADC_BITS 12
+
+/* Masks for the BD79124_REG_OPMODE_CFG */
+#define BD79124_MSK_CONV_MODE GENMASK(6, 5)
+#define BD79124_CONV_MODE_MANSEQ 0
+#define BD79124_CONV_MODE_AUTO 1
+#define BD79124_MSK_AUTO_INTERVAL GENMASK(1, 0)
+#define BD79124_INTERVAL_750_US 0
+
+/* Masks for the BD79124_REG_GEN_CFG */
+#define BD79124_MSK_DWC_EN BIT(4)
+#define BD79124_MSK_STATS_EN BIT(5)
+
+/* Masks for the BD79124_REG_SEQ_CFG */
+#define BD79124_MSK_SEQ_START BIT(4)
+#define BD79124_MSK_SEQ_MODE GENMASK(1, 0)
+#define BD79124_MSK_SEQ_MANUAL 0
+#define BD79124_MSK_SEQ_SEQ 1
+
+#define BD79124_MSK_HYSTERESIS GENMASK(3, 0)
+#define BD79124_LOW_LIMIT_MIN 0
+#define BD79124_HIGH_LIMIT_MAX GENMASK(11, 0)
+
+/*
+ * The high limit, low limit and last measurement result are each stored in
+ * 2 consequtive registers. 4 bits are in the high bits of the first register
+ * and 8 bits in the next register.
+ *
+ * These macros return the address of the first reg for the given channel.
+ */
+#define BD79124_GET_HIGH_LIMIT_REG(ch) (BD79124_REG_HYSTERESIS_CH0 + (ch) * 4)
+#define BD79124_GET_LOW_LIMIT_REG(ch) (BD79124_REG_EVENTCOUNT_CH0 + (ch) * 4)
+#define BD79124_GET_LIMIT_REG(ch, dir) ((dir) == IIO_EV_DIR_RISING ? \
+ BD79124_GET_HIGH_LIMIT_REG(ch) : BD79124_GET_LOW_LIMIT_REG(ch))
+#define BD79124_GET_RECENT_RES_REG(ch) (BD79124_REG_RECENT_CH0_LSB + (ch) * 2)
+
+/*
+ * The hysteresis for a channel is stored in the same register where the
+ * 4 bits of high limit reside.
+ */
+#define BD79124_GET_HYSTERESIS_REG(ch) BD79124_GET_HIGH_LIMIT_REG(ch)
+
+#define BD79124_MAX_NUM_CHANNELS 8
+
+struct bd79124_data {
+ s64 timestamp;
+ struct regmap *map;
+ struct device *dev;
+ int vmax;
+ /*
+ * Keep measurement status so read_raw() knows if the measurement needs
+ * to be started.
+ */
+ int alarm_monitored[BD79124_MAX_NUM_CHANNELS];
+ /*
+ * The BD79124 does not allow disabling/enabling limit separately for
+ * one direction only. Hence, we do the disabling by changing the limit
+ * to maximum/minimum measurable value. This means we need to cache
+ * the limit in order to maintain it over the time limit is disabled.
+ */
+ u16 alarm_r_limit[BD79124_MAX_NUM_CHANNELS];
+ u16 alarm_f_limit[BD79124_MAX_NUM_CHANNELS];
+ /* Bitmask of disabled events (for rate limiting) for each channel. */
+ int alarm_suppressed[BD79124_MAX_NUM_CHANNELS];
+ /*
+ * The BD79124 is configured to run the measurements in the background.
+ * This is done for the event monitoring as well as for the read_raw().
+ * Protect the measurement starting/stopping using a mutex.
+ */
+ struct mutex mutex;
+ struct delayed_work alm_enable_work;
+ struct gpio_chip gc;
+ u8 gpio_valid_mask;
+};
+
+static const struct regmap_range bd79124_ro_ranges[] = {
+ {
+ .range_min = BD79124_REG_EVENT_FLAG,
+ .range_max = BD79124_REG_EVENT_FLAG,
+ }, {
+ .range_min = BD79124_REG_RECENT_CH0_LSB,
+ .range_max = BD79124_REG_RECENT_CH7_MSB,
+ },
+};
+
+static const struct regmap_access_table bd79124_ro_regs = {
+ .no_ranges = &bd79124_ro_ranges[0],
+ .n_no_ranges = ARRAY_SIZE(bd79124_ro_ranges),
+};
+
+static const struct regmap_range bd79124_volatile_ranges[] = {
+ {
+ .range_min = BD79124_REG_RECENT_CH0_LSB,
+ .range_max = BD79124_REG_RECENT_CH7_MSB,
+ }, {
+ .range_min = BD79124_REG_EVENT_FLAG,
+ .range_max = BD79124_REG_EVENT_FLAG,
+ }, {
+ .range_min = BD79124_REG_EVENT_FLAG_HI,
+ .range_max = BD79124_REG_EVENT_FLAG_HI,
+ }, {
+ .range_min = BD79124_REG_EVENT_FLAG_LO,
+ .range_max = BD79124_REG_EVENT_FLAG_LO,
+ }, {
+ .range_min = BD79124_REG_SYSTEM_STATUS,
+ .range_max = BD79124_REG_SYSTEM_STATUS,
+ },
+};
+
+static const struct regmap_access_table bd79124_volatile_regs = {
+ .yes_ranges = &bd79124_volatile_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bd79124_volatile_ranges),
+};
+
+static const struct regmap_range bd79124_precious_ranges[] = {
+ {
+ .range_min = BD79124_REG_EVENT_FLAG_HI,
+ .range_max = BD79124_REG_EVENT_FLAG_HI,
+ }, {
+ .range_min = BD79124_REG_EVENT_FLAG_LO,
+ .range_max = BD79124_REG_EVENT_FLAG_LO,
+ },
+};
+
+static const struct regmap_access_table bd79124_precious_regs = {
+ .yes_ranges = &bd79124_precious_ranges[0],
+ .n_yes_ranges = ARRAY_SIZE(bd79124_precious_ranges),
+};
+
+static const struct regmap_config bd79124_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .read_flag_mask = BD79124_I2C_MULTI_READ,
+ .write_flag_mask = BD79124_I2C_MULTI_WRITE,
+ .max_register = BD79124_REG_MAX,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_table = &bd79124_volatile_regs,
+ .wr_table = &bd79124_ro_regs,
+ .precious_table = &bd79124_precious_regs,
+};
+
+static int bd79124gpo_direction_get(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int bd79124gpo_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct bd79124_data *data = gpiochip_get_data(gc);
+
+ return regmap_assign_bits(data->map, BD79124_REG_GPO_VAL, BIT(offset),
+ value);
+}
+
+static int bd79124gpo_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ unsigned int all_gpos;
+ int ret;
+ struct bd79124_data *data = gpiochip_get_data(gc);
+
+ /*
+ * Ensure all GPIOs in 'mask' are set to be GPIOs
+ * The valid_mask was not obeyed by the gpiolib in all cases prior the
+ * https://lore.kernel.org/all/cd5e067b80e1bb590027bc3bfa817e7f794f21c3.1741180097.git.mazziesaccount@gmail.com/
+ *
+ * Keep this check here for a couple of cycles.
+ */
+ ret = regmap_read(data->map, BD79124_REG_PINCFG, &all_gpos);
+ if (ret)
+ return ret;
+
+ if (all_gpos ^ *mask) {
+ dev_dbg(data->dev, "Invalid mux config. Can't set value.\n");
+
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(data->map, BD79124_REG_GPO_VAL, *mask, *bits);
+}
+
+static int bd79124_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct bd79124_data *data = gpiochip_get_data(gc);
+
+ *valid_mask = data->gpio_valid_mask;
+
+ return 0;
+}
+
+/* Template for GPIO chip */
+static const struct gpio_chip bd79124gpo_chip = {
+ .label = "bd79124-gpo",
+ .get_direction = bd79124gpo_direction_get,
+ .set_rv = bd79124gpo_set,
+ .set_multiple_rv = bd79124gpo_set_multiple,
+ .init_valid_mask = bd79124_init_valid_mask,
+ .can_sleep = true,
+ .ngpio = 8,
+ .base = -1,
+};
+
+struct bd79124_raw {
+ u8 val_bit3_0; /* Is set in high bits of the byte */
+ u8 val_bit11_4;
+};
+#define BD79124_RAW_TO_INT(r) ((r.val_bit11_4 << 4) | (r.val_bit3_0 >> 4))
+#define BD79124_INT_TO_RAW(val) { \
+ .val_bit11_4 = (val) >> 4, \
+ .val_bit3_0 = (val) << 4, \
+}
+
+/*
+ * The high and low limits as well as the recent result values are stored in
+ * the same way in 2 consequent registers. The first register contains 4 bits
+ * of the value. These bits are stored in the high bits [7:4] of register, but
+ * they represent the low bits [3:0] of the value.
+ * The value bits [11:4] are stored in the next register.
+ *
+ * Read data from register and convert to integer.
+ */
+static int bd79124_read_reg_to_int(struct bd79124_data *data, int reg,
+ unsigned int *val)
+{
+ int ret;
+ struct bd79124_raw raw;
+
+ ret = regmap_bulk_read(data->map, reg, &raw, sizeof(raw));
+ if (ret) {
+ dev_dbg(data->dev, "bulk_read failed %d\n", ret);
+
+ return ret;
+ }
+
+ *val = BD79124_RAW_TO_INT(raw);
+
+ return 0;
+}
+
+/*
+ * The high and low limits as well as the recent result values are stored in
+ * the same way in 2 consequent registers. The first register contains 4 bits
+ * of the value. These bits are stored in the high bits [7:4] of register, but
+ * they represent the low bits [3:0] of the value.
+ * The value bits [11:4] are stored in the next register.
+ *
+ * Convert the integer to register format and write it using rmw cycle.
+ */
+static int bd79124_write_int_to_reg(struct bd79124_data *data, int reg,
+ unsigned int val)
+{
+ struct bd79124_raw raw = BD79124_INT_TO_RAW(val);
+ unsigned int tmp;
+ int ret;
+
+ ret = regmap_read(data->map, reg, &tmp);
+ if (ret)
+ return ret;
+
+ raw.val_bit3_0 |= (tmp & 0xf);
+
+ return regmap_bulk_write(data->map, reg, &raw, sizeof(raw));
+}
+
+static const struct iio_event_spec bd79124_events[] = {
+ {
+ .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),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+static const struct iio_chan_spec bd79124_chan_template_noirq = {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+};
+
+static const struct iio_chan_spec bd79124_chan_template = {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .indexed = 1,
+ .event_spec = bd79124_events,
+ .num_event_specs = ARRAY_SIZE(bd79124_events),
+};
+
+static int bd79124_read_event_value(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val,
+ int *val2)
+{
+ struct bd79124_data *data = iio_priv(iio_dev);
+ int ret, reg;
+
+ if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (dir == IIO_EV_DIR_RISING)
+ *val = data->alarm_r_limit[chan->channel];
+ else if (dir == IIO_EV_DIR_FALLING)
+ *val = data->alarm_f_limit[chan->channel];
+ else
+ return -EINVAL;
+
+ return IIO_VAL_INT;
+
+ case IIO_EV_INFO_HYSTERESIS:
+ reg = BD79124_GET_HYSTERESIS_REG(chan->channel);
+ ret = regmap_read(data->map, reg, val);
+ if (ret)
+ return ret;
+
+ *val &= BD79124_MSK_HYSTERESIS;
+ /*
+ * The data-sheet says the hysteresis register value needs to be
+ * shifted left by 3.
+ */
+ *val <<= 3;
+
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bd79124_start_measurement(struct bd79124_data *data, int chan)
+{
+ unsigned int val, regval;
+ int ret;
+
+ /* See if already started */
+ ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &val);
+ if (val & BIT(chan))
+ return 0;
+
+ /*
+ * The sequencer must be stopped when channels are added/removed from
+ * the list of the measured channels to ensure the new channel
+ * configuration is used.
+ */
+ ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, val | BIT(chan));
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+ if (ret)
+ return ret;
+
+ /*
+ * Start the measurement at the background. Don't bother checking if
+ * it was started, regmap has cache.
+ */
+ regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_AUTO);
+
+ return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
+ BD79124_MSK_CONV_MODE, regval);
+}
+
+static int bd79124_stop_measurement(struct bd79124_data *data, int chan)
+{
+ unsigned int enabled_chans;
+ int ret;
+
+ /* See if already stopped */
+ ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &enabled_chans);
+ if (!(enabled_chans & BIT(chan)))
+ return 0;
+
+ ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+
+ /* Clear the channel from the measured channels */
+ enabled_chans &= ~BIT(chan);
+ ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS,
+ enabled_chans);
+ if (ret)
+ return ret;
+
+ /*
+ * Stop background conversion for power saving if it was the last
+ * channel.
+ */
+ if (!enabled_chans) {
+ int regval = FIELD_PREP(BD79124_MSK_CONV_MODE,
+ BD79124_CONV_MODE_MANSEQ);
+
+ ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
+ BD79124_MSK_CONV_MODE, regval);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+}
+
+static int bd79124_read_event_config(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct bd79124_data *data = iio_priv(iio_dev);
+
+ if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
+ return -EINVAL;
+
+ return !!(data->alarm_monitored[chan->channel] & BIT(dir));
+}
+
+static int bd79124_disable_event(struct bd79124_data *data,
+ enum iio_event_direction dir, int channel)
+{
+ int dir_bit = BIT(dir);
+ int reg;
+ unsigned int limit;
+
+ guard(mutex)(&data->mutex);
+
+ /*
+ * Set thresholds either to 0 or to 2^12 - 1 as appropriate to prevent
+ * alerts and thus disable event generation.
+ */
+ if (dir == IIO_EV_DIR_RISING) {
+ reg = BD79124_GET_HIGH_LIMIT_REG(channel);
+ limit = BD79124_HIGH_LIMIT_MAX;
+ } else if (dir == IIO_EV_DIR_FALLING) {
+ reg = BD79124_GET_LOW_LIMIT_REG(channel);
+ limit = BD79124_LOW_LIMIT_MIN;
+ } else {
+ return -EINVAL;
+ }
+
+ data->alarm_monitored[channel] &= ~dir_bit;
+
+ /*
+ * Stop measurement if there is no more events to monitor.
+ * We don't bother checking the retval because the limit
+ * setting should in any case effectively disable the alarm.
+ */
+ if (!data->alarm_monitored[channel]) {
+ bd79124_stop_measurement(data, channel);
+ regmap_clear_bits(data->map, BD79124_REG_ALERT_CH_SEL,
+ BIT(channel));
+ }
+
+ return bd79124_write_int_to_reg(data, reg, limit);
+}
+
+static int bd79124_enable_event(struct bd79124_data *data,
+ enum iio_event_direction dir,
+ unsigned int channel)
+{
+ int dir_bit = BIT(dir);
+ int reg, ret;
+ u16 *limit;
+
+ guard(mutex)(&data->mutex);
+ ret = bd79124_start_measurement(data, channel);
+ if (ret)
+ return ret;
+
+ data->alarm_monitored[channel] |= dir_bit;
+
+ /* Add the channel to the list of monitored channels */
+ ret = regmap_set_bits(data->map, BD79124_REG_ALERT_CH_SEL, BIT(channel));
+ if (ret)
+ return ret;
+
+ if (dir == IIO_EV_DIR_RISING) {
+ limit = &data->alarm_f_limit[channel];
+ reg = BD79124_GET_HIGH_LIMIT_REG(channel);
+ } else {
+ limit = &data->alarm_f_limit[channel];
+ reg = BD79124_GET_LOW_LIMIT_REG(channel);
+ }
+ /*
+ * Don't write the new limit to the hardware if we are in the
+ * rate-limit period. The timer which re-enables the event will set
+ * the limit.
+ */
+ if (!(data->alarm_suppressed[channel] & dir_bit)) {
+ ret = bd79124_write_int_to_reg(data, reg, *limit);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Enable comparator. Trust the regmap cache, no need to check
+ * if it was already enabled.
+ *
+ * We could do this in the hw-init, but there may be users who
+ * never enable alarms and for them it makes sense to not
+ * enable the comparator at probe.
+ */
+ return regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
+ BD79124_MSK_DWC_EN);
+}
+
+static int bd79124_write_event_config(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, bool state)
+{
+ struct bd79124_data *data = iio_priv(iio_dev);
+
+ if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
+ return -EINVAL;
+
+ if (state)
+ return bd79124_enable_event(data, dir, chan->channel);
+
+ return bd79124_disable_event(data, dir, chan->channel);
+}
+
+static int bd79124_write_event_value(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val,
+ int val2)
+{
+ struct bd79124_data *data = iio_priv(iio_dev);
+ int reg;
+
+ if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ {
+ guard(mutex)(&data->mutex);
+
+ if (dir == IIO_EV_DIR_RISING) {
+ data->alarm_r_limit[chan->channel] = val;
+ reg = BD79124_GET_HIGH_LIMIT_REG(chan->channel);
+ } else if (dir == IIO_EV_DIR_FALLING) {
+ data->alarm_f_limit[chan->channel] = val;
+ reg = BD79124_GET_LOW_LIMIT_REG(chan->channel);
+ } else {
+ return -EINVAL;
+ }
+ /*
+ * We don't want to enable the alarm if it is not enabled or
+ * if it is suppressed. In that case skip writing to the
+ * register.
+ */
+ if (!(data->alarm_monitored[chan->channel] & BIT(dir)) ||
+ data->alarm_suppressed[chan->channel] & BIT(dir))
+ return 0;
+
+ return bd79124_write_int_to_reg(data, reg, val);
+ }
+ case IIO_EV_INFO_HYSTERESIS:
+ reg = BD79124_GET_HYSTERESIS_REG(chan->channel);
+ val >>= 3;
+
+ return regmap_update_bits(data->map, reg, BD79124_MSK_HYSTERESIS,
+ val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bd79124_single_chan_seq(struct bd79124_data *data, int chan, unsigned int *old)
+{
+ int ret;
+
+ ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+ if (ret)
+ return ret;
+
+ /*
+ * It may be we have some channels monitored for alarms so we want to
+ * cache the old config and return it when the single channel
+ * measurement has been completed.
+ */
+ ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, old);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, BIT(chan));
+ if (ret)
+ return ret;
+
+ /* Restart the sequencer */
+ return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+}
+
+static int bd79124_single_chan_seq_end(struct bd79124_data *data, unsigned int old)
+{
+ int ret;
+
+ ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, old);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+}
+
+static int bd79124_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long m)
+{
+ struct bd79124_data *data = iio_priv(iio_dev);
+ int ret;
+
+ if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
+ return -EINVAL;
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ {
+ unsigned int old_chan_cfg, regval;
+ int tmp;
+
+ guard(mutex)(&data->mutex);
+
+ /*
+ * Start the automatic conversion. This is needed here if no
+ * events have been enabled.
+ */
+ regval = FIELD_PREP(BD79124_MSK_CONV_MODE,
+ BD79124_CONV_MODE_AUTO);
+ ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
+ BD79124_MSK_CONV_MODE, regval);
+ if (ret)
+ return ret;
+
+ ret = bd79124_single_chan_seq(data, chan->channel, &old_chan_cfg);
+ if (ret)
+ return ret;
+
+ /* The maximum conversion time is 6 uS. */
+ udelay(6);
+
+ ret = bd79124_read_reg_to_int(data,
+ BD79124_GET_RECENT_RES_REG(chan->channel), val);
+ /*
+ * Return the old chan config even if data reading failed in
+ * order to re-enable the event monitoring.
+ */
+ tmp = bd79124_single_chan_seq_end(data, old_chan_cfg);
+ if (tmp)
+ dev_err(data->dev,
+ "Failed to return config. Alarms may be disabled\n");
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val = data->vmax / 1000;
+ *val2 = BD79124_ADC_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info bd79124_info = {
+ .read_raw = bd79124_read_raw,
+ .read_event_config = &bd79124_read_event_config,
+ .write_event_config = &bd79124_write_event_config,
+ .read_event_value = &bd79124_read_event_value,
+ .write_event_value = &bd79124_write_event_value,
+};
+
+static void bd79124_re_enable_lo(struct bd79124_data *data, unsigned int channel)
+{
+ int ret, evbit = BIT(IIO_EV_DIR_FALLING);
+
+ /*
+ * We should not re-enable the event if user has disabled it while
+ * rate-limiting was enabled.
+ */
+ if (!(data->alarm_suppressed[channel] & evbit))
+ return;
+
+ data->alarm_suppressed[channel] &= ~evbit;
+
+ if (!(data->alarm_monitored[channel] & evbit))
+ return;
+
+ ret = bd79124_write_int_to_reg(data, BD79124_GET_LOW_LIMIT_REG(channel),
+ data->alarm_f_limit[channel]);
+ if (ret)
+ dev_warn(data->dev, "Low limit enabling failed for channel%d\n",
+ channel);
+}
+
+static void bd79124_re_enable_hi(struct bd79124_data *data, unsigned int channel)
+{
+ int ret, evbit = BIT(IIO_EV_DIR_RISING);
+
+ /*
+ * We should not re-enable the event if user has disabled it while
+ * rate-limiting was enabled.
+ */
+ if (!(data->alarm_suppressed[channel] & evbit))
+ return;
+
+ data->alarm_suppressed[channel] &= ~evbit;
+
+ if (!(data->alarm_monitored[channel] & evbit))
+ return;
+
+ ret = bd79124_write_int_to_reg(data, BD79124_GET_HIGH_LIMIT_REG(channel),
+ data->alarm_r_limit[channel]);
+ if (ret)
+ dev_warn(data->dev, "High limit enabling failed for channel%d\n",
+ channel);
+}
+
+static void bd79124_alm_enable_worker(struct work_struct *work)
+{
+ int i;
+ struct bd79124_data *data = container_of(work, struct bd79124_data,
+ alm_enable_work.work);
+
+ /* Take the mutex so there is no race with user disabling the alarm */
+ guard(mutex)(&data->mutex);
+ for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
+ bd79124_re_enable_hi(data, i);
+ bd79124_re_enable_lo(data, i);
+ }
+}
+
+static int __bd79124_event_ratelimit(struct bd79124_data *data, int reg,
+ unsigned int limit)
+{
+ int ret;
+
+ if (limit > BD79124_HIGH_LIMIT_MAX)
+ return -EINVAL;
+
+ ret = bd79124_write_int_to_reg(data, reg, limit);
+ if (ret)
+ return ret;
+
+ /*
+ * We use 1 sec 'grace period'. At the moment I see no reason to make
+ * this user configurable. We need an ABI for this if configuration is
+ * needed.
+ */
+ schedule_delayed_work(&data->alm_enable_work, msecs_to_jiffies(1000));
+
+ return 0;
+}
+
+static int bd79124_event_ratelimit_hi(struct bd79124_data *data,
+ unsigned int channel)
+{
+ guard(mutex)(&data->mutex);
+ data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_RISING);
+
+ return __bd79124_event_ratelimit(data,
+ BD79124_GET_HIGH_LIMIT_REG(channel),
+ BD79124_HIGH_LIMIT_MAX);
+}
+
+static int bd79124_event_ratelimit_lo(struct bd79124_data *data,
+ unsigned int channel)
+{
+ guard(mutex)(&data->mutex);
+ data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_FALLING);
+
+ return __bd79124_event_ratelimit(data,
+ BD79124_GET_LOW_LIMIT_REG(channel),
+ BD79124_LOW_LIMIT_MIN);
+}
+
+static irqreturn_t bd79124_event_handler(int irq, void *priv)
+{
+ unsigned int i_hi, i_lo;
+ int i, ret;
+ struct iio_dev *iio_dev = priv;
+ struct bd79124_data *data = iio_priv(iio_dev);
+
+ /*
+ * Return IRQ_NONE if bailing-out without acking. This allows the IRQ
+ * subsystem to disable the offending IRQ line if we get a hardware
+ * problem. This behaviour has saved my poor bottom a few times in the
+ * past as, instead of getting unusably unresponsive, the system has
+ * spilled out the magic words "...nobody cared".
+ */
+ ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_HI, &i_hi);
+ if (ret)
+ return IRQ_NONE;
+
+ ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_LO, &i_lo);
+ if (ret)
+ return IRQ_NONE;
+
+ if (!i_lo && !i_hi)
+ return IRQ_NONE;
+
+ for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
+ u64 ecode;
+
+ if (BIT(i) & i_hi) {
+ ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING);
+
+ iio_push_event(iio_dev, ecode, data->timestamp);
+ /*
+ * The BD79124 keeps the IRQ asserted for as long as
+ * the voltage exceeds the threshold. It causes the IRQ
+ * to keep firing.
+ *
+ * Disable the event for the channel and schedule the
+ * re-enabling the event later to prevent storm of
+ * events.
+ */
+ ret = bd79124_event_ratelimit_hi(data, i);
+ if (ret)
+ return IRQ_NONE;
+ }
+ if (BIT(i) & i_lo) {
+ ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING);
+
+ iio_push_event(iio_dev, ecode, data->timestamp);
+ ret = bd79124_event_ratelimit_lo(data, i);
+ if (ret)
+ return IRQ_NONE;
+ }
+ }
+
+ ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_HI, i_hi);
+ if (ret)
+ return IRQ_NONE;
+
+ ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_LO, i_lo);
+ if (ret)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bd79124_irq_handler(int irq, void *priv)
+{
+ struct iio_dev *iio_dev = priv;
+ struct bd79124_data *data = iio_priv(iio_dev);
+
+ data->timestamp = iio_get_time_ns(iio_dev);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int bd79124_chan_init(struct bd79124_data *data, int channel)
+{
+ int ret;
+
+ ret = regmap_write(data->map, BD79124_GET_HIGH_LIMIT_REG(channel),
+ BD79124_HIGH_LIMIT_MAX);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->map, BD79124_GET_LOW_LIMIT_REG(channel),
+ BD79124_LOW_LIMIT_MIN);
+}
+
+static int bd79124_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels)
+{
+ int i, gpio_channels;
+
+ /*
+ * Let's initialize the mux config to say that all 8 channels are
+ * GPIOs. Then we can just loop through the iio_chan_spec and clear the
+ * bits for found ADC channels.
+ */
+ gpio_channels = GENMASK(7, 0);
+ for (i = 0; i < num_channels; i++)
+ gpio_channels &= ~BIT(cs[i].channel);
+
+ return gpio_channels;
+}
+
+static int bd79124_hw_init(struct bd79124_data *data)
+{
+ unsigned int regval;
+ int ret, i;
+
+ for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
+ ret = bd79124_chan_init(data, i);
+ if (ret)
+ return ret;
+ data->alarm_r_limit[i] = BD79124_HIGH_LIMIT_MAX;
+ }
+ /* Stop auto sequencer */
+ ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_START);
+ if (ret)
+ return ret;
+
+ /* Enable writing the measured values to the regsters */
+ ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
+ BD79124_MSK_STATS_EN);
+ if (ret)
+ return ret;
+
+ /* Set no channels to be auto-measured */
+ ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, 0x0);
+ if (ret)
+ return ret;
+
+ /* Set no channels to be manually measured */
+ ret = regmap_write(data->map, BD79124_REG_MANUAL_CHANNELS, 0x0);
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(BD79124_MSK_AUTO_INTERVAL, BD79124_INTERVAL_750_US);
+ ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
+ BD79124_MSK_AUTO_INTERVAL, regval);
+ if (ret)
+ return ret;
+
+ /* Sequencer mode to auto */
+ ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
+ BD79124_MSK_SEQ_SEQ);
+ if (ret)
+ return ret;
+
+ /* Don't start the measurement */
+ regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_MANSEQ);
+ return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
+ BD79124_MSK_CONV_MODE, regval);
+}
+
+static int bd79124_probe(struct i2c_client *i2c)
+{
+ struct bd79124_data *data;
+ struct iio_dev *iio_dev;
+ const struct iio_chan_spec *template;
+ struct iio_chan_spec *cs;
+ struct device *dev = &i2c->dev;
+ unsigned int gpio_pins;
+ int ret;
+
+ iio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(iio_dev);
+ data->dev = dev;
+ data->map = devm_regmap_init_i2c(i2c, &bd79124_regmap);
+ if (IS_ERR(data->map))
+ return dev_err_probe(dev, PTR_ERR(data->map),
+ "Failed to initialize Regmap\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "vdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get the Vdd\n");
+
+ data->vmax = ret;
+
+ ret = devm_regulator_get_enable(dev, "iovdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to enable I/O voltage\n");
+
+ ret = devm_delayed_work_autocancel(dev, &data->alm_enable_work,
+ bd79124_alm_enable_worker);
+ if (ret)
+ return ret;
+
+ if (i2c->irq) {
+ template = &bd79124_chan_template;
+ } else {
+ template = &bd79124_chan_template_noirq;
+ dev_dbg(dev, "No IRQ found, events disabled\n");
+ }
+
+ ret = devm_mutex_init(dev, &data->mutex);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_adc_device_alloc_chaninfo_se(dev, template,
+ BD79124_MAX_NUM_CHANNELS - 1, &cs);
+ if (ret < 0) {
+ /* Register all pins as GPOs if there are no ADC channels */
+ if (ret == -ENOENT)
+ goto register_gpios;
+ return ret;
+ }
+ iio_dev->channels = cs;
+ iio_dev->num_channels = ret;
+ iio_dev->info = &bd79124_info;
+ iio_dev->name = "bd79124";
+ iio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = bd79124_hw_init(data);
+ if (ret)
+ return ret;
+
+ if (i2c->irq > 0) {
+ ret = devm_request_threaded_irq(dev, i2c->irq,
+ bd79124_irq_handler, &bd79124_event_handler,
+ IRQF_ONESHOT, "adc-thresh-alert", iio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Failed to register IRQ\n");
+ }
+
+ ret = devm_iio_device_register(data->dev, iio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Failed to register ADC\n");
+
+register_gpios:
+ gpio_pins = bd79124_get_gpio_pins(iio_dev->channels,
+ iio_dev->num_channels);
+
+ /*
+ * The mux should default to "all ADCs", but better to not trust it.
+ * Thus we do set the mux even when we have only ADCs and no GPOs.
+ */
+ ret = regmap_write(data->map, BD79124_REG_PINCFG, gpio_pins);
+ if (ret)
+ return ret;
+
+ /* No GPOs if all channels are reserved for ADC, so we're done. */
+ if (!gpio_pins)
+ return 0;
+
+ data->gpio_valid_mask = gpio_pins;
+ data->gc = bd79124gpo_chip;
+ data->gc.parent = dev;
+
+ return devm_gpiochip_add_data(dev, &data->gc, data);
+}
+
+static const struct of_device_id bd79124_of_match[] = {
+ { .compatible = "rohm,bd79124" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bd79124_of_match);
+
+static const struct i2c_device_id bd79124_id[] = {
+ { "bd79124" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bd79124_id);
+
+static struct i2c_driver bd79124_driver = {
+ .driver = {
+ .name = "bd79124",
+ .of_match_table = bd79124_of_match,
+ },
+ .probe = bd79124_probe,
+ .id_table = bd79124_id,
+};
+module_i2c_driver(bd79124_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Driver for ROHM BD79124 ADC");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DRIVER");
diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c
index 54239df61d86..6ff47415a222 100644
--- a/drivers/iio/adc/rtq6056.c
+++ b/drivers/iio/adc/rtq6056.c
@@ -666,7 +666,8 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
data.vals[i++] = raw;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data),
+ iio_get_time_ns(indio_dev));
out:
pm_runtime_mark_last_busy(dev);
diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
index 883c167c0670..9674d48074c9 100644
--- a/drivers/iio/adc/rzg2l_adc.c
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -11,6 +11,7 @@
#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/iio/adc-helpers.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -324,48 +325,39 @@ static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static const struct iio_chan_spec rzg2l_adc_chan_template = {
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+};
+
static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
{
const struct rzg2l_adc_hw_params *hw_params = adc->hw_params;
struct iio_chan_spec *chan_array;
struct rzg2l_adc_data *data;
- unsigned int channel;
int num_channels;
- int ret;
u8 i;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- num_channels = device_get_child_node_count(&pdev->dev);
- if (!num_channels)
- return dev_err_probe(&pdev->dev, -ENODEV, "no channel children\n");
+ num_channels = devm_iio_adc_device_alloc_chaninfo_se(&pdev->dev,
+ &rzg2l_adc_chan_template,
+ hw_params->num_channels - 1,
+ &chan_array);
+ if (num_channels < 0)
+ return num_channels;
if (num_channels > hw_params->num_channels)
return dev_err_probe(&pdev->dev, -EINVAL,
"num of channel children out of range\n");
- chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
- GFP_KERNEL);
- if (!chan_array)
- return -ENOMEM;
+ for (i = 0; i < num_channels; i++) {
+ int channel = chan_array[i].channel;
- i = 0;
- device_for_each_child_node_scoped(&pdev->dev, fwnode) {
- ret = fwnode_property_read_u32(fwnode, "reg", &channel);
- if (ret)
- return ret;
-
- if (channel >= hw_params->num_channels)
- return -EINVAL;
-
- chan_array[i].type = rzg2l_adc_channels[channel].type;
- chan_array[i].indexed = 1;
- chan_array[i].channel = channel;
- chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan_array[i].datasheet_name = rzg2l_adc_channels[channel].name;
- i++;
+ chan_array[i].type = rzg2l_adc_channels[channel].type;
}
data->num_channels = num_channels;
@@ -515,7 +507,7 @@ static const struct rzg2l_adc_hw_params rzg3s_hw_params = {
static const struct of_device_id rzg2l_adc_match[] = {
{ .compatible = "renesas,r9a08g045-adc", .data = &rzg3s_hw_params },
{ .compatible = "renesas,rzg2l-adc", .data = &rzg2l_hw_params },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
@@ -626,3 +618,4 @@ module_platform_driver(rzg2l_adc_driver);
MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_DRIVER");
diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c
index b6dd096391c1..e3a865c79686 100644
--- a/drivers/iio/adc/spear_adc.c
+++ b/drivers/iio/adc/spear_adc.c
@@ -345,7 +345,7 @@ static int spear_adc_probe(struct platform_device *pdev)
static const struct of_device_id spear_adc_dt_ids[] = {
{ .compatible = "st,spear600-adc", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 73b2c2e91c08..db50a9f3b922 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -10,6 +10,9 @@
#ifndef __STM32_ADC_H
#define __STM32_ADC_H
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+
/*
* STM32 - ADC global register map
* ________________________________________________________
@@ -91,6 +94,7 @@
#define STM32H7_ADC_IER 0x04
#define STM32H7_ADC_CR 0x08
#define STM32H7_ADC_CFGR 0x0C
+#define STM32H7_ADC_CFGR2 0x10
#define STM32H7_ADC_SMPR1 0x14
#define STM32H7_ADC_SMPR2 0x18
#define STM32H7_ADC_PCSEL 0x1C
@@ -160,6 +164,13 @@
#define STM32H7_DMNGT_SHIFT 0
#define STM32H7_DMNGT_MASK GENMASK(1, 0)
+/* STM32H7_ADC_CFGR2 bit fields */
+#define STM32H7_OVSR_MASK GENMASK(25, 16) /* Correspond to OSVR field in datasheet */
+#define STM32H7_OVSR(v) FIELD_PREP(STM32H7_OVSR_MASK, v)
+#define STM32H7_OVSS_MASK GENMASK(8, 5)
+#define STM32H7_OVSS(v) FIELD_PREP(STM32H7_OVSS_MASK, v)
+#define STM32H7_ROVSE BIT(0)
+
enum stm32h7_adc_dmngt {
STM32H7_DMNGT_DR_ONLY, /* Regular data in DR only */
STM32H7_DMNGT_DMA_ONESHOT, /* DMA one shot mode */
@@ -226,6 +237,12 @@ enum stm32h7_adc_dmngt {
#define STM32MP13_RES_SHIFT 3
#define STM32MP13_RES_MASK GENMASK(4, 3)
+/* STM32MP13_ADC_CFGR2 bit fields */
+#define STM32MP13_OVSR_MASK GENMASK(4, 2)
+#define STM32MP13_OVSR(v) FIELD_PREP(STM32MP13_OVSR_MASK, v)
+#define STM32MP13_OVSS_MASK GENMASK(8, 5)
+#define STM32MP13_OVSS(v) FIELD_PREP(STM32MP13_OVSS_MASK, v)
+
/* STM32MP13_ADC_DIFSEL - bit fields */
#define STM32MP13_DIFSEL_MASK GENMASK(18, 0)
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 5dbf5f136768..e84babf43385 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -6,6 +6,7 @@
* Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
*/
+#include <linux/array_size.h>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -202,11 +203,13 @@ struct stm32_adc;
* @has_boostmode: boost mode support flag
* @has_linearcal: linear calibration support flag
* @has_presel: channel preselection support flag
+ * @has_oversampling: oversampling support flag
* @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions
* @stop_conv: routine to stop conversions
* @unprepare: optional unprepare routine (disable, power-down)
* @irq_clear: routine to clear irqs
+ * @set_ovs: routine to set oversampling configuration
* @smp_cycles: programmable sampling time (ADC clock cycles)
* @ts_int_ch: pointer to array of internal channels minimum sampling time in ns
*/
@@ -219,11 +222,13 @@ struct stm32_adc_cfg {
bool has_boostmode;
bool has_linearcal;
bool has_presel;
+ bool has_oversampling;
int (*prepare)(struct iio_dev *);
void (*start_conv)(struct iio_dev *, bool dma);
void (*stop_conv)(struct iio_dev *);
void (*unprepare)(struct iio_dev *);
void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
+ void (*set_ovs)(struct iio_dev *indio_dev, u32 ovs_idx);
const unsigned int *smp_cycles;
const unsigned int *ts_int_ch;
};
@@ -255,6 +260,7 @@ struct stm32_adc_cfg {
* @num_diff: number of differential channels
* @int_ch: internal channel indexes array
* @nsmps: number of channels with optional sample time
+ * @ovs_idx: current oversampling ratio index (in oversampling array)
*/
struct stm32_adc {
struct stm32_adc_common *common;
@@ -282,6 +288,7 @@ struct stm32_adc {
u32 num_diff;
int int_ch[STM32_ADC_INT_CH_NB];
int nsmps;
+ int ovs_idx;
};
struct stm32_adc_diff_channel {
@@ -293,12 +300,24 @@ struct stm32_adc_diff_channel {
* struct stm32_adc_info - stm32 ADC, per instance config data
* @max_channels: Number of channels
* @resolutions: available resolutions
+ * @oversampling: available oversampling ratios
* @num_res: number of available resolutions
+ * @num_ovs: number of available oversampling ratios
*/
struct stm32_adc_info {
int max_channels;
const unsigned int *resolutions;
+ const unsigned int *oversampling;
const unsigned int num_res;
+ const unsigned int num_ovs;
+};
+
+static const unsigned int stm32h7_adc_oversampling_avail[] = {
+ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+static const unsigned int stm32mp13_adc_oversampling_avail[] = {
+ 1, 2, 4, 8, 16, 32, 64, 128, 256,
};
static const unsigned int stm32f4_adc_resolutions[] = {
@@ -322,14 +341,18 @@ static const unsigned int stm32h7_adc_resolutions[] = {
static const struct stm32_adc_info stm32h7_adc_info = {
.max_channels = STM32_ADC_CH_MAX,
.resolutions = stm32h7_adc_resolutions,
+ .oversampling = stm32h7_adc_oversampling_avail,
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
+ .num_ovs = ARRAY_SIZE(stm32h7_adc_oversampling_avail),
};
/* stm32mp13 can have up to 19 channels */
static const struct stm32_adc_info stm32mp13_adc_info = {
.max_channels = 19,
.resolutions = stm32f4_adc_resolutions,
+ .oversampling = stm32mp13_adc_oversampling_avail,
.num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
+ .num_ovs = ARRAY_SIZE(stm32mp13_adc_oversampling_avail),
};
/*
@@ -469,7 +492,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
{ LPTIM1_OUT, STM32_EXT18 },
{ LPTIM2_OUT, STM32_EXT19 },
{ LPTIM3_OUT, STM32_EXT20 },
- {},
+ { }
};
/*
@@ -889,6 +912,56 @@ static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
}
+static void stm32h7_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 ovsr_bits, bits, msk;
+
+ msk = STM32H7_ROVSE | STM32H7_OVSR_MASK | STM32H7_OVSS_MASK;
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk);
+
+ if (!ovs_idx)
+ return;
+
+ /*
+ * Only the oversampling ratios corresponding to 2^ovs_idx are exposed in sysfs.
+ * Oversampling ratios [2,3,...,1024] are mapped on OVSR register values [1,2,...,1023].
+ * OVSR = 2^ovs_idx - 1
+ * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial
+ * resolution given by "assigned-resolution-bits" property.
+ * OVSS = ovs_idx
+ */
+ ovsr_bits = GENMASK(ovs_idx - 1, 0);
+ bits = STM32H7_ROVSE | STM32H7_OVSS(ovs_idx) | STM32H7_OVSR(ovsr_bits);
+
+ stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk);
+}
+
+static void stm32mp13_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 bits, msk;
+
+ msk = STM32H7_ROVSE | STM32MP13_OVSR_MASK | STM32MP13_OVSS_MASK;
+ stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk);
+
+ if (!ovs_idx)
+ return;
+
+ /*
+ * The oversampling ratios [2,4,8,..,256] are mapped on OVSR register values [0,1,...,7].
+ * OVSR = ovs_idx - 1
+ * These ratio increase the resolution by ovs_idx bits. Apply a right shift to keep initial
+ * resolution given by "assigned-resolution-bits" property.
+ * OVSS = ovs_idx
+ */
+ bits = STM32H7_ROVSE | STM32MP13_OVSS(ovs_idx);
+ if (ovs_idx - 1)
+ bits |= STM32MP13_OVSR(ovs_idx - 1);
+
+ stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk);
+}
+
static int stm32h7_adc_exit_pwr_down(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
@@ -1461,6 +1534,67 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
return ret;
}
+static int stm32_adc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
+ int nb = adc->cfg->adc_info->num_ovs;
+ unsigned int idx;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (val2)
+ return -EINVAL;
+
+ for (idx = 0; idx < nb; idx++)
+ if (adc->cfg->adc_info->oversampling[idx] == val)
+ break;
+ if (idx >= nb)
+ return -EINVAL;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err;
+
+ adc->cfg->set_ovs(indio_dev, idx);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ adc->ovs_idx = idx;
+
+err:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int stm32_adc_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length, long m)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *type = IIO_VAL_INT;
+ *length = adc->cfg->adc_info->num_ovs;
+ *vals = adc->cfg->adc_info->oversampling;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static int stm32_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -1502,6 +1636,10 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
*val = 0;
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = adc->cfg->adc_info->oversampling[adc->ovs_idx];
+ return IIO_VAL_INT;
+
default:
return -EINVAL;
}
@@ -1678,6 +1816,8 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev,
static const struct iio_info stm32_adc_iio_info = {
.read_raw = stm32_adc_read_raw,
+ .write_raw = stm32_adc_write_raw,
+ .read_avail = stm32_adc_read_avail,
.validate_trigger = stm32_adc_validate_trigger,
.hwfifo_set_watermark = stm32_adc_set_watermark,
.update_scan_mode = stm32_adc_update_scan_mode,
@@ -1858,8 +1998,8 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p)
/* reset buffer index */
adc->bufi = 0;
- iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, adc->buffer, sizeof(adc->buffer),
+ pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
/* re-enable eoc irq */
@@ -1876,7 +2016,7 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
.read = iio_enum_available_read,
.private = (uintptr_t)&stm32_adc_trig_pol,
},
- {},
+ { }
};
static void stm32_adc_debugfs_init(struct iio_dev *indio_dev)
@@ -1971,6 +2111,10 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET);
+ if (adc->cfg->has_oversampling) {
+ chan->info_mask_shared_by_all |= BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+ chan->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+ }
chan->scan_type.sign = 'u';
chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res];
chan->scan_type.storagebits = 16;
@@ -2587,6 +2731,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.has_boostmode = true,
.has_linearcal = true,
.has_presel = true,
+ .has_oversampling = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@@ -2594,6 +2739,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_h7,
+ .set_ovs = stm32h7_adc_set_ovs,
};
static const unsigned int stm32_adc_min_ts_mp1[] = { 100, 100, 100, 4300, 9800 };
@@ -2607,6 +2753,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.has_boostmode = true,
.has_linearcal = true,
.has_presel = true,
+ .has_oversampling = true,
.start_conv = stm32h7_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@@ -2614,6 +2761,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_mp1,
+ .set_ovs = stm32h7_adc_set_ovs,
};
static const unsigned int stm32_adc_min_ts_mp13[] = { 100, 0, 0, 4300, 9800 };
@@ -2623,6 +2771,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.regs = &stm32mp13_adc_regspec,
.adc_info = &stm32mp13_adc_info,
.trigs = stm32h7_adc_trigs,
+ .has_oversampling = true,
.start_conv = stm32mp13_adc_start_conv,
.stop_conv = stm32h7_adc_stop_conv,
.prepare = stm32h7_adc_prepare,
@@ -2630,6 +2779,7 @@ static const struct stm32_adc_cfg stm32mp13_adc_cfg = {
.smp_cycles = stm32mp13_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
.ts_int_ch = stm32_adc_min_ts_mp13,
+ .set_ovs = stm32mp13_adc_set_ovs,
};
static const struct of_device_id stm32_adc_of_match[] = {
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 726ddafc9f6d..f583924eb16b 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -108,7 +108,7 @@ static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_type[] = {
{ "SPI_F", 1 }, /* SPI with data on falling edge */
{ "MANCH_R", 2 }, /* Manchester codec, rising edge = logic 0 */
{ "MANCH_F", 3 }, /* Manchester codec, falling edge = logic 1 */
- {},
+ { }
};
/* DFSDM channel clock source */
@@ -121,7 +121,7 @@ static const struct stm32_dfsdm_str2field stm32_dfsdm_chan_src[] = {
{ "CLKOUT_F", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING },
/* Internal SPI clock divided by 2 (falling edge) */
{ "CLKOUT_R", DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING },
- {},
+ { }
};
static int stm32_dfsdm_str2val(const char *str,
@@ -167,7 +167,7 @@ static const struct stm32_dfsdm_trig_info stm32_dfsdm_trigs[] = {
{ LPTIM1_OUT, 26 },
{ LPTIM2_OUT, 27 },
{ LPTIM3_OUT, 28 },
- {},
+ { }
};
static int stm32_dfsdm_get_jextsel(struct iio_dev *indio_dev,
@@ -1747,7 +1747,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = {
.compatible = "st,stm32-dfsdm-dmic",
.data = &stm32h7_dfsdm_audio_data,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match);
diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c
index 136b8d9c294f..e4dfe76e6362 100644
--- a/drivers/iio/adc/sun20i-gpadc-iio.c
+++ b/drivers/iio/adc/sun20i-gpadc-iio.c
@@ -15,6 +15,7 @@
#include <linux/property.h>
#include <linux/reset.h>
+#include <linux/iio/adc-helpers.h>
#include <linux/iio/iio.h>
#define SUN20I_GPADC_DRIVER_NAME "sun20i-gpadc"
@@ -149,36 +150,23 @@ static void sun20i_gpadc_reset_assert(void *data)
reset_control_assert(rst);
}
+static const struct iio_chan_spec sun20i_gpadc_chan_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev,
struct device *dev)
{
- unsigned int channel;
- int num_channels, i, ret;
+ int num_channels;
struct iio_chan_spec *channels;
- num_channels = device_get_child_node_count(dev);
- if (num_channels == 0)
- return dev_err_probe(dev, -ENODEV, "no channel children\n");
-
- channels = devm_kcalloc(dev, num_channels, sizeof(*channels),
- GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- i = 0;
- device_for_each_child_node_scoped(dev, node) {
- ret = fwnode_property_read_u32(node, "reg", &channel);
- if (ret)
- return dev_err_probe(dev, ret, "invalid channel number\n");
-
- channels[i].type = IIO_VOLTAGE;
- channels[i].indexed = 1;
- channels[i].channel = channel;
- channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
- channels[i].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
-
- i++;
- }
+ num_channels = devm_iio_adc_device_alloc_chaninfo_se(dev,
+ &sun20i_gpadc_chan_template, -1, &channels);
+ if (num_channels < 0)
+ return num_channels;
indio_dev->channels = channels;
indio_dev->num_channels = num_channels;
@@ -255,7 +243,7 @@ static int sun20i_gpadc_probe(struct platform_device *pdev)
static const struct of_device_id sun20i_gpadc_of_id[] = {
{ .compatible = "allwinner,sun20i-d1-gpadc" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, sun20i_gpadc_of_id);
@@ -271,3 +259,4 @@ module_platform_driver(sun20i_gpadc_driver);
MODULE_DESCRIPTION("ADC driver for sunxi platforms");
MODULE_AUTHOR("Maksim Kiselev <bigunclemax@gmail.com>");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_DRIVER");
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 8b27458dcd66..6b8d6bee1873 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -116,7 +116,7 @@ struct sun4i_gpadc_iio {
static const struct iio_map sun4i_gpadc_hwmon_maps[] = {
IIO_MAP("temp_adc", "iio_hwmon.0", NULL),
- { /* sentinel */ },
+ { }
};
static const struct iio_chan_spec sun4i_gpadc_channels[] = {
@@ -485,7 +485,7 @@ static const struct of_device_id sun4i_gpadc_of_id[] = {
.compatible = "allwinner,sun8i-a33-ths",
.data = &sun8i_a33_gpadc_data,
},
- { /* sentinel */ }
+ { }
};
static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
@@ -685,7 +685,7 @@ static const struct platform_device_id sun4i_gpadc_id[] = {
{ "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data },
{ "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data },
{ "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data },
- { /* sentinel */ },
+ { }
};
MODULE_DEVICE_TABLE(platform, sun4i_gpadc_id);
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 1af9be071d8d..4f514db5c26e 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -140,8 +140,8 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p)
if (ret < 0)
goto out;
data->scan.channel = ret;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c
index e2dbd070c7c4..cfcdafbe284b 100644
--- a/drivers/iio/adc/ti-adc0832.c
+++ b/drivers/iio/adc/ti-adc0832.c
@@ -225,8 +225,8 @@ static irqreturn_t adc0832_trigger_handler(int irq, void *p)
adc->data[i] = ret;
i++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, adc->data, sizeof(adc->data),
+ iio_get_time_ns(indio_dev));
out:
mutex_unlock(&adc->lock);
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
index 9c845ee01697..50a474f4d9f5 100644
--- a/drivers/iio/adc/ti-adc084s021.c
+++ b/drivers/iio/adc/ti-adc084s021.c
@@ -151,8 +151,8 @@ static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc)
if (adc084s021_adc_conversion(adc, adc->scan.channels) < 0)
dev_err(&adc->spi->dev, "Failed to read data\n");
- iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &adc->scan, sizeof(adc->scan),
+ iio_get_time_ns(indio_dev));
mutex_unlock(&adc->lock);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c
index 7f065f457b36..9dc465a10ffc 100644
--- a/drivers/iio/adc/ti-adc12138.c
+++ b/drivers/iio/adc/ti-adc12138.c
@@ -376,8 +376,8 @@ static irqreturn_t adc12138_trigger_handler(int irq, void *p)
}
}
- iio_push_to_buffers_with_timestamp(indio_dev, adc->data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, adc->data, sizeof(adc->data),
+ iio_get_time_ns(indio_dev));
out:
mutex_unlock(&adc->lock);
diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c
index a456ea78462f..1b46a8155803 100644
--- a/drivers/iio/adc/ti-adc128s052.c
+++ b/drivers/iio/adc/ti-adc128s052.c
@@ -9,6 +9,7 @@
* https://www.ti.com/lit/ds/symlink/adc124s021.pdf
*/
+#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/mod_devicetable.h>
@@ -20,40 +21,44 @@
struct adc128_configuration {
const struct iio_chan_spec *channels;
u8 num_channels;
+ const char *refname;
+ int num_other_regulators;
+ const char * const (*other_regulators)[];
};
struct adc128 {
struct spi_device *spi;
- struct regulator *reg;
+ /*
+ * Serialize the SPI 'write-channel + read data' accesses and protect
+ * the shared buffer.
+ */
struct mutex lock;
-
- u8 buffer[2] __aligned(IIO_DMA_MINALIGN);
+ int vref_mv;
+ union {
+ __be16 buffer16;
+ u8 buffer[2];
+ } __aligned(IIO_DMA_MINALIGN);
};
static int adc128_adc_conversion(struct adc128 *adc, u8 channel)
{
int ret;
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
adc->buffer[0] = channel << 3;
adc->buffer[1] = 0;
- ret = spi_write(adc->spi, &adc->buffer, 2);
- if (ret < 0) {
- mutex_unlock(&adc->lock);
+ ret = spi_write(adc->spi, &adc->buffer, sizeof(adc->buffer));
+ if (ret < 0)
return ret;
- }
-
- ret = spi_read(adc->spi, &adc->buffer, 2);
-
- mutex_unlock(&adc->lock);
+ ret = spi_read(adc->spi, &adc->buffer16, sizeof(adc->buffer16));
if (ret < 0)
return ret;
- return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF);
+ return be16_to_cpu(adc->buffer16) & 0xFFF;
}
static int adc128_read_raw(struct iio_dev *indio_dev,
@@ -75,11 +80,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
- ret = regulator_get_voltage(adc->reg);
- if (ret < 0)
- return ret;
-
- *val = ret / 1000;
+ *val = adc->vref_mv;
*val2 = 12;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -121,21 +122,34 @@ static const struct iio_chan_spec adc124s021_channels[] = {
ADC128_VOLTAGE_CHANNEL(3),
};
+static const char * const bd79104_regulators[] = { "iovdd" };
+
static const struct adc128_configuration adc128_config[] = {
- { adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
- { adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
- { adc124s021_channels, ARRAY_SIZE(adc124s021_channels) },
+ {
+ .channels = adc128s052_channels,
+ .num_channels = ARRAY_SIZE(adc128s052_channels),
+ .refname = "vref",
+ }, {
+ .channels = adc122s021_channels,
+ .num_channels = ARRAY_SIZE(adc122s021_channels),
+ .refname = "vref",
+ }, {
+ .channels = adc124s021_channels,
+ .num_channels = ARRAY_SIZE(adc124s021_channels),
+ .refname = "vref",
+ }, {
+ .channels = adc128s052_channels,
+ .num_channels = ARRAY_SIZE(adc128s052_channels),
+ .refname = "vdd",
+ .other_regulators = &bd79104_regulators,
+ .num_other_regulators = 1,
+ },
};
static const struct iio_info adc128_info = {
.read_raw = adc128_read_raw,
};
-static void adc128_disable_regulator(void *reg)
-{
- regulator_disable(reg);
-}
-
static int adc128_probe(struct spi_device *spi)
{
const struct adc128_configuration *config;
@@ -159,20 +173,28 @@ static int adc128_probe(struct spi_device *spi)
indio_dev->channels = config->channels;
indio_dev->num_channels = config->num_channels;
- adc->reg = devm_regulator_get(&spi->dev, "vref");
- if (IS_ERR(adc->reg))
- return PTR_ERR(adc->reg);
-
- ret = regulator_enable(adc->reg);
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev,
+ config->refname);
if (ret < 0)
- return ret;
- ret = devm_add_action_or_reset(&spi->dev, adc128_disable_regulator,
- adc->reg);
+ return dev_err_probe(&spi->dev, ret,
+ "failed to read '%s' voltage",
+ config->refname);
+
+ adc->vref_mv = ret / 1000;
+
+ if (config->num_other_regulators) {
+ ret = devm_regulator_bulk_get_enable(&spi->dev,
+ config->num_other_regulators,
+ *config->other_regulators);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "Failed to enable regulators\n");
+ }
+
+ ret = devm_mutex_init(&spi->dev, &adc->lock);
if (ret)
return ret;
- mutex_init(&adc->lock);
-
return devm_iio_device_register(&spi->dev, indio_dev);
}
@@ -184,7 +206,8 @@ static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc124s021", .data = &adc128_config[2] },
{ .compatible = "ti,adc124s051", .data = &adc128_config[2] },
{ .compatible = "ti,adc124s101", .data = &adc128_config[2] },
- { /* sentinel */ },
+ { .compatible = "rohm,bd79104", .data = &adc128_config[3] },
+ { }
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
@@ -196,6 +219,7 @@ static const struct spi_device_id adc128_id[] = {
{ "adc124s021", (kernel_ulong_t)&adc128_config[2] },
{ "adc124s051", (kernel_ulong_t)&adc128_config[2] },
{ "adc124s101", (kernel_ulong_t)&adc128_config[2] },
+ { "bd79104", (kernel_ulong_t)&adc128_config[3] },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 4355726b373a..21181cc3bd85 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -12,6 +12,7 @@
*/
#include <linux/module.h>
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
@@ -466,8 +467,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
scan.chan = res;
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, &scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -533,6 +534,31 @@ static int ads1015_read_avail(struct iio_dev *indio_dev,
}
}
+static int __ads1015_read_info_raw(struct ads1015_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
+
+ if (ads1015_event_channel_enabled(data) &&
+ data->event_channel != chan->address)
+ return -EBUSY;
+
+ ret = ads1015_set_power_state(data, true);
+ if (ret < 0)
+ return ret;
+
+ ret = ads1015_get_adc_result(data, chan->address, val);
+ if (ret < 0) {
+ ads1015_set_power_state(data, false);
+ return ret;
+ }
+
+ *val = sign_extend32(*val >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+
+ return ads1015_set_power_state(data, false);
+}
+
static int ads1015_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -540,58 +566,29 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
int ret, idx;
struct ads1015_data *data = iio_priv(indio_dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = __ads1015_read_info_raw(data, chan, val);
+ iio_device_release_direct(indio_dev);
if (ret)
- break;
-
- if (ads1015_event_channel_enabled(data) &&
- data->event_channel != chan->address) {
- ret = -EBUSY;
- goto release_direct;
- }
-
- ret = ads1015_set_power_state(data, true);
- if (ret < 0)
- goto release_direct;
-
- ret = ads1015_get_adc_result(data, chan->address, val);
- if (ret < 0) {
- ads1015_set_power_state(data, false);
- goto release_direct;
- }
-
- *val = sign_extend32(*val >> chan->scan_type.shift,
- chan->scan_type.realbits - 1);
-
- ret = ads1015_set_power_state(data, false);
- if (ret < 0)
- goto release_direct;
+ return ret;
- ret = IIO_VAL_INT;
-release_direct:
- iio_device_release_direct_mode(indio_dev);
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
idx = data->channel_data[chan->address].pga;
*val = ads1015_fullscale_range[idx];
*val2 = chan->scan_type.realbits - 1;
- ret = IIO_VAL_FRACTIONAL_LOG2;
- break;
+ return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
idx = data->channel_data[chan->address].data_rate;
*val = data->chip->data_rate[idx];
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_write_raw(struct iio_dev *indio_dev,
@@ -599,23 +596,16 @@ static int ads1015_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = ads1015_set_scale(data, chan, val, val2);
- break;
+ return ads1015_set_scale(data, chan, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = ads1015_set_data_rate(data, chan->address, val);
- break;
+ return ads1015_set_data_rate(data, chan->address, val);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_read_event(struct iio_dev *indio_dev,
@@ -624,20 +614,18 @@ static int ads1015_read_event(struct iio_dev *indio_dev,
int *val2)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret;
unsigned int comp_queue;
int period;
int dr;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = (dir == IIO_EV_DIR_RISING) ?
data->thresh_data[chan->address].high_thresh :
data->thresh_data[chan->address].low_thresh;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
dr = data->channel_data[chan->address].data_rate;
comp_queue = data->thresh_data[chan->address].comp_queue;
@@ -646,16 +634,10 @@ static int ads1015_read_event(struct iio_dev *indio_dev,
*val = period / USEC_PER_SEC;
*val2 = period % USEC_PER_SEC;
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_write_event(struct iio_dev *indio_dev,
@@ -666,24 +648,22 @@ static int ads1015_write_event(struct iio_dev *indio_dev,
struct ads1015_data *data = iio_priv(indio_dev);
const int *data_rate = data->chip->data_rate;
int realbits = chan->scan_type.realbits;
- int ret = 0;
long long period;
int i;
int dr;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (info) {
case IIO_EV_INFO_VALUE:
- if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1)) {
- ret = -EINVAL;
- break;
- }
+ if (val >= 1 << (realbits - 1) || val < -1 << (realbits - 1))
+ return -EINVAL;
+
if (dir == IIO_EV_DIR_RISING)
data->thresh_data[chan->address].high_thresh = val;
else
data->thresh_data[chan->address].low_thresh = val;
- break;
+ return 0;
case IIO_EV_INFO_PERIOD:
dr = data->channel_data[chan->address].data_rate;
period = val * USEC_PER_SEC + val2;
@@ -694,15 +674,10 @@ static int ads1015_write_event(struct iio_dev *indio_dev,
break;
}
data->thresh_data[chan->address].comp_queue = i;
- break;
+ return 0;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1015_read_event_config(struct iio_dev *indio_dev,
@@ -710,25 +685,19 @@ static int ads1015_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
struct ads1015_data *data = iio_priv(indio_dev);
- int ret = 0;
- mutex_lock(&data->lock);
- if (data->event_channel == chan->address) {
- switch (dir) {
- case IIO_EV_DIR_RISING:
- ret = 1;
- break;
- case IIO_EV_DIR_EITHER:
- ret = (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- }
- mutex_unlock(&data->lock);
+ guard(mutex)(&data->lock);
+ if (data->event_channel != chan->address)
+ return 0;
- return ret;
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return 1;
+ case IIO_EV_DIR_EITHER:
+ return (data->comp_mode == ADS1015_CFG_COMP_MODE_WINDOW);
+ default:
+ return -EINVAL;
+ }
}
static int ads1015_enable_event_config(struct ads1015_data *data,
@@ -813,23 +782,18 @@ static int ads1015_write_event_config(struct iio_dev *indio_dev,
int comp_mode = (dir == IIO_EV_DIR_EITHER) ?
ADS1015_CFG_COMP_MODE_WINDOW : ADS1015_CFG_COMP_MODE_TRAD;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
/* Prevent from enabling both buffer and event at a time */
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret) {
- mutex_unlock(&data->lock);
- return ret;
- }
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
if (state)
ret = ads1015_enable_event_config(data, chan, comp_mode);
else
ret = ads1015_disable_event_config(data, chan, comp_mode);
- iio_device_release_direct_mode(indio_dev);
- mutex_unlock(&data->lock);
-
+ iio_device_release_direct(indio_dev);
return ret;
}
diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c
index 1e46f07a9ca6..b0790e300b18 100644
--- a/drivers/iio/adc/ti-ads1100.c
+++ b/drivers/iio/adc/ti-ads1100.c
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -219,36 +220,30 @@ static int ads1100_read_raw(struct iio_dev *indio_dev,
int ret;
struct ads1100_data *data = iio_priv(indio_dev);
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- break;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = ads1100_get_adc_result(data, chan->address, val);
- if (ret >= 0)
- ret = IIO_VAL_INT;
- iio_device_release_direct_mode(indio_dev);
- break;
+ iio_device_release_direct(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* full-scale is the supply voltage in millivolts */
*val = ads1100_get_vdd_millivolts(data);
*val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config);
- ret = IIO_VAL_FRACTIONAL_LOG2;
- break;
+ return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK,
data->config)];
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static int ads1100_write_raw(struct iio_dev *indio_dev,
@@ -256,23 +251,16 @@ static int ads1100_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct ads1100_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = ads1100_set_scale(data, val, val2);
- break;
+ return ads1100_set_scale(data, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = ads1100_set_data_rate(data, chan->address, val);
- break;
+ return ads1100_set_data_rate(data, chan->address, val);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- mutex_unlock(&data->lock);
-
- return ret;
}
static const struct iio_info ads1100_info = {
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index f120e7e21cff..d280c949cf47 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -534,8 +534,8 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private)
scan.sample = ret;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c
index 77c299bb4ebc..8ea1269f74db 100644
--- a/drivers/iio/adc/ti-ads124s08.c
+++ b/drivers/iio/adc/ti-ads124s08.c
@@ -297,8 +297,8 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p)
j++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, priv->buffer, sizeof(priv->buffer),
+ pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index c6096b64664e..085f0d6fb39e 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -664,8 +664,8 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
i++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, st->tmp_buf.data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->tmp_buf, sizeof(st->tmp_buf),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c
index af28672aa803..0356ccf23fea 100644
--- a/drivers/iio/adc/ti-ads7950.c
+++ b/drivers/iio/adc/ti-ads7950.c
@@ -403,10 +403,11 @@ static const struct iio_info ti_ads7950_info = {
.update_scan_mode = ti_ads7950_update_scan_mode,
};
-static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
+ int ret;
mutex_lock(&st->slock);
@@ -416,9 +417,11 @@ static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
st->cmd_settings_bitmask &= ~BIT(offset);
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
- spi_sync(st->spi, &st->scan_single_msg);
+ ret = spi_sync(st->spi, &st->scan_single_msg);
mutex_unlock(&st->slock);
+
+ return ret;
}
static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
@@ -499,7 +502,11 @@ static int ti_ads7950_direction_input(struct gpio_chip *chip,
static int ti_ads7950_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
- ti_ads7950_set(chip, offset, value);
+ int ret;
+
+ ret = ti_ads7950_set(chip, offset, value);
+ if (ret)
+ return ret;
return _ti_ads7950_set_direction(chip, offset, 0);
}
@@ -641,7 +648,7 @@ static int ti_ads7950_probe(struct spi_device *spi)
st->chip.direction_input = ti_ads7950_direction_input;
st->chip.direction_output = ti_ads7950_direction_output;
st->chip.get = ti_ads7950_get;
- st->chip.set = ti_ads7950_set;
+ st->chip.set_rv = ti_ads7950_set;
ret = gpiochip_add_data(&st->chip, st);
if (ret) {
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
index a31658b760a4..b0bf46cae0b6 100644
--- a/drivers/iio/adc/ti-ads8688.c
+++ b/drivers/iio/adc/ti-ads8688.c
@@ -389,8 +389,8 @@ static irqreturn_t ads8688_trigger_handler(int irq, void *p)
j++;
}
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c
index 1e4a78677fe5..3f375c1f586c 100644
--- a/drivers/iio/adc/ti-lmp92064.c
+++ b/drivers/iio/adc/ti-lmp92064.c
@@ -209,8 +209,8 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p)
if (ret)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data, sizeof(data),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -366,7 +366,7 @@ MODULE_DEVICE_TABLE(spi, lmp92064_id_table);
static const struct of_device_id lmp92064_of_table[] = {
{ .compatible = "ti,lmp92064" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, lmp92064_of_table);
diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c
index 5a138be983ed..f67945c62c99 100644
--- a/drivers/iio/adc/ti-tlc4541.c
+++ b/drivers/iio/adc/ti-tlc4541.c
@@ -99,8 +99,8 @@ static irqreturn_t tlc4541_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, st->rx_buf, sizeof(st->rx_buf),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
index 49560059f4b7..c2d2aada6772 100644
--- a/drivers/iio/adc/ti-tsc2046.c
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -418,8 +418,9 @@ static int tsc2046_adc_scan(struct iio_dev *indio_dev)
for (group = 0; group < priv->groups; group++)
priv->scan_buf.data[group] = tsc2046_adc_get_val(priv, group);
- ret = iio_push_to_buffers_with_timestamp(indio_dev, &priv->scan_buf,
- iio_get_time_ns(indio_dev));
+ ret = iio_push_to_buffers_with_ts(indio_dev, &priv->scan_buf,
+ sizeof(priv->scan_buf),
+ iio_get_time_ns(indio_dev));
/* If the consumer is kfifo, we may get a EBUSY here - ignore it. */
if (ret < 0 && ret != -EBUSY) {
dev_err_ratelimited(dev, "Failed to push scan buffer %pe\n",
@@ -760,7 +761,6 @@ static int tsc2046_adc_probe(struct spi_device *spi)
if (!dcfg)
return -EINVAL;
- spi->bits_per_word = 8;
spi->mode &= ~SPI_MODE_X_MASK;
spi->mode |= SPI_MODE_0;
ret = spi_setup(spi);
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
index ef7430e6877d..3ac774ebf678 100644
--- a/drivers/iio/adc/twl6030-gpadc.c
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -871,7 +871,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = {
.compatible = "ti,twl6032-gpadc",
.data = &twl6032_pdata,
},
- { /* end */ }
+ { }
};
MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl);
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 513365d42aa5..6404b015234a 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -11,6 +11,7 @@
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -504,7 +505,7 @@ static const struct iio_enum vf610_conversion_mode = {
static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR, &vf610_conversion_mode),
- {},
+ { }
};
#define VF610_ADC_CHAN(_idx, _chan_type) { \
@@ -591,9 +592,9 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
info->value = vf610_adc_read_data(info);
if (iio_buffer_enabled(indio_dev)) {
info->scan.chan = info->value;
- iio_push_to_buffers_with_timestamp(indio_dev,
- &info->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &info->scan,
+ sizeof(info->scan),
+ iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
} else
complete(&info->completion);
@@ -630,36 +631,29 @@ static const struct attribute_group vf610_attribute_group = {
.attrs = vf610_attributes,
};
-static int vf610_read_sample(struct iio_dev *indio_dev,
+static int vf610_read_sample(struct vf610_adc *info,
struct iio_chan_spec const *chan, int *val)
{
- struct vf610_adc *info = iio_priv(indio_dev);
unsigned int hc_cfg;
int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
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);
ret = wait_for_completion_interruptible_timeout(&info->completion,
VF610_ADC_TIMEOUT);
- if (ret == 0) {
- ret = -ETIMEDOUT;
- goto out_unlock;
- }
+ if (ret == 0)
+ return -ETIMEDOUT;
if (ret < 0)
- goto out_unlock;
+ return ret;
switch (chan->type) {
case IIO_VOLTAGE:
*val = info->value;
- break;
+ return 0;
case IIO_TEMP:
/*
* Calculate in degree Celsius times 1000
@@ -669,17 +663,10 @@ static int vf610_read_sample(struct iio_dev *indio_dev,
*val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
1000000 / VF610_TEMP_SLOPE_COEFF;
- break;
+ return 0;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
-out_unlock:
- mutex_unlock(&info->lock);
- iio_device_release_direct_mode(indio_dev);
-
- return ret;
}
static int vf610_read_raw(struct iio_dev *indio_dev,
@@ -694,7 +681,10 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
- ret = vf610_read_sample(indio_dev, chan, val);
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = vf610_read_sample(info, chan, val);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -823,7 +813,7 @@ static const struct vf610_chip_info imx6sx_chip_info = {
static const struct of_device_id vf610_adc_match[] = {
{ .compatible = "fsl,imx6sx-adc", .data = &imx6sx_chip_info},
{ .compatible = "fsl,vf610-adc", .data = &vf610_chip_info},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, vf610_adc_match);
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index e1f8740ae688..e257c1b94a5f 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -1186,7 +1186,7 @@ static const struct of_device_id xadc_of_match_table[] = {
.compatible = "xlnx,system-management-wiz-1.3",
.data = &xadc_us_axi_ops
},
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, xadc_of_match_table);
diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c
index a7e480f2472d..4d8b64048e4f 100644
--- a/drivers/iio/addac/ad74115.c
+++ b/drivers/iio/addac/ad74115.c
@@ -542,18 +542,16 @@ static int ad74115_gpio_get(struct gpio_chip *gc, unsigned int offset)
return FIELD_GET(AD74115_GPIO_CONFIG_GPI_DATA, val);
}
-static void ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+static int ad74115_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
{
struct ad74115_state *st = gpiochip_get_data(gc);
- struct device *dev = &st->spi->dev;
- int ret;
- ret = regmap_update_bits(st->regmap, AD74115_GPIO_CONFIG_X_REG(offset),
- AD74115_GPIO_CONFIG_GPO_DATA,
- FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA, value));
- if (ret)
- dev_err(dev, "Failed to set GPIO %u output value, err: %d\n",
- offset, ret);
+ return regmap_update_bits(st->regmap,
+ AD74115_GPIO_CONFIG_X_REG(offset),
+ AD74115_GPIO_CONFIG_GPO_DATA,
+ FIELD_PREP(AD74115_GPIO_CONFIG_GPO_DATA,
+ value));
}
static int ad74115_set_comp_debounce(struct ad74115_state *st, unsigned int val)
@@ -866,15 +864,14 @@ static int ad74115_get_adc_code(struct iio_dev *indio_dev,
struct ad74115_state *st = iio_priv(indio_dev);
int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&st->lock);
ret = _ad74115_get_adc_code(st, channel, val);
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -1580,7 +1577,7 @@ static int ad74115_setup_gpio_chip(struct ad74115_state *st)
.direction_input = ad74115_gpio_direction_input,
.direction_output = ad74115_gpio_direction_output,
.get = ad74115_gpio_get,
- .set = ad74115_gpio_set,
+ .set_rv = ad74115_gpio_set,
};
return devm_gpiochip_add_data(dev, &st->gc, st);
diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c
index f14d12b03da6..a0bb1dbcb7ad 100644
--- a/drivers/iio/addac/ad74413r.c
+++ b/drivers/iio/addac/ad74413r.c
@@ -4,7 +4,6 @@
* Author: Cosmin Tanislav <cosmin.tanislav@analog.com>
*/
-#include <linux/unaligned.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/crc8.h>
@@ -24,6 +23,8 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
#include <dt-bindings/iio/addac/adi,ad74413r.h>
@@ -84,7 +85,7 @@ struct ad74413r_state {
*/
struct {
u8 rx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX];
- s64 timestamp;
+ aligned_s64 timestamp;
} adc_samples_buf __aligned(IIO_DMA_MINALIGN);
u8 adc_samples_tx_buf[AD74413R_FRAME_SIZE * AD74413R_CHANNEL_MAX];
@@ -276,8 +277,8 @@ static int ad74413r_set_comp_drive_strength(struct ad74413r_state *st,
}
-static void ad74413r_gpio_set(struct gpio_chip *chip,
- unsigned int offset, int val)
+static int ad74413r_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct ad74413r_state *st = gpiochip_get_data(chip);
unsigned int real_offset = st->gpo_gpio_offsets[offset];
@@ -286,16 +287,16 @@ static void ad74413r_gpio_set(struct gpio_chip *chip,
ret = ad74413r_set_gpo_config(st, real_offset,
AD74413R_GPO_CONFIG_LOGIC);
if (ret)
- return;
+ return ret;
- regmap_update_bits(st->regmap, AD74413R_REG_GPO_CONFIG_X(real_offset),
- AD74413R_GPO_CONFIG_DATA_MASK,
- val ? AD74413R_GPO_CONFIG_DATA_MASK : 0);
+ return regmap_update_bits(st->regmap,
+ AD74413R_REG_GPO_CONFIG_X(real_offset),
+ AD74413R_GPO_CONFIG_DATA_MASK,
+ val ? AD74413R_GPO_CONFIG_DATA_MASK : 0);
}
-static void ad74413r_gpio_set_multiple(struct gpio_chip *chip,
- unsigned long *mask,
- unsigned long *bits)
+static int ad74413r_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
{
struct ad74413r_state *st = gpiochip_get_data(chip);
unsigned long real_mask = 0;
@@ -309,15 +310,15 @@ static void ad74413r_gpio_set_multiple(struct gpio_chip *chip,
ret = ad74413r_set_gpo_config(st, real_offset,
AD74413R_GPO_CONFIG_LOGIC_PARALLEL);
if (ret)
- return;
+ return ret;
real_mask |= BIT(real_offset);
if (*bits & offset)
real_bits |= BIT(real_offset);
}
- regmap_update_bits(st->regmap, AD74413R_REG_GPO_PAR_DATA,
- real_mask, real_bits);
+ return regmap_update_bits(st->regmap, AD74413R_REG_GPO_PAR_DATA,
+ real_mask, real_bits);
}
static int ad74413r_gpio_get(struct gpio_chip *chip, unsigned int offset)
@@ -1424,8 +1425,8 @@ static int ad74413r_probe(struct spi_device *spi)
st->gpo_gpiochip.ngpio = st->num_gpo_gpios;
st->gpo_gpiochip.parent = st->dev;
st->gpo_gpiochip.can_sleep = true;
- st->gpo_gpiochip.set = ad74413r_gpio_set;
- st->gpo_gpiochip.set_multiple = ad74413r_gpio_set_multiple;
+ st->gpo_gpiochip.set_rv = ad74413r_gpio_set;
+ st->gpo_gpiochip.set_multiple_rv = ad74413r_gpio_set_multiple;
st->gpo_gpiochip.set_config = ad74413r_gpio_set_gpo_config;
st->gpo_gpiochip.get_direction =
ad74413r_gpio_get_gpo_direction;
@@ -1505,14 +1506,14 @@ static const struct of_device_id ad74413r_dt_id[] = {
.compatible = "adi,ad74413r",
.data = &ad74413r_chip_info_data,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ad74413r_dt_id);
static const struct spi_device_id ad74413r_spi_id[] = {
{ .name = "ad74412r", .driver_data = (kernel_ulong_t)&ad74412r_chip_info_data },
{ .name = "ad74413r", .driver_data = (kernel_ulong_t)&ad74413r_chip_info_data },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad74413r_spi_id);
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index b6a46036d5ea..ecaf59278c6f 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -514,7 +514,7 @@ static const struct of_device_id rescale_match[] = {
.data = &rescale_cfg[TEMP_SENSE_RTD], },
{ .compatible = "temperature-transducer",
.data = &rescale_cfg[TEMP_TRANSDUCER], },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, rescale_match);
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index 31564afb13a2..e73c9b983395 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -330,7 +330,7 @@ static const struct spi_device_id ad8366_id[] = {
{"adl5240", ID_ADL5240},
{"hmc792a", ID_HMC792},
{"hmc1119", ID_HMC1119},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad8366_id);
diff --git a/drivers/iio/amplifiers/ada4250.c b/drivers/iio/amplifiers/ada4250.c
index 566f0e1c98a5..74f8429d652b 100644
--- a/drivers/iio/amplifiers/ada4250.c
+++ b/drivers/iio/amplifiers/ada4250.c
@@ -378,13 +378,13 @@ static int ada4250_probe(struct spi_device *spi)
static const struct spi_device_id ada4250_id[] = {
{ "ada4250", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ada4250_id);
static const struct of_device_id ada4250_of_match[] = {
{ .compatible = "adi,ada4250" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ada4250_of_match);
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index d9a359e1388a..4dbf894c7e3b 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -270,7 +270,7 @@ static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = {
.write = ltc6373_write_powerdown,
.shared = IIO_SEPARATE,
},
- {}
+ { }
};
#define HMC425A_CHAN(_channel) \
@@ -398,7 +398,6 @@ static int hmc425a_probe(struct platform_device *pdev)
return devm_iio_device_register(&pdev->dev, indio_dev);
}
-/* Match table for of_platform binding */
static const struct of_device_id hmc425a_of_match[] = {
{ .compatible = "adi,hmc425a",
.data = &hmc425a_chip_info_tbl[ID_HMC425A]},
@@ -408,7 +407,7 @@ static const struct of_device_id hmc425a_of_match[] = {
.data = &hmc425a_chip_info_tbl[ID_ADRF5740]},
{ .compatible = "adi,ltc6373",
.data = &hmc425a_chip_info_tbl[ID_LTC6373]},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c
index e64a41bae32c..427d32e398b3 100644
--- a/drivers/iio/cdc/ad7150.c
+++ b/drivers/iio/cdc/ad7150.c
@@ -631,7 +631,7 @@ static const struct i2c_device_id ad7150_id[] = {
{ "ad7150", AD7150 },
{ "ad7151", AD7151 },
{ "ad7156", AD7150 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad7150_id);
@@ -640,7 +640,7 @@ static const struct of_device_id ad7150_of_match[] = {
{ "adi,ad7150" },
{ "adi,ad7151" },
{ "adi,ad7156" },
- {}
+ { }
};
static struct i2c_driver ad7150_driver = {
.driver = {
diff --git a/drivers/iio/cdc/ad7746.c b/drivers/iio/cdc/ad7746.c
index ba18dbbe0940..8a306d55c72a 100644
--- a/drivers/iio/cdc/ad7746.c
+++ b/drivers/iio/cdc/ad7746.c
@@ -792,7 +792,7 @@ static const struct i2c_device_id ad7746_id[] = {
{ "ad7745", 7745 },
{ "ad7746", 7746 },
{ "ad7747", 7747 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad7746_id);
@@ -800,7 +800,7 @@ static const struct of_device_id ad7746_of_match[] = {
{ .compatible = "adi,ad7745" },
{ .compatible = "adi,ad7746" },
{ .compatible = "adi,ad7747" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, ad7746_of_match);
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index 330fe0af946f..b22afa1f6d59 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -108,6 +108,16 @@ config IAQCORE
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
sensors
+config MHZ19B
+ tristate "Winsen MHZ19B CO2 sensor"
+ depends on SERIAL_DEV_BUS
+ help
+ Say Y here to build Serdev interface support for the Winsen
+ MHZ19B CO2 sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called mhz19b.
+
config PMS7003
tristate "Plantower PMS7003 particulate matter sensor"
depends on SERIAL_DEV_BUS
@@ -166,6 +176,16 @@ config SCD4X
To compile this driver as a module, choose M here: the module will
be called scd4x.
+config SEN0322
+ tristate "SEN0322 oxygen sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here to build support for the DFRobot SEN0322 oxygen sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called sen0322.
+
config SENSIRION_SGP30
tristate "Sensirion SGPxx gas sensors"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index 4866db06bdc9..2287a00a6b75 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -15,11 +15,13 @@ obj-$(CONFIG_ENS160) += ens160_core.o
obj-$(CONFIG_ENS160_I2C) += ens160_i2c.o
obj-$(CONFIG_ENS160_SPI) += ens160_spi.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
+obj-$(CONFIG_MHZ19B) += mhz19b.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SCD30_CORE) += scd30_core.o
obj-$(CONFIG_SCD30_I2C) += scd30_i2c.o
obj-$(CONFIG_SCD30_SERIAL) += scd30_serial.o
obj-$(CONFIG_SCD4X) += scd4x.o
+obj-$(CONFIG_SEN0322) += sen0322.o
obj-$(CONFIG_SENSEAIR_SUNRISE_CO2) += sunrise_co2.o
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
obj-$(CONFIG_SENSIRION_SGP40) += sgp40.o
diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c
index 8fcd80946543..151178d4e8f4 100644
--- a/drivers/iio/chemical/ags02ma.c
+++ b/drivers/iio/chemical/ags02ma.c
@@ -140,13 +140,13 @@ static int ags02ma_probe(struct i2c_client *client)
static const struct i2c_device_id ags02ma_id_table[] = {
{ "ags02ma" },
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, ags02ma_id_table);
static const struct of_device_id ags02ma_of_table[] = {
{ .compatible = "aosong,ags02ma" },
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, ags02ma_of_table);
diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c
index 761a853a4d17..de0b87edd188 100644
--- a/drivers/iio/chemical/atlas-ezo-sensor.c
+++ b/drivers/iio/chemical/atlas-ezo-sensor.c
@@ -189,7 +189,7 @@ static const struct i2c_device_id atlas_ezo_id[] = {
{ "atlas-co2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_CO2_EZO] },
{ "atlas-o2-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_O2_EZO] },
{ "atlas-hum-ezo", (kernel_ulong_t)&atlas_ezo_devices[ATLAS_HUM_EZO] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
@@ -197,7 +197,7 @@ static const struct of_device_id atlas_ezo_dt_ids[] = {
{ .compatible = "atlas,co2-ezo", .data = &atlas_ezo_devices[ATLAS_CO2_EZO], },
{ .compatible = "atlas,o2-ezo", .data = &atlas_ezo_devices[ATLAS_O2_EZO], },
{ .compatible = "atlas,hum-ezo", .data = &atlas_ezo_devices[ATLAS_HUM_EZO], },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c
index baf93e5e3ca7..cb6662b92137 100644
--- a/drivers/iio/chemical/atlas-sensor.c
+++ b/drivers/iio/chemical/atlas-sensor.c
@@ -458,8 +458,9 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
&data->buffer, sizeof(__be32) * channels);
if (!ret)
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, data->buffer,
+ sizeof(data->buffer),
+ iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
@@ -518,13 +519,12 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
case IIO_CONCENTRATION:
case IIO_ELECTRICALCONDUCTIVITY:
case IIO_VOLTAGE:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = atlas_read_measurement(data, chan->address, &reg);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
break;
default:
ret = -EINVAL;
@@ -594,7 +594,7 @@ static const struct i2c_device_id atlas_id[] = {
{ "atlas-orp-sm", (kernel_ulong_t)&atlas_devices[ATLAS_ORP_SM] },
{ "atlas-do-sm", (kernel_ulong_t)&atlas_devices[ATLAS_DO_SM] },
{ "atlas-rtd-sm", (kernel_ulong_t)&atlas_devices[ATLAS_RTD_SM] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c
index 9d73fd2cf52c..3e850562ab00 100644
--- a/drivers/iio/chemical/bme680_core.c
+++ b/drivers/iio/chemical/bme680_core.c
@@ -1120,8 +1120,8 @@ static irqreturn_t bme680_trigger_handler(int irq, void *p)
gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val);
data->scan.chan[3] = bme680_compensate_gas(data, adc_gas_res, gas_range);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c
index ac7763f98a6a..5560ea708b36 100644
--- a/drivers/iio/chemical/bme680_i2c.c
+++ b/drivers/iio/chemical/bme680_i2c.c
@@ -37,13 +37,13 @@ static int bme680_i2c_probe(struct i2c_client *client)
static const struct i2c_device_id bme680_i2c_id[] = {
{ "bme680" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
static const struct of_device_id bme680_of_i2c_match[] = {
{ .compatible = "bosch,bme680", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, bme680_of_i2c_match);
diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c
index ecb24ba0ebc9..aa97645ba539 100644
--- a/drivers/iio/chemical/bme680_spi.c
+++ b/drivers/iio/chemical/bme680_spi.c
@@ -112,14 +112,6 @@ static int bme680_spi_probe(struct spi_device *spi)
const struct spi_device_id *id = spi_get_device_id(spi);
struct bme680_spi_bus_context *bus_context;
struct regmap *regmap;
- int ret;
-
- spi->bits_per_word = 8;
- ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(&spi->dev, "spi_setup failed!\n");
- return ret;
- }
bus_context = devm_kzalloc(&spi->dev, sizeof(*bus_context), GFP_KERNEL);
if (!bus_context)
@@ -140,13 +132,13 @@ static int bme680_spi_probe(struct spi_device *spi)
static const struct spi_device_id bme680_spi_id[] = {
{"bme680", 0},
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, bme680_spi_id);
static const struct of_device_id bme680_of_spi_match[] = {
{ .compatible = "bosch,bme680", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
index 451fb65dbe60..998c9239c4c7 100644
--- a/drivers/iio/chemical/ccs811.c
+++ b/drivers/iio/chemical/ccs811.c
@@ -15,6 +15,7 @@
* 4. Read error register and put the information in logs
*/
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -214,6 +215,40 @@ static int ccs811_get_measurement(struct ccs811_data *data)
return ret;
}
+static int ccs811_read_info_raw(struct ccs811_data *data,
+ struct iio_chan_spec const *chan,
+ int *val, int mask)
+{
+ int ret;
+
+ guard(mutex)(&data->lock);
+ ret = ccs811_get_measurement(data);
+ if (ret < 0)
+ return ret;
+
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = be16_to_cpu(data->buffer.raw_data) & CCS811_VOLTAGE_MASK;
+ return IIO_VAL_INT;
+ case IIO_CURRENT:
+ *val = be16_to_cpu(data->buffer.raw_data) >> 10;
+ return IIO_VAL_INT;
+ case IIO_CONCENTRATION:
+ switch (chan->channel2) {
+ case IIO_MOD_CO2:
+ *val = be16_to_cpu(data->buffer.co2);
+ return IIO_VAL_INT;
+ case IIO_MOD_VOC:
+ *val = be16_to_cpu(data->buffer.voc);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
static int ccs811_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -223,46 +258,12 @@ static int ccs811_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
- mutex_lock(&data->lock);
- ret = ccs811_get_measurement(data);
- if (ret < 0) {
- mutex_unlock(&data->lock);
- iio_device_release_direct_mode(indio_dev);
- return ret;
- }
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
- switch (chan->type) {
- case IIO_VOLTAGE:
- *val = be16_to_cpu(data->buffer.raw_data) &
- CCS811_VOLTAGE_MASK;
- ret = IIO_VAL_INT;
- break;
- case IIO_CURRENT:
- *val = be16_to_cpu(data->buffer.raw_data) >> 10;
- ret = IIO_VAL_INT;
- break;
- case IIO_CONCENTRATION:
- switch (chan->channel2) {
- case IIO_MOD_CO2:
- *val = be16_to_cpu(data->buffer.co2);
- ret = IIO_VAL_INT;
- break;
- case IIO_MOD_VOC:
- *val = be16_to_cpu(data->buffer.voc);
- ret = IIO_VAL_INT;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- default:
- ret = -EINVAL;
- }
- mutex_unlock(&data->lock);
- iio_device_release_direct_mode(indio_dev);
+ ret = ccs811_read_info_raw(data, chan, val, mask);
+
+ iio_device_release_direct(indio_dev);
return ret;
@@ -342,8 +343,8 @@ static irqreturn_t ccs811_trigger_handler(int irq, void *p)
goto err;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c
index 152f81ff57e3..6cec60074827 100644
--- a/drivers/iio/chemical/ens160_core.c
+++ b/drivers/iio/chemical/ens160_core.c
@@ -267,8 +267,8 @@ static irqreturn_t ens160_trigger_handler(int irq, void *p)
if (ret)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c
new file mode 100644
index 000000000000..3c64154918b1
--- /dev/null
+++ b/drivers/iio/chemical/mhz19b.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mh-z19b CO₂ sensor driver
+ *
+ * Copyright (c) 2025 Gyeyoung Baek <gye976@gmail.com>
+ *
+ * Datasheet:
+ * https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
+ */
+
+#include <linux/array_size.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/kstrtox.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serdev.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+/*
+ * Commands have following format:
+ *
+ * +------+------+-----+------+------+------+------+------+-------+
+ * | 0xFF | 0x01 | cmd | arg0 | arg1 | 0x00 | 0x00 | 0x00 | cksum |
+ * +------+------+-----+------+------+------+------+------+-------+
+ */
+#define MHZ19B_CMD_SIZE 9
+
+/* ABC logic in MHZ19B means auto calibration. */
+#define MHZ19B_ABC_LOGIC_CMD 0x79
+#define MHZ19B_READ_CO2_CMD 0x86
+#define MHZ19B_SPAN_POINT_CMD 0x88
+#define MHZ19B_ZERO_POINT_CMD 0x87
+
+#define MHZ19B_SPAN_POINT_PPM_MIN 1000
+#define MHZ19B_SPAN_POINT_PPM_MAX 5000
+
+#define MHZ19B_SERDEV_TIMEOUT msecs_to_jiffies(100)
+
+struct mhz19b_state {
+ struct serdev_device *serdev;
+
+ /* Must wait until the 'buf' is filled with 9 bytes.*/
+ struct completion buf_ready;
+
+ u8 buf_idx;
+ /*
+ * Serdev receive buffer.
+ * When data is received from the MH-Z19B,
+ * the 'mhz19b_receive_buf' callback function is called and fills this buffer.
+ */
+ u8 buf[MHZ19B_CMD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+static u8 mhz19b_get_checksum(u8 *cmd_buf)
+{
+ u8 i, checksum = 0;
+
+/*
+ * +------+------+-----+------+------+------+------+------+-------+
+ * | 0xFF | 0x01 | cmd | arg0 | arg1 | 0x00 | 0x00 | 0x00 | cksum |
+ * +------+------+-----+------+------+------+------+------+-------+
+ * i:1 2 3 4 5 6 7
+ *
+ * Sum all cmd_buf elements from index 1 to 7.
+ */
+ for (i = 1; i < 8; i++)
+ checksum += cmd_buf[i];
+
+ return -checksum;
+}
+
+static int mhz19b_serdev_cmd(struct iio_dev *indio_dev, int cmd, u16 arg)
+{
+ struct mhz19b_state *st = iio_priv(indio_dev);
+ struct serdev_device *serdev = st->serdev;
+ struct device *dev = &indio_dev->dev;
+ int ret;
+
+ /*
+ * cmd_buf[3,4] : arg0,1
+ * cmd_buf[8] : checksum
+ */
+ u8 cmd_buf[MHZ19B_CMD_SIZE] = {
+ 0xFF, 0x01, cmd,
+ };
+
+ switch (cmd) {
+ case MHZ19B_ABC_LOGIC_CMD:
+ cmd_buf[3] = arg ? 0xA0 : 0;
+ break;
+ case MHZ19B_SPAN_POINT_CMD:
+ put_unaligned_be16(arg, &cmd_buf[3]);
+ break;
+ default:
+ break;
+ }
+ cmd_buf[8] = mhz19b_get_checksum(cmd_buf);
+
+ /* Write buf to uart ctrl synchronously */
+ ret = serdev_device_write(serdev, cmd_buf, MHZ19B_CMD_SIZE, 0);
+ if (ret < 0)
+ return ret;
+ if (ret != MHZ19B_CMD_SIZE)
+ return -EIO;
+
+ switch (cmd) {
+ case MHZ19B_READ_CO2_CMD:
+ ret = wait_for_completion_interruptible_timeout(&st->buf_ready,
+ MHZ19B_SERDEV_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ return -ETIMEDOUT;
+
+ if (st->buf[8] != mhz19b_get_checksum(st->buf)) {
+ dev_err(dev, "checksum err");
+ return -EINVAL;
+ }
+
+ return get_unaligned_be16(&st->buf[2]);
+ default:
+ /* No response commands. */
+ return 0;
+ }
+}
+
+static int mhz19b_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+
+ ret = mhz19b_serdev_cmd(indio_dev, MHZ19B_READ_CO2_CMD, 0);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+}
+
+/*
+ * echo 0 > calibration_auto_enable : ABC logic off
+ * echo 1 > calibration_auto_enable : ABC logic on
+ */
+static ssize_t calibration_auto_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool enable;
+ int ret;
+
+ ret = kstrtobool(buf, &enable);
+ if (ret)
+ return ret;
+
+ ret = mhz19b_serdev_cmd(indio_dev, MHZ19B_ABC_LOGIC_CMD, enable);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+static IIO_DEVICE_ATTR_WO(calibration_auto_enable, 0);
+
+/*
+ * echo 0 > calibration_forced_value : zero point calibration
+ * (make sure the sensor has been working under 400ppm for over 20 minutes.)
+ * echo [1000 1 5000] > calibration_forced_value : span point calibration
+ * (make sure the sensor has been working under a certain level CO₂ for over 20 minutes.)
+ */
+static ssize_t calibration_forced_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ u16 ppm;
+ int cmd, ret;
+
+ ret = kstrtou16(buf, 0, &ppm);
+ if (ret)
+ return ret;
+
+ if (ppm) {
+ if (!in_range(ppm, MHZ19B_SPAN_POINT_PPM_MIN,
+ MHZ19B_SPAN_POINT_PPM_MAX - MHZ19B_SPAN_POINT_PPM_MIN + 1)) {
+ dev_dbg(&indio_dev->dev,
+ "span point ppm should be in a range [%d-%d]\n",
+ MHZ19B_SPAN_POINT_PPM_MIN, MHZ19B_SPAN_POINT_PPM_MAX);
+ return -EINVAL;
+ }
+
+ cmd = MHZ19B_SPAN_POINT_CMD;
+ } else {
+ cmd = MHZ19B_ZERO_POINT_CMD;
+ }
+
+ ret = mhz19b_serdev_cmd(indio_dev, cmd, ppm);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+static IIO_DEVICE_ATTR_WO(calibration_forced_value, 0);
+
+static struct attribute *mhz19b_attrs[] = {
+ &iio_dev_attr_calibration_auto_enable.dev_attr.attr,
+ &iio_dev_attr_calibration_forced_value.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group mhz19b_attr_group = {
+ .attrs = mhz19b_attrs,
+};
+
+static const struct iio_info mhz19b_info = {
+ .attrs = &mhz19b_attr_group,
+ .read_raw = mhz19b_read_raw,
+};
+
+static const struct iio_chan_spec mhz19b_channels[] = {
+ {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_CO2,
+ .modified = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+};
+
+static size_t mhz19b_receive_buf(struct serdev_device *serdev,
+ const u8 *data, size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
+ struct mhz19b_state *st = iio_priv(indio_dev);
+
+ memcpy(st->buf + st->buf_idx, data, len);
+ st->buf_idx += len;
+
+ if (st->buf_idx == MHZ19B_CMD_SIZE) {
+ st->buf_idx = 0;
+ complete(&st->buf_ready);
+ }
+
+ return len;
+}
+
+static const struct serdev_device_ops mhz19b_ops = {
+ .receive_buf = mhz19b_receive_buf,
+ .write_wakeup = serdev_device_write_wakeup,
+};
+
+static int mhz19b_probe(struct serdev_device *serdev)
+{
+ int ret;
+ struct device *dev = &serdev->dev;
+ struct iio_dev *indio_dev;
+ struct mhz19b_state *st;
+
+ serdev_device_set_client_ops(serdev, &mhz19b_ops);
+ ret = devm_serdev_device_open(dev, serdev);
+ if (ret)
+ return ret;
+ serdev_device_set_baudrate(serdev, 9600);
+ serdev_device_set_flow_control(serdev, false);
+ ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+ if (ret)
+ return ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+ serdev_device_set_drvdata(serdev, indio_dev);
+
+ st = iio_priv(indio_dev);
+ st->serdev = serdev;
+
+ init_completion(&st->buf_ready);
+
+ ret = devm_regulator_get_enable(dev, "vin");
+ if (ret)
+ return ret;
+
+ indio_dev->name = "mh-z19b";
+ indio_dev->channels = mhz19b_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mhz19b_channels);
+ indio_dev->info = &mhz19b_info;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mhz19b_of_match[] = {
+ { .compatible = "winsen,mhz19b", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mhz19b_of_match);
+
+static struct serdev_device_driver mhz19b_driver = {
+ .driver = {
+ .name = "mhz19b",
+ .of_match_table = mhz19b_of_match,
+ },
+ .probe = mhz19b_probe,
+};
+module_serdev_device_driver(mhz19b_driver);
+
+MODULE_AUTHOR("Gyeyoung Baek");
+MODULE_DESCRIPTION("MH-Z19B CO2 sensor driver using serdev interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c
index e05ce1f12065..656d4a12c58f 100644
--- a/drivers/iio/chemical/pms7003.c
+++ b/drivers/iio/chemical/pms7003.c
@@ -127,8 +127,8 @@ static irqreturn_t pms7003_trigger_handler(int irq, void *p)
pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
mutex_unlock(&state->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, &state->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &state->scan, sizeof(state->scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c
index 3fed6b63710f..8316720b1fa3 100644
--- a/drivers/iio/chemical/scd30_core.c
+++ b/drivers/iio/chemical/scd30_core.c
@@ -601,7 +601,8 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p)
if (ret)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/chemical/scd4x.c b/drivers/iio/chemical/scd4x.c
index 50e3ac44422b..2463149519b6 100644
--- a/drivers/iio/chemical/scd4x.c
+++ b/drivers/iio/chemical/scd4x.c
@@ -358,15 +358,14 @@ static int scd4x_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&state->lock);
ret = scd4x_read_channel(state, chan->address);
mutex_unlock(&state->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -676,7 +675,8 @@ static irqreturn_t scd4x_trigger_handler(int irq, void *p)
if (ret)
goto out;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/chemical/sen0322.c b/drivers/iio/chemical/sen0322.c
new file mode 100644
index 000000000000..96c6fc1203ad
--- /dev/null
+++ b/drivers/iio/chemical/sen0322.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the DFRobot SEN0322 oxygen sensor.
+ *
+ * Datasheet:
+ * https://wiki.dfrobot.com/Gravity_I2C_Oxygen_Sensor_SKU_SEN0322
+ *
+ * Possible I2C slave addresses:
+ * 0x70
+ * 0x71
+ * 0x72
+ * 0x73
+ *
+ * Copyright (C) 2025 Tóth János <gomba007@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+
+#define SEN0322_REG_DATA 0x03
+#define SEN0322_REG_COEFF 0x0A
+
+struct sen0322 {
+ struct regmap *regmap;
+};
+
+static int sen0322_read_data(struct sen0322 *sen0322)
+{
+ u8 data[3] = { };
+ int ret;
+
+ ret = regmap_bulk_read(sen0322->regmap, SEN0322_REG_DATA, data,
+ sizeof(data));
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The actual value in the registers is:
+ * val = data[0] + data[1] / 10 + data[2] / 100
+ * but it is multiplied by 100 here to avoid floating-point math
+ * and the scale is divided by 100 to compensate this.
+ */
+ return data[0] * 100 + data[1] * 10 + data[2];
+}
+
+static int sen0322_read_scale(struct sen0322 *sen0322, int *num, int *den)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(sen0322->regmap, SEN0322_REG_COEFF, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val) {
+ *num = val;
+ *den = 100000; /* Coeff is scaled by 1000 at calibration. */
+ } else { /* The device is not calibrated, using the factory-defaults. */
+ *num = 209; /* Oxygen content in the atmosphere is 20.9%. */
+ *den = 120000; /* Output of the sensor at 20.9% is 120 uA. */
+ }
+
+ dev_dbg(regmap_get_device(sen0322->regmap), "scale: %d/%d\n",
+ *num, *den);
+
+ return 0;
+}
+
+static int sen0322_read_raw(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct sen0322 *sen0322 = iio_priv(iio_dev);
+ int ret;
+
+ if (chan->type != IIO_CONCENTRATION)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = sen0322_read_data(sen0322);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = sen0322_read_scale(sen0322, val, val2);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_FRACTIONAL;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info sen0322_info = {
+ .read_raw = sen0322_read_raw,
+};
+
+static const struct regmap_config sen0322_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct iio_chan_spec sen0322_channel = {
+ .type = IIO_CONCENTRATION,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int sen0322_probe(struct i2c_client *client)
+{
+ struct sen0322 *sen0322;
+ struct iio_dev *iio_dev;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*sen0322));
+ if (!iio_dev)
+ return -ENOMEM;
+
+ sen0322 = iio_priv(iio_dev);
+
+ sen0322->regmap = devm_regmap_init_i2c(client, &sen0322_regmap_conf);
+ if (IS_ERR(sen0322->regmap))
+ return PTR_ERR(sen0322->regmap);
+
+ iio_dev->info = &sen0322_info;
+ iio_dev->name = "sen0322";
+ iio_dev->channels = &sen0322_channel;
+ iio_dev->num_channels = 1;
+ iio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(&client->dev, iio_dev);
+}
+
+static const struct of_device_id sen0322_of_match[] = {
+ { .compatible = "dfrobot,sen0322" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sen0322_of_match);
+
+static struct i2c_driver sen0322_driver = {
+ .driver = {
+ .name = "sen0322",
+ .of_match_table = sen0322_of_match,
+ },
+ .probe = sen0322_probe,
+};
+module_i2c_driver(sen0322_driver);
+
+MODULE_AUTHOR("Tóth János <gomba007@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SEN0322 oxygen sensor driver");
diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c
index a7888146188d..a934bf0298dd 100644
--- a/drivers/iio/chemical/sps30.c
+++ b/drivers/iio/chemical/sps30.c
@@ -117,8 +117,8 @@ static irqreturn_t sps30_trigger_handler(int irq, void *p)
if (ret)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c
index cdb8696a4e81..af79efde37e8 100644
--- a/drivers/iio/chemical/sunrise_co2.c
+++ b/drivers/iio/chemical/sunrise_co2.c
@@ -373,7 +373,7 @@ static const struct iio_chan_spec_ext_info sunrise_concentration_ext_info[] = {
.read = iio_enum_available_read,
.private = (uintptr_t)&sunrise_error_statuses_enum,
},
- {}
+ { }
};
static const struct iio_chan_spec sunrise_channels[] = {
@@ -519,7 +519,7 @@ static int sunrise_probe(struct i2c_client *client)
static const struct of_device_id sunrise_of_match[] = {
{ .compatible = "senseair,sunrise-006-0-0007" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, sunrise_of_match);
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
index 119acb078af3..2d3d148b4206 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c
@@ -121,7 +121,7 @@ static const struct platform_device_id cros_ec_lid_angle_ids[] = {
{
.name = DRV_NAME,
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids);
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
index 66153b1850f1..82cef4a12442 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
@@ -311,7 +311,7 @@ static const struct platform_device_id cros_ec_sensors_ids[] = {
{
.name = "cros-ec-mag",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
index 7751d6f69b12..700ebcd68ff4 100644
--- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
+++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
@@ -34,25 +34,19 @@
static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev,
u16 cmd_offset, u16 cmd, u32 *mask)
{
+ DEFINE_RAW_FLEX(struct cros_ec_command, buf, data,
+ MAX(sizeof(struct ec_response_get_cmd_versions),
+ sizeof(struct ec_params_get_cmd_versions)));
int ret;
- struct {
- struct cros_ec_command msg;
- union {
- struct ec_params_get_cmd_versions params;
- struct ec_response_get_cmd_versions resp;
- };
- } __packed buf = {
- .msg = {
- .command = EC_CMD_GET_CMD_VERSIONS + cmd_offset,
- .insize = sizeof(struct ec_response_get_cmd_versions),
- .outsize = sizeof(struct ec_params_get_cmd_versions)
- },
- .params = {.cmd = cmd}
- };
-
- ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
+
+ buf->command = EC_CMD_GET_CMD_VERSIONS + cmd_offset;
+ buf->insize = sizeof(struct ec_response_get_cmd_versions);
+ buf->outsize = sizeof(struct ec_params_get_cmd_versions);
+ ((struct ec_params_get_cmd_versions *)buf->data)->cmd = cmd;
+
+ ret = cros_ec_cmd_xfer_status(ec_dev, buf);
if (ret >= 0)
- *mask = buf.resp.version_mask;
+ *mask = ((struct ec_response_get_cmd_versions *)buf->data)->version_mask;
return ret;
}
@@ -97,22 +91,6 @@ static void get_default_min_max_freq(enum motionsensor_type type,
}
}
-static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st,
- int rate)
-{
- int ret;
-
- if (rate > U16_MAX)
- rate = U16_MAX;
-
- mutex_lock(&st->cmd_lock);
- st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
- st->param.ec_rate.data = rate;
- ret = cros_ec_motion_send_host_cmd(st, 0);
- mutex_unlock(&st->cmd_lock);
- return ret;
-}
-
static ssize_t cros_ec_sensor_set_report_latency(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
@@ -128,7 +106,25 @@ static ssize_t cros_ec_sensor_set_report_latency(struct device *dev,
/* EC rate is in ms. */
latency = integer * 1000 + fract / 1000;
- ret = cros_ec_sensor_set_ec_rate(st, latency);
+
+ mutex_lock(&st->cmd_lock);
+ st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
+ st->param.ec_rate.data = min(U16_MAX, latency);
+ ret = cros_ec_motion_send_host_cmd(st, 0);
+ if (ret < 0) {
+ mutex_unlock(&st->cmd_lock);
+ return ret;
+ }
+
+ /*
+ * Flush samples currently in the FIFO, especially when the new latency
+ * is shorter than the old one: new timeout value is only considered when
+ * there is a new sample available. It can take a while for a slow
+ * sensor.
+ */
+ st->param.cmd = MOTIONSENSE_CMD_FIFO_FLUSH;
+ ret = cros_ec_motion_send_host_cmd(st, 0);
+ mutex_unlock(&st->cmd_lock);
if (ret < 0)
return ret;
@@ -486,7 +482,7 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = {
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_sensors_id
},
- { },
+ { }
};
EXPORT_SYMBOL_GPL(cros_ec_sensors_ext_info);
@@ -838,6 +834,18 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
st->param.sensor_odr.roundup = 1;
ret = cros_ec_motion_send_host_cmd(st, 0);
+ if (ret)
+ break;
+
+ /* Flush the FIFO when a sensor is stopped.
+ * If the FIFO has just been emptied, pending samples will be
+ * stuck until new samples are available. It will not happen
+ * when all the sensors are stopped.
+ */
+ if (frequency == 0) {
+ st->param.cmd = MOTIONSENSE_CMD_FIFO_FLUSH;
+ ret = cros_ec_motion_send_host_cmd(st, 0);
+ }
break;
default:
ret = -EINVAL;
diff --git a/drivers/iio/common/scmi_sensors/scmi_iio.c b/drivers/iio/common/scmi_sensors/scmi_iio.c
index ed15dcbf4cf6..da516c46e057 100644
--- a/drivers/iio/common/scmi_sensors/scmi_iio.c
+++ b/drivers/iio/common/scmi_sensors/scmi_iio.c
@@ -351,12 +351,11 @@ static int scmi_iio_read_raw(struct iio_dev *iio_dev,
ret = scmi_iio_get_odr_val(iio_dev, val, val2);
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
ret = scmi_iio_read_channel_data(iio_dev, ch, val, val2);
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return ret;
default:
return -EINVAL;
@@ -418,7 +417,7 @@ static const struct iio_chan_spec_ext_info scmi_iio_ext_info[] = {
.read = scmi_iio_get_raw_available,
.shared = IIO_SHARED_BY_TYPE,
},
- {},
+ { }
};
static void scmi_iio_set_timestamp_channel(struct iio_chan_spec *iio_chan,
@@ -705,7 +704,7 @@ static int scmi_iio_dev_probe(struct scmi_device *sdev)
static const struct scmi_device_id scmi_id_table[] = {
{ SCMI_PROTOCOL_SENSOR, "iiodev" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c
index 22ea10eb48ae..7c488672936f 100644
--- a/drivers/iio/common/ssp_sensors/ssp_dev.c
+++ b/drivers/iio/common/ssp_sensors/ssp_dev.c
@@ -434,7 +434,7 @@ static const struct of_device_id ssp_of_match[] = {
.compatible = "samsung,sensorhub-thermostat",
.data = &ssp_thermostat_info,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ssp_of_match);
diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c
index f32b04b63ea1..b7f093d7345b 100644
--- a/drivers/iio/common/ssp_sensors/ssp_spi.c
+++ b/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -104,7 +104,7 @@ static struct ssp_msg *ssp_create_msg(u8 cmd, u16 len, u16 opt, u32 data)
/*
* It is a bit heavy to do it this way but often the function is used to compose
* the message from smaller chunks which are placed on the stack. Often the
- * chunks are small so memcpy should be optimalized.
+ * chunks are small so memcpy should be optimized.
*/
static inline void ssp_fill_buffer(struct ssp_msg *m, unsigned int offset,
const void *src, unsigned int len)
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index e4f5a7ff7e74..8ce1dccfea4f 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -530,9 +530,8 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
int err;
struct st_sensor_data *sdata = iio_priv(indio_dev);
- err = iio_device_claim_direct_mode(indio_dev);
- if (err)
- return err;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&sdata->odr_lock);
@@ -551,7 +550,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
out:
mutex_unlock(&sdata->odr_lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return err;
}
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 4811ea973125..e0996dc014a3 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -6,6 +6,17 @@
menu "Digital to analog converters"
+config AD3530R
+ tristate "Analog Devices AD3530R and Similar DACs driver"
+ depends on SPI
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Analog Devices AD3530R, AD3531R
+ Digital to Analog Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad3530r.
+
config AD3552R_HS
tristate "Analog Devices AD3552R DAC High Speed driver"
select AD3552R_LIB
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 8dd6cce81ed1..3684cd52b7fa 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -4,6 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AD3530R) += ad3530r.o
obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o
obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o
obj-$(CONFIG_AD3552R) += ad3552r.o
diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
new file mode 100644
index 000000000000..f9752a571aa5
--- /dev/null
+++ b/drivers/iio/dac/ad3530r.c
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver
+ * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/kstrtox.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#define AD3530R_INTERFACE_CONFIG_A 0x00
+#define AD3530R_OUTPUT_OPERATING_MODE_0 0x20
+#define AD3530R_OUTPUT_OPERATING_MODE_1 0x21
+#define AD3530R_OUTPUT_CONTROL_0 0x2A
+#define AD3530R_REFERENCE_CONTROL_0 0x3C
+#define AD3530R_SW_LDAC_TRIG_A 0xE5
+#define AD3530R_INPUT_CH 0xEB
+#define AD3530R_MAX_REG_ADDR 0xF9
+
+#define AD3531R_SW_LDAC_TRIG_A 0xDD
+#define AD3531R_INPUT_CH 0xE3
+
+#define AD3530R_SLD_TRIG_A BIT(7)
+#define AD3530R_OUTPUT_CONTROL_RANGE BIT(2)
+#define AD3530R_REFERENCE_CONTROL_SEL BIT(0)
+#define AD3530R_REG_VAL_MASK GENMASK(15, 0)
+#define AD3530R_OP_MODE_CHAN_MSK(chan) (GENMASK(1, 0) << 2 * (chan))
+
+#define AD3530R_SW_RESET (BIT(7) | BIT(0))
+#define AD3530R_INTERNAL_VREF_mV 2500
+#define AD3530R_LDAC_PULSE_US 100
+
+#define AD3530R_DAC_MAX_VAL GENMASK(15, 0)
+#define AD3530R_MAX_CHANNELS 8
+#define AD3531R_MAX_CHANNELS 4
+
+/* Non-constant mask variant of FIELD_PREP() */
+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
+
+enum ad3530r_mode {
+ AD3530R_NORMAL_OP,
+ AD3530R_POWERDOWN_1K,
+ AD3530R_POWERDOWN_7K7,
+ AD3530R_POWERDOWN_32K,
+};
+
+struct ad3530r_chan {
+ enum ad3530r_mode powerdown_mode;
+ bool powerdown;
+};
+
+struct ad3530r_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ int (*input_ch_reg)(unsigned int channel);
+ unsigned int num_channels;
+ unsigned int sw_ldac_trig_reg;
+ bool internal_ref_support;
+};
+
+struct ad3530r_state {
+ struct regmap *regmap;
+ /* lock to protect against multiple access to the device and shared data */
+ struct mutex lock;
+ struct ad3530r_chan chan[AD3530R_MAX_CHANNELS];
+ const struct ad3530r_chip_info *chip_info;
+ struct gpio_desc *ldac_gpio;
+ int vref_mV;
+ /*
+ * DMA (thus cache coherency maintenance) may require the transfer
+ * buffers to live in their own cache lines.
+ */
+ __be16 buf __aligned(IIO_DMA_MINALIGN);
+};
+
+static int ad3530r_input_ch_reg(unsigned int channel)
+{
+ return 2 * channel + AD3530R_INPUT_CH;
+}
+
+static int ad3531r_input_ch_reg(unsigned int channel)
+{
+ return 2 * channel + AD3531R_INPUT_CH;
+}
+
+static const char * const ad3530r_powerdown_modes[] = {
+ "1kohm_to_gnd",
+ "7.7kohm_to_gnd",
+ "32kohm_to_gnd",
+};
+
+static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+ return st->chan[chan->channel].powerdown_mode - 1;
+}
+
+static int ad3530r_set_powerdown_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+ st->chan[chan->channel].powerdown_mode = mode + 1;
+
+ return 0;
+}
+
+static const struct iio_enum ad3530r_powerdown_mode_enum = {
+ .items = ad3530r_powerdown_modes,
+ .num_items = ARRAY_SIZE(ad3530r_powerdown_modes),
+ .get = ad3530r_get_powerdown_mode,
+ .set = ad3530r_set_powerdown_mode,
+};
+
+static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+
+ guard(mutex)(&st->lock);
+ return sysfs_emit(buf, "%d\n", st->chan[chan->channel].powerdown);
+}
+
+static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+ int ret;
+ unsigned int reg, pdmode, mask, val;
+ bool powerdown;
+
+ ret = kstrtobool(buf, &powerdown);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&st->lock);
+ reg = chan->channel < AD3531R_MAX_CHANNELS ?
+ AD3530R_OUTPUT_OPERATING_MODE_0 :
+ AD3530R_OUTPUT_OPERATING_MODE_1;
+ pdmode = powerdown ? st->chan[chan->channel].powerdown_mode : 0;
+ mask = AD3530R_OP_MODE_CHAN_MSK(chan->channel);
+ val = field_prep(mask, pdmode);
+
+ ret = regmap_update_bits(st->regmap, reg, mask, val);
+ if (ret)
+ return ret;
+
+ st->chan[chan->channel].powerdown = powerdown;
+
+ return len;
+}
+
+static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
+{
+ gpiod_set_value_cansleep(ldac_gpio, 1);
+ fsleep(AD3530R_LDAC_PULSE_US);
+ gpiod_set_value_cansleep(ldac_gpio, 0);
+
+ return 0;
+}
+
+static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan,
+ unsigned int val)
+{
+ int ret;
+
+ guard(mutex)(&st->lock);
+ st->buf = cpu_to_be16(val);
+
+ ret = regmap_bulk_write(st->regmap, st->chip_info->input_ch_reg(chan),
+ &st->buf, sizeof(st->buf));
+ if (ret)
+ return ret;
+
+ if (st->ldac_gpio)
+ return ad3530r_trigger_hw_ldac(st->ldac_gpio);
+
+ return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg,
+ AD3530R_SLD_TRIG_A);
+}
+
+static int ad3530r_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ ret = regmap_bulk_read(st->regmap,
+ st->chip_info->input_ch_reg(chan->channel),
+ &st->buf, sizeof(st->buf));
+ if (ret)
+ return ret;
+
+ *val = FIELD_GET(AD3530R_REG_VAL_MASK, be16_to_cpu(st->buf));
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->vref_mV;
+ *val2 = 16;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad3530r_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (val < 0 || val > AD3530R_DAC_MAX_VAL)
+ return -EINVAL;
+
+ return ad3530r_dac_write(st, chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad3530r_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad3530r_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_chan_spec_ext_info ad3530r_ext_info[] = {
+ {
+ .name = "powerdown",
+ .shared = IIO_SEPARATE,
+ .read = ad3530r_get_dac_powerdown,
+ .write = ad3530r_set_dac_powerdown,
+ },
+ IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3530r_powerdown_mode_enum),
+ IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+ &ad3530r_powerdown_mode_enum),
+ { }
+};
+
+#define AD3530R_CHAN(_chan) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .output = 1, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .ext_info = ad3530r_ext_info, \
+}
+
+static const struct iio_chan_spec ad3530r_channels[] = {
+ AD3530R_CHAN(0),
+ AD3530R_CHAN(1),
+ AD3530R_CHAN(2),
+ AD3530R_CHAN(3),
+ AD3530R_CHAN(4),
+ AD3530R_CHAN(5),
+ AD3530R_CHAN(6),
+ AD3530R_CHAN(7),
+};
+
+static const struct iio_chan_spec ad3531r_channels[] = {
+ AD3530R_CHAN(0),
+ AD3530R_CHAN(1),
+ AD3530R_CHAN(2),
+ AD3530R_CHAN(3),
+};
+
+static const struct ad3530r_chip_info ad3530_chip = {
+ .name = "ad3530",
+ .channels = ad3530r_channels,
+ .num_channels = ARRAY_SIZE(ad3530r_channels),
+ .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .input_ch_reg = ad3530r_input_ch_reg,
+ .internal_ref_support = false,
+};
+
+static const struct ad3530r_chip_info ad3530r_chip = {
+ .name = "ad3530r",
+ .channels = ad3530r_channels,
+ .num_channels = ARRAY_SIZE(ad3530r_channels),
+ .sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+ .input_ch_reg = ad3530r_input_ch_reg,
+ .internal_ref_support = true,
+};
+
+static const struct ad3530r_chip_info ad3531_chip = {
+ .name = "ad3531",
+ .channels = ad3531r_channels,
+ .num_channels = ARRAY_SIZE(ad3531r_channels),
+ .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .input_ch_reg = ad3531r_input_ch_reg,
+ .internal_ref_support = false,
+};
+
+static const struct ad3530r_chip_info ad3531r_chip = {
+ .name = "ad3531r",
+ .channels = ad3531r_channels,
+ .num_channels = ARRAY_SIZE(ad3531r_channels),
+ .sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+ .input_ch_reg = ad3531r_input_ch_reg,
+ .internal_ref_support = true,
+};
+
+static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ struct gpio_desc *reset_gpio;
+ int i, ret;
+ u8 range_multiplier, val;
+
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ "Failed to get reset GPIO\n");
+
+ if (reset_gpio) {
+ /* Perform hardware reset */
+ fsleep(1 * USEC_PER_MSEC);
+ gpiod_set_value_cansleep(reset_gpio, 0);
+ } else {
+ /* Perform software reset */
+ ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A,
+ AD3530R_SW_RESET, AD3530R_SW_RESET);
+ if (ret)
+ return ret;
+ }
+
+ fsleep(10 * USEC_PER_MSEC);
+
+ range_multiplier = 1;
+ if (device_property_read_bool(dev, "adi,range-double")) {
+ ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0,
+ AD3530R_OUTPUT_CONTROL_RANGE);
+ if (ret)
+ return ret;
+
+ range_multiplier = 2;
+ }
+
+ if (external_vref_uV) {
+ st->vref_mV = range_multiplier * external_vref_uV / MILLI;
+ } else {
+ ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0,
+ AD3530R_REFERENCE_CONTROL_SEL);
+ if (ret)
+ return ret;
+
+ st->vref_mV = range_multiplier * AD3530R_INTERNAL_VREF_mV;
+ }
+
+ /* Set normal operating mode for all channels */
+ val = FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(0), AD3530R_NORMAL_OP) |
+ FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(1), AD3530R_NORMAL_OP) |
+ FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) |
+ FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP);
+
+ ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val);
+ if (ret)
+ return ret;
+
+ if (st->chip_info->num_channels > 4) {
+ ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1,
+ val);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < st->chip_info->num_channels; i++)
+ st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K;
+
+ st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW);
+ if (IS_ERR(st->ldac_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->ldac_gpio),
+ "Failed to get ldac GPIO\n");
+
+ return 0;
+}
+
+static const struct regmap_config ad3530r_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = AD3530R_MAX_REG_ADDR,
+};
+
+static const struct iio_info ad3530r_info = {
+ .read_raw = ad3530r_read_raw,
+ .write_raw = ad3530r_write_raw,
+ .debugfs_reg_access = ad3530r_reg_access,
+};
+
+static int ad3530r_probe(struct spi_device *spi)
+{
+ static const char * const regulators[] = { "vdd", "iovdd" };
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad3530r_state *st;
+ int ret, external_vref_uV;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "Failed to init regmap");
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ st->chip_info = spi_get_device_match_data(spi);
+ if (!st->chip_info)
+ return -ENODEV;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+ regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ external_vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref");
+ if (external_vref_uV < 0 && external_vref_uV != -ENODEV)
+ return external_vref_uV;
+
+ if (external_vref_uV == -ENODEV)
+ external_vref_uV = 0;
+
+ if (!st->chip_info->internal_ref_support && external_vref_uV == 0)
+ return -ENODEV;
+
+ ret = ad3530r_setup(st, external_vref_uV);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->chip_info->name;
+ indio_dev->info = &ad3530r_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = st->chip_info->channels;
+ indio_dev->num_channels = st->chip_info->num_channels;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ad3530r_id[] = {
+ { "ad3530", (kernel_ulong_t)&ad3530_chip },
+ { "ad3530r", (kernel_ulong_t)&ad3530r_chip },
+ { "ad3531", (kernel_ulong_t)&ad3531_chip },
+ { "ad3531r", (kernel_ulong_t)&ad3531r_chip },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad3530r_id);
+
+static const struct of_device_id ad3530r_of_match[] = {
+ { .compatible = "adi,ad3530", .data = &ad3530_chip },
+ { .compatible = "adi,ad3530r", .data = &ad3530r_chip },
+ { .compatible = "adi,ad3531", .data = &ad3531_chip },
+ { .compatible = "adi,ad3531r", .data = &ad3531r_chip },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad3530r_of_match);
+
+static struct spi_driver ad3530r_driver = {
+ .driver = {
+ .name = "ad3530r",
+ .of_match_table = ad3530r_of_match,
+ },
+ .probe = ad3530r_probe,
+ .id_table = ad3530r_id,
+};
+module_spi_driver(ad3530r_driver);
+
+MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD3530R and Similar DACs Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
index b8807e54fa05..38baaea0e6c8 100644
--- a/drivers/iio/dac/ad3552r-common.c
+++ b/drivers/iio/dac/ad3552r-common.c
@@ -43,6 +43,7 @@ const struct ad3552r_model_data ad3541r_model_data = {
.num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
.requires_output_range = true,
.num_spi_data_lanes = 2,
+ .max_reg_addr = 0x46,
};
EXPORT_SYMBOL_NS_GPL(ad3541r_model_data, "IIO_AD3552R");
@@ -54,6 +55,7 @@ const struct ad3552r_model_data ad3542r_model_data = {
.num_ranges = ARRAY_SIZE(ad3542r_ch_ranges),
.requires_output_range = true,
.num_spi_data_lanes = 2,
+ .max_reg_addr = 0x49,
};
EXPORT_SYMBOL_NS_GPL(ad3542r_model_data, "IIO_AD3552R");
@@ -65,6 +67,7 @@ const struct ad3552r_model_data ad3551r_model_data = {
.num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
.requires_output_range = false,
.num_spi_data_lanes = 4,
+ .max_reg_addr = 0x46,
};
EXPORT_SYMBOL_NS_GPL(ad3551r_model_data, "IIO_AD3552R");
@@ -76,6 +79,7 @@ const struct ad3552r_model_data ad3552r_model_data = {
.num_ranges = ARRAY_SIZE(ad3552r_ch_ranges),
.requires_output_range = false,
.num_spi_data_lanes = 4,
+ .max_reg_addr = 0x49,
};
EXPORT_SYMBOL_NS_GPL(ad3552r_model_data, "IIO_AD3552R");
diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c
index cd8dabb60c55..41b96b48ba98 100644
--- a/drivers/iio/dac/ad3552r-hs.c
+++ b/drivers/iio/dac/ad3552r-hs.c
@@ -7,6 +7,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/backend.h>
@@ -54,6 +55,18 @@ struct ad3552r_hs_state {
struct ad3552r_hs_platform_data *data;
/* INTERFACE_CONFIG_D register cache, in DDR we cannot read values. */
u32 config_d;
+ /* Protects backend I/O operations from concurrent accesses. */
+ struct mutex lock;
+};
+
+enum ad3552r_sources {
+ AD3552R_SRC_NORMAL,
+ AD3552R_SRC_RAMP_16BIT,
+};
+
+static const char * const dbgfs_attr_source[] = {
+ [AD3552R_SRC_NORMAL] = "normal",
+ [AD3552R_SRC_RAMP_16BIT] = "ramp-16bit",
};
static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val,
@@ -65,6 +78,20 @@ static int ad3552r_hs_reg_read(struct ad3552r_hs_state *st, u32 reg, u32 *val,
return st->data->bus_reg_read(st->back, reg, val, xfer_size);
}
+static int ad3552r_hs_set_data_source(struct ad3552r_hs_state *st,
+ enum iio_backend_data_source type)
+{
+ int i, ret;
+
+ for (i = 0; i < st->model_data->num_hw_channels; ++i) {
+ ret = iio_backend_data_source_set(st->back, i, type);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ad3552r_hs_update_reg_bits(struct ad3552r_hs_state *st, u32 reg,
u32 mask, u32 val, size_t xfer_size)
{
@@ -464,6 +491,122 @@ static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st,
gain, 1);
}
+static int ad3552r_hs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+
+ if (reg > st->model_data->max_reg_addr)
+ return -EINVAL;
+
+ /*
+ * There are 8, 16 or 24 bit registers, but HDL supports only reading 8
+ * or 16 bit data, not 24. So, also to avoid to check any proper read
+ * alignment, supporting only 8-bit readings here.
+ */
+ if (readval)
+ return ad3552r_hs_reg_read(st, reg, readval, 1);
+
+ return st->data->bus_reg_write(st->back, reg, writeval, 1);
+}
+
+static ssize_t ad3552r_hs_show_data_source(struct file *f, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ad3552r_hs_state *st = file_inode(f)->i_private;
+ enum iio_backend_data_source type;
+ int idx, ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = iio_backend_data_source_get(st->back, 0, &type);
+ if (ret)
+ return ret;
+
+ switch (type) {
+ case IIO_BACKEND_INTERNAL_RAMP_16BIT:
+ idx = AD3552R_SRC_RAMP_16BIT;
+ break;
+ case IIO_BACKEND_EXTERNAL:
+ idx = AD3552R_SRC_NORMAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ dbgfs_attr_source[idx],
+ strlen(dbgfs_attr_source[idx]));
+}
+
+static ssize_t ad3552r_hs_write_data_source(struct file *f,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ad3552r_hs_state *st = file_inode(f)->i_private;
+ char buf[64];
+ int ret, source;
+
+ guard(mutex)(&st->lock);
+
+ ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf,
+ count);
+ if (ret < 0)
+ return ret;
+
+ buf[count] = '\0';
+
+ ret = match_string(dbgfs_attr_source, ARRAY_SIZE(dbgfs_attr_source),
+ buf);
+ if (ret < 0)
+ return ret;
+
+ switch (ret) {
+ case AD3552R_SRC_RAMP_16BIT:
+ source = IIO_BACKEND_INTERNAL_RAMP_16BIT;
+ break;
+ case AD3552R_SRC_NORMAL:
+ source = IIO_BACKEND_EXTERNAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = ad3552r_hs_set_data_source(st, source);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t ad3552r_hs_show_data_source_avail(struct file *f,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t len = 0;
+ char buf[128];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dbgfs_attr_source); i++) {
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
+ dbgfs_attr_source[i]);
+ }
+ buf[len - 1] = '\n';
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations ad3552r_hs_data_source_fops = {
+ .owner = THIS_MODULE,
+ .write = ad3552r_hs_write_data_source,
+ .read = ad3552r_hs_show_data_source,
+};
+
+static const struct file_operations ad3552r_hs_data_source_avail_fops = {
+ .owner = THIS_MODULE,
+ .read = ad3552r_hs_show_data_source_avail,
+};
+
static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
{
u16 id;
@@ -531,11 +674,7 @@ static int ad3552r_hs_setup(struct ad3552r_hs_state *st)
if (ret)
return ret;
- ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL);
- if (ret)
- return ret;
-
- ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL);
+ ret = ad3552r_hs_set_data_source(st, IIO_BACKEND_EXTERNAL);
if (ret)
return ret;
@@ -639,8 +778,29 @@ static const struct iio_chan_spec ad3552r_hs_channels[] = {
static const struct iio_info ad3552r_hs_info = {
.read_raw = &ad3552r_hs_read_raw,
.write_raw = &ad3552r_hs_write_raw,
+ .debugfs_reg_access = &ad3552r_hs_reg_access,
};
+static void ad3552r_hs_debugfs_init(struct iio_dev *indio_dev)
+{
+ struct ad3552r_hs_state *st = iio_priv(indio_dev);
+ struct dentry *d = iio_get_debugfs_dentry(indio_dev);
+
+ if (!IS_ENABLED(CONFIG_DEBUG_FS))
+ return;
+
+ d = iio_get_debugfs_dentry(indio_dev);
+ if (!d) {
+ dev_warn(st->dev, "can't set debugfs in driver dir\n");
+ return;
+ }
+
+ debugfs_create_file("data_source", 0600, d, st,
+ &ad3552r_hs_data_source_fops);
+ debugfs_create_file("data_source_available", 0600, d, st,
+ &ad3552r_hs_data_source_avail_fops);
+}
+
static int ad3552r_hs_probe(struct platform_device *pdev)
{
struct ad3552r_hs_state *st;
@@ -685,7 +845,17 @@ static int ad3552r_hs_probe(struct platform_device *pdev)
if (ret)
return ret;
- return devm_iio_device_register(&pdev->dev, indio_dev);
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_mutex_init(&pdev->dev, &st->lock);
+ if (ret)
+ return ret;
+
+ ad3552r_hs_debugfs_init(indio_dev);
+
+ return ret;
}
static const struct of_device_id ad3552r_hs_of_id[] = {
diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
index 768fa264d39e..9bb46a9e07a5 100644
--- a/drivers/iio/dac/ad3552r.h
+++ b/drivers/iio/dac/ad3552r.h
@@ -156,6 +156,7 @@ struct ad3552r_model_data {
int num_ranges;
bool requires_output_range;
int num_spi_data_lanes;
+ int max_reg_addr;
};
struct ad3552r_ch_data {
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index 905988724f27..84be5174babd 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -378,7 +378,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5064_powerdown_mode_enum),
- { },
+ { }
};
static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = {
@@ -390,7 +390,7 @@ static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ltc2617_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ltc2617_powerdown_mode_enum),
- { },
+ { }
};
#define AD5064_CHANNEL(chan, addr, bits, _shift, _ext_info) { \
@@ -936,7 +936,7 @@ static const struct spi_device_id ad5064_spi_ids[] = {
{"ad5668-1", ID_AD5668_1},
{"ad5668-2", ID_AD5668_2},
{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5064_spi_ids);
@@ -1048,7 +1048,7 @@ static const struct i2c_device_id ad5064_i2c_ids[] = {
{"ltc2635-h10", ID_LTC2635_H10},
{"ltc2635-l8", ID_LTC2635_L8},
{"ltc2635-h8", ID_LTC2635_H8},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index e0b7f658d611..a57b0a093112 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -542,7 +542,7 @@ static const struct spi_device_id ad5360_ids[] = {
{ "ad5371", ID_AD5371 },
{ "ad5372", ID_AD5372 },
{ "ad5373", ID_AD5373 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5360_ids);
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index 392a1c7aee03..f63af704b77e 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -246,7 +246,7 @@ static const struct iio_chan_spec_ext_info ad5380_ext_info[] = {
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5380_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5380_powerdown_mode_enum),
- { },
+ { }
};
#define AD5380_CHANNEL(_bits) { \
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index 6ad99f97eed5..ad304b0fec08 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -141,7 +141,7 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5446_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5446_powerdown_mode_enum),
- { },
+ { }
};
#define _AD5446_CHANNEL(bits, storage, _shift, ext) { \
@@ -440,7 +440,7 @@ static const struct spi_device_id ad5446_spi_ids[] = {
{"dac101s101", ID_AD5310},
{"dac121s101", ID_AD5320},
{"dac7512", ID_AD5320},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
@@ -543,7 +543,7 @@ static const struct i2c_device_id ad5446_i2c_ids[] = {
{"ad5602", ID_AD5602},
{"ad5612", ID_AD5612},
{"ad5622", ID_AD5622},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids);
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
index 1c996016756a..d8c325260259 100644
--- a/drivers/iio/dac/ad5449.c
+++ b/drivers/iio/dac/ad5449.c
@@ -337,7 +337,7 @@ static const struct spi_device_id ad5449_spi_ids[] = {
{ "ad5439", ID_AD5439 },
{ "ad5443", ID_AD5443 },
{ "ad5449", ID_AD5449 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5449_spi_ids);
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index ff0765c8af47..355bcb6a8ba0 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -242,7 +242,7 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5504_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5504_powerdown_mode_enum),
- { },
+ { }
};
#define AD5504_CHANNEL(_chan) { \
@@ -320,7 +320,7 @@ static int ad5504_probe(struct spi_device *spi)
static const struct spi_device_id ad5504_id[] = {
{"ad5504", ID_AD5504},
{"ad5501", ID_AD5501},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5504_id);
diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c
index 50d19304bacb..5f2cd51723f6 100644
--- a/drivers/iio/dac/ad5592r-base.c
+++ b/drivers/iio/dac/ad5592r-base.c
@@ -7,6 +7,7 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
@@ -24,16 +25,14 @@ static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret = 0;
- u8 val;
+ u8 val = 0;
- mutex_lock(&st->gpio_lock);
-
- if (st->gpio_out & BIT(offset))
- val = st->gpio_val;
- else
- ret = st->ops->gpio_read(st, &val);
-
- mutex_unlock(&st->gpio_lock);
+ scoped_guard(mutex, &st->gpio_lock) {
+ if (st->gpio_out & BIT(offset))
+ val = st->gpio_val;
+ else
+ ret = st->ops->gpio_read(st, &val);
+ }
if (ret < 0)
return ret;
@@ -41,20 +40,19 @@ static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset));
}
-static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int ad5592r_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
- mutex_lock(&st->gpio_lock);
+ guard(mutex)(&st->gpio_lock);
if (value)
st->gpio_val |= BIT(offset);
else
st->gpio_val &= ~BIT(offset);
- st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
-
- mutex_unlock(&st->gpio_lock);
+ return st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
}
static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -62,21 +60,16 @@ static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret;
- mutex_lock(&st->gpio_lock);
+ guard(mutex)(&st->gpio_lock);
st->gpio_out &= ~BIT(offset);
st->gpio_in |= BIT(offset);
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret < 0)
- goto err_unlock;
-
- ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
-
-err_unlock:
- mutex_unlock(&st->gpio_lock);
+ return ret;
- return ret;
+ return st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
}
static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
@@ -85,7 +78,7 @@ static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret;
- mutex_lock(&st->gpio_lock);
+ guard(mutex)(&st->gpio_lock);
if (value)
st->gpio_val |= BIT(offset);
@@ -97,18 +90,13 @@ static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
if (ret < 0)
- goto err_unlock;
+ return ret;
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret < 0)
- goto err_unlock;
-
- ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
-
-err_unlock:
- mutex_unlock(&st->gpio_lock);
+ return ret;
- return ret;
+ return st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
}
static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -141,7 +129,7 @@ static int ad5592r_gpio_init(struct ad5592r_state *st)
st->gpiochip.direction_input = ad5592r_gpio_direction_input;
st->gpiochip.direction_output = ad5592r_gpio_direction_output;
st->gpiochip.get = ad5592r_gpio_get;
- st->gpiochip.set = ad5592r_gpio_set;
+ st->gpiochip.set_rv = ad5592r_gpio_set;
st->gpiochip.request = ad5592r_gpio_request;
st->gpiochip.owner = THIS_MODULE;
st->gpiochip.names = ad5592r_gpio_names;
@@ -155,6 +143,8 @@ static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
{
if (st->gpio_map)
gpiochip_remove(&st->gpiochip);
+
+ mutex_destroy(&st->gpio_lock);
}
static int ad5592r_reset(struct ad5592r_state *st)
@@ -169,10 +159,9 @@ static int ad5592r_reset(struct ad5592r_state *st)
udelay(1);
gpiod_set_value(gpio, 1);
} else {
- mutex_lock(&st->lock);
- /* Writing this magic value resets the device */
- st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock)
+ /* Writing this magic value resets the device */
+ st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
}
udelay(250);
@@ -247,46 +236,44 @@ static int ad5592r_set_channel_modes(struct ad5592r_state *st)
}
}
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
/* Pull down unused pins to GND */
ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
if (ret)
- goto err_unlock;
+ return ret;
ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate);
if (ret)
- goto err_unlock;
+ return ret;
/* Configure pins that we use */
ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac);
if (ret)
- goto err_unlock;
+ return ret;
ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc);
if (ret)
- goto err_unlock;
+ return ret;
ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
if (ret)
- goto err_unlock;
+ return ret;
ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret)
- goto err_unlock;
+ return ret;
ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
if (ret)
- goto err_unlock;
+ return ret;
/* Verify that we can read back at least one register */
ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back);
if (!ret && (read_back & 0xff) != adc)
- ret = -EIO;
+ return -EIO;
-err_unlock:
- mutex_unlock(&st->lock);
- return ret;
+ return 0;
}
static int ad5592r_reset_channel_modes(struct ad5592r_state *st)
@@ -303,7 +290,7 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct ad5592r_state *st = iio_priv(iio_dev);
- int ret;
+ int ret = 0;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -314,11 +301,11 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
if (!chan->output)
return -EINVAL;
- mutex_lock(&st->lock);
- ret = st->ops->write_dac(st, chan->channel, val);
- if (!ret)
- st->cached_dac[chan->channel] = val;
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ ret = st->ops->write_dac(st, chan->channel, val);
+ if (!ret)
+ st->cached_dac[chan->channel] = val;
+ }
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_VOLTAGE) {
@@ -333,14 +320,12 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
else
return -EINVAL;
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
&st->cached_gp_ctrl);
- if (ret < 0) {
- mutex_unlock(&st->lock);
+ if (ret < 0)
return ret;
- }
if (chan->output) {
if (gain)
@@ -358,11 +343,8 @@ static int ad5592r_write_raw(struct iio_dev *iio_dev,
~AD5592R_REG_CTRL_ADC_RANGE;
}
- ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
- st->cached_gp_ctrl);
- mutex_unlock(&st->lock);
-
- return ret;
+ return st->ops->reg_write(st, AD5592R_REG_CTRL,
+ st->cached_gp_ctrl);
}
break;
default:
@@ -377,15 +359,15 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
int *val, int *val2, long m)
{
struct ad5592r_state *st = iio_priv(iio_dev);
- u16 read_val;
- int ret, mult;
+ u16 read_val = 0;
+ int ret = 0, mult = 0;
switch (m) {
case IIO_CHAN_INFO_RAW:
if (!chan->output) {
- mutex_lock(&st->lock);
- ret = st->ops->read_adc(st, chan->channel, &read_val);
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock)
+ ret = st->ops->read_adc(st, chan->channel,
+ &read_val);
if (ret)
return ret;
@@ -398,9 +380,8 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
read_val &= GENMASK(11, 0);
} else {
- mutex_lock(&st->lock);
- read_val = st->cached_dac[chan->channel];
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock)
+ read_val = st->cached_dac[chan->channel];
}
dev_dbg(st->dev, "Channel %u read: 0x%04hX\n",
@@ -418,35 +399,32 @@ static int ad5592r_read_raw(struct iio_dev *iio_dev,
return IIO_VAL_INT_PLUS_NANO;
}
- mutex_lock(&st->lock);
-
- if (chan->output)
- mult = !!(st->cached_gp_ctrl &
- AD5592R_REG_CTRL_DAC_RANGE);
- else
- mult = !!(st->cached_gp_ctrl &
- AD5592R_REG_CTRL_ADC_RANGE);
-
- mutex_unlock(&st->lock);
+ scoped_guard(mutex, &st->lock) {
+ if (chan->output)
+ mult = !!(st->cached_gp_ctrl &
+ AD5592R_REG_CTRL_DAC_RANGE);
+ else
+ mult = !!(st->cached_gp_ctrl &
+ AD5592R_REG_CTRL_ADC_RANGE);
+ }
*val *= ++mult;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
- case IIO_CHAN_INFO_OFFSET:
+ case IIO_CHAN_INFO_OFFSET: {
ret = ad5592r_get_vref(st);
- mutex_lock(&st->lock);
+ guard(mutex)(&st->lock);
if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
*val = (-34365 * 25) / ret;
else
*val = (-75365 * 25) / ret;
- mutex_unlock(&st->lock);
-
return IIO_VAL_INT;
+ }
default:
return -EINVAL;
}
@@ -490,7 +468,7 @@ static const struct iio_chan_spec_ext_info ad5592r_ext_info[] = {
.read = ad5592r_show_scale_available,
.shared = IIO_SHARED_BY_TYPE,
},
- {},
+ { }
};
static void ad5592r_setup_channel(struct iio_dev *iio_dev,
@@ -606,6 +584,10 @@ int ad5592r_probe(struct device *dev, const char *name,
st->num_channels = 8;
dev_set_drvdata(dev, iio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
st->reg = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->reg)) {
if ((PTR_ERR(st->reg) != -ENODEV) && dev_fwnode(dev))
@@ -622,8 +604,6 @@ int ad5592r_probe(struct device *dev, const char *name,
iio_dev->info = &ad5592r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
- mutex_init(&st->lock);
-
ad5592r_init_scales(st, ad5592r_get_vref(st));
ret = ad5592r_reset(st);
diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c
index fd82d8701322..92d1b629b85d 100644
--- a/drivers/iio/dac/ad5592r.c
+++ b/drivers/iio/dac/ad5592r.c
@@ -137,19 +137,19 @@ static void ad5592r_spi_remove(struct spi_device *spi)
static const struct spi_device_id ad5592r_spi_ids[] = {
{ .name = "ad5592r", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids);
static const struct of_device_id ad5592r_of_match[] = {
{ .compatible = "adi,ad5592r", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ad5592r_of_match);
static const struct acpi_device_id ad5592r_acpi_match[] = {
{"ADS5592", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ad5592r_acpi_match);
diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c
index ddd13ad821a7..9a8525c61173 100644
--- a/drivers/iio/dac/ad5593r.c
+++ b/drivers/iio/dac/ad5593r.c
@@ -116,19 +116,19 @@ static void ad5593r_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id ad5593r_i2c_ids[] = {
{ .name = "ad5593r", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids);
static const struct of_device_id ad5593r_of_match[] = {
{ .compatible = "adi,ad5593r", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ad5593r_of_match);
static const struct acpi_device_id ad5593r_acpi_match[] = {
{"ADS5593", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ad5593r_acpi_match);
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index 2fd38ac8f698..13aefe769bad 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -160,7 +160,7 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5624r_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5624r_powerdown_mode_enum),
- { },
+ { }
};
#define AD5624R_CHANNEL(_chan, _bits) { \
@@ -266,7 +266,7 @@ static const struct spi_device_id ad5624r_id[] = {
{"ad5624r5", ID_AD5624R5},
{"ad5644r5", ID_AD5644R5},
{"ad5664r5", ID_AD5664R5},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5624r_id);
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
index 9c727aa6ea18..df8619e0c092 100644
--- a/drivers/iio/dac/ad5686-spi.c
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -112,7 +112,7 @@ static const struct spi_device_id ad5686_spi_id[] = {
{"ad5685r", ID_AD5685R},
{"ad5686", ID_AD5686},
{"ad5686r", ID_AD5686R},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5686_spi_id);
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 763af690c444..d9cae9555e5d 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -185,7 +185,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5686_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5686_powerdown_mode_enum),
- { },
+ { }
};
#define AD5868_CHANNEL(chan, addr, bits, _shift) { \
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
index 0156f32c12c8..d3327bca0e07 100644
--- a/drivers/iio/dac/ad5696-i2c.c
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -82,7 +82,7 @@ static const struct i2c_device_id ad5686_i2c_id[] = {
{"ad5695r", ID_AD5695R},
{"ad5696", ID_AD5696},
{"ad5696r", ID_AD5696R},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id);
@@ -101,7 +101,7 @@ static const struct of_device_id ad5686_of_match[] = {
{ .compatible = "adi,ad5695r" },
{ .compatible = "adi,ad5696" },
{ .compatible = "adi,ad5696r" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad5686_of_match);
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 05e80b6ae2cc..d0e5f35462b1 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -522,7 +522,7 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
.write = ad5755_write_powerdown,
.shared = IIO_SEPARATE,
},
- { },
+ { }
};
#define AD5755_CHANNEL(_bits) { \
@@ -853,7 +853,7 @@ static const struct spi_device_id ad5755_id[] = {
{ "ad5757", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5757] },
{ "ad5735", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5735] },
{ "ad5737", (kernel_ulong_t)&ad5755_chip_info_tbl[ID_AD5737] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5755_id);
diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c
index 98771e37a7b5..4ed4fda76ea9 100644
--- a/drivers/iio/dac/ad5758.c
+++ b/drivers/iio/dac/ad5758.c
@@ -878,7 +878,7 @@ static int ad5758_probe(struct spi_device *spi)
static const struct spi_device_id ad5758_id[] = {
{ "ad5758", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5758_id);
diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c
index 0aa5ba7f4654..b5d20f04f070 100644
--- a/drivers/iio/dac/ad5761.c
+++ b/drivers/iio/dac/ad5761.c
@@ -137,13 +137,11 @@ static int _ad5761_spi_read(struct ad5761_state *st, u8 addr, u16 *val)
struct spi_transfer xfers[] = {
{
.tx_buf = &st->data[0].d8[1],
- .bits_per_word = 8,
.len = 3,
.cs_change = true,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[2].d8[1],
- .bits_per_word = 8,
.len = 3,
},
};
@@ -348,7 +346,7 @@ static const struct spi_device_id ad5761_id[] = {
{"ad5721r", ID_AD5721R},
{"ad5761", ID_AD5761},
{"ad5761r", ID_AD5761R},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5761_id);
diff --git a/drivers/iio/dac/ad5766.c b/drivers/iio/dac/ad5766.c
index f658ac8086aa..f6a0a0d84fef 100644
--- a/drivers/iio/dac/ad5766.c
+++ b/drivers/iio/dac/ad5766.c
@@ -148,13 +148,11 @@ static int __ad5766_spi_read(struct ad5766_state *st, u8 dac, int *val)
struct spi_transfer xfers[] = {
{
.tx_buf = &st->data[0].d32,
- .bits_per_word = 8,
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d32,
.rx_buf = &st->data[2].d32,
- .bits_per_word = 8,
.len = 3,
},
};
@@ -437,7 +435,7 @@ static const struct iio_chan_spec_ext_info ad5766_ext_info[] = {
IIO_ENUM("dither_scale", IIO_SEPARATE, &ad5766_dither_scale_enum),
IIO_ENUM_AVAILABLE("dither_scale", IIO_SEPARATE,
&ad5766_dither_scale_enum),
- {}
+ { }
};
#define AD576x_CHANNEL(_chan, _bits) { \
@@ -648,14 +646,14 @@ static int ad5766_probe(struct spi_device *spi)
static const struct of_device_id ad5766_dt_match[] = {
{ .compatible = "adi,ad5766" },
{ .compatible = "adi,ad5767" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad5766_dt_match);
static const struct spi_device_id ad5766_spi_ids[] = {
{ "ad5766", ID_AD5766 },
{ "ad5767", ID_AD5767 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5766_spi_ids);
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
index 25cf11d0471b..6eb4027a44fb 100644
--- a/drivers/iio/dac/ad5770r.c
+++ b/drivers/iio/dac/ad5770r.c
@@ -637,13 +637,13 @@ static int ad5770r_probe(struct spi_device *spi)
static const struct of_device_id ad5770r_of_id[] = {
{ .compatible = "adi,ad5770r", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ad5770r_of_id);
static const struct spi_device_id ad5770r_id[] = {
{ "ad5770r", 0 },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, ad5770r_id);
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 07848be3f8d5..41582f2b90fb 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -138,13 +138,11 @@ static int ad5791_spi_read(struct ad5791_state *st, u8 addr, u32 *val)
struct spi_transfer xfers[] = {
{
.tx_buf = &st->data[0].d8[1],
- .bits_per_word = 8,
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d8[1],
.rx_buf = &st->data[2].d8[1],
- .bits_per_word = 8,
.len = 3,
},
};
@@ -312,7 +310,7 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE,
&ad5791_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5791_powerdown_mode_enum),
- { },
+ { }
};
#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \
diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c
index d3f49b5337d2..c3797e40cdd9 100644
--- a/drivers/iio/dac/ad7293.c
+++ b/drivers/iio/dac/ad7293.c
@@ -114,6 +114,7 @@
#define AD7293_REG_DATA_RAW_MSK GENMASK(15, 4)
#define AD7293_REG_VINX_RANGE_GET_CH_MSK(x, ch) (((x) >> (ch)) & 0x1)
#define AD7293_REG_VINX_RANGE_SET_CH_MSK(x, ch) (((x) & 0x1) << (ch))
+#define AD7293_GENERAL_ADC_REF_MSK BIT(7)
#define AD7293_CHIP_ID 0x18
enum ad7293_ch_type {
@@ -141,6 +142,7 @@ struct ad7293_state {
/* Protect against concurrent accesses to the device, page selection and data content */
struct mutex lock;
struct gpio_desc *gpio_reset;
+ bool vrefin_en;
u8 page_select;
u8 data[3] __aligned(IIO_DMA_MINALIGN);
};
@@ -785,6 +787,12 @@ static int ad7293_properties_parse(struct ad7293_state *st)
if (ret)
return dev_err_probe(&spi->dev, ret, "failed to enable VDRIVE\n");
+ ret = devm_regulator_get_enable_optional(&spi->dev, "vrefin");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(&spi->dev, ret, "failed to enable VREFIN\n");
+
+ st->vrefin_en = ret != -ENODEV;
+
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gpio_reset))
@@ -818,6 +826,11 @@ static int ad7293_init(struct ad7293_state *st)
return -EINVAL;
}
+ if (!st->vrefin_en)
+ return __ad7293_spi_update_bits(st, AD7293_REG_GENERAL,
+ AD7293_GENERAL_ADC_REF_MSK,
+ AD7293_GENERAL_ADC_REF_MSK);
+
return 0;
}
@@ -859,13 +872,13 @@ static int ad7293_probe(struct spi_device *spi)
static const struct spi_device_id ad7293_id[] = {
{ "ad7293", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad7293_id);
static const struct of_device_id ad7293_of_match[] = {
{ .compatible = "adi,ad7293" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad7293_of_match);
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index bff6bf697d9c..a88cc639047d 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -173,7 +173,7 @@ static const struct iio_chan_spec_ext_info ad7303_ext_info[] = {
.write = ad7303_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
- { },
+ { }
};
#define AD7303_CHANNEL(chan) { \
@@ -264,13 +264,13 @@ static int ad7303_probe(struct spi_device *spi)
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 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c
index 8a362fae2eca..60e663af1cc1 100644
--- a/drivers/iio/dac/ad8801.c
+++ b/drivers/iio/dac/ad8801.c
@@ -153,7 +153,7 @@ static int ad8801_probe(struct spi_device *spi)
static const struct spi_device_id ad8801_ids[] = {
{"ad8801", ID_AD8801},
{"ad8803", ID_AD8803},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad8801_ids);
diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c
index b6a65359b0b4..d77b46d83bd4 100644
--- a/drivers/iio/dac/ad9739a.c
+++ b/drivers/iio/dac/ad9739a.c
@@ -442,13 +442,13 @@ static int ad9739a_probe(struct spi_device *spi)
static const struct of_device_id ad9739a_of_match[] = {
{ .compatible = "adi,ad9739a" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad9739a_of_match);
static const struct spi_device_id ad9739a_id[] = {
{"ad9739a"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad9739a_id);
diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c
index 892d770aec69..33faba4b02c2 100644
--- a/drivers/iio/dac/adi-axi-dac.c
+++ b/drivers/iio/dac/adi-axi-dac.c
@@ -84,6 +84,7 @@
#define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40)
#define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0)
+#define AXI_DAC_CHAN_CNTRL_MAX 15
#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x))
/* 360 degrees in rad */
@@ -186,6 +187,9 @@ static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan,
u32 reg, raw;
int ret;
+ if (chan > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
if (!st->dac_clk) {
dev_err(st->dev, "Sampling rate is 0...\n");
return -EINVAL;
@@ -230,6 +234,9 @@ static int axi_dac_scale_get(struct axi_dac_state *st,
int ret, vals[2];
u32 reg, raw;
+ if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
if (tone_2)
reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel);
else
@@ -264,6 +271,9 @@ static int axi_dac_phase_get(struct axi_dac_state *st,
u32 reg, raw, phase;
int ret, vals[2];
+ if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
if (tone_2)
reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel);
else
@@ -291,6 +301,9 @@ static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan,
u16 raw;
int ret;
+ if (chan > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
if (!sample_rate || freq > sample_rate / 2) {
dev_err(st->dev, "Invalid frequency(%u) dac_clk(%llu)\n",
freq, sample_rate);
@@ -342,6 +355,9 @@ static int axi_dac_scale_set(struct axi_dac_state *st,
u32 raw = 0, reg;
int ret;
+ if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac);
if (ret)
return ret;
@@ -385,6 +401,9 @@ static int axi_dac_phase_set(struct axi_dac_state *st,
u32 raw, reg;
int ret;
+ if (chan->channel > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
ret = iio_str_to_fixpoint(buf, 100000, &integer, &frac);
if (ret)
return ret;
@@ -469,7 +488,7 @@ static const struct iio_chan_spec_ext_info axi_dac_ext_info[] = {
IIO_BACKEND_EX_INFO("scale1", IIO_SEPARATE, AXI_DAC_SCALE_TONE_2),
IIO_BACKEND_EX_INFO("phase0", IIO_SEPARATE, AXI_DAC_PHASE_TONE_1),
IIO_BACKEND_EX_INFO("phase1", IIO_SEPARATE, AXI_DAC_PHASE_TONE_2),
- {}
+ { }
};
static int axi_dac_extend_chan(struct iio_backend *back,
@@ -493,6 +512,9 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
{
struct axi_dac_state *st = iio_backend_get_priv(back);
+ if (chan > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
switch (data) {
case IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE:
return regmap_update_bits(st->regmap,
@@ -514,6 +536,35 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan,
}
}
+static int axi_dac_data_source_get(struct iio_backend *back, unsigned int chan,
+ enum iio_backend_data_source *data)
+{
+ struct axi_dac_state *st = iio_backend_get_priv(back);
+ int ret;
+ u32 val;
+
+ if (chan > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
+
+ ret = regmap_read(st->regmap, AXI_DAC_CHAN_CNTRL_7_REG(chan), &val);
+ if (ret)
+ return ret;
+
+ switch (val) {
+ case AXI_DAC_DATA_INTERNAL_TONE:
+ *data = IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE;
+ return 0;
+ case AXI_DAC_DATA_DMA:
+ *data = IIO_BACKEND_EXTERNAL;
+ return 0;
+ case AXI_DAC_DATA_INTERNAL_RAMP_16BIT:
+ *data = IIO_BACKEND_INTERNAL_RAMP_16BIT;
+ return 0;
+ default:
+ return -EIO;
+ }
+}
+
static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan,
u64 sample_rate)
{
@@ -521,6 +572,8 @@ static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan,
unsigned int freq;
int ret, tone;
+ if (chan > AXI_DAC_CHAN_CNTRL_MAX)
+ return -EINVAL;
if (!sample_rate)
return -EINVAL;
if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE)
@@ -707,6 +760,7 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
{
struct axi_dac_state *st = iio_backend_get_priv(back);
int ret;
+ u32 ival;
guard(mutex)(&st->lock);
@@ -719,6 +773,13 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
if (ret)
return ret;
+ ret = regmap_read_poll_timeout(st->regmap,
+ AXI_DAC_UI_STATUS_REG, ival,
+ FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0,
+ 10, 100 * KILO);
+ if (ret)
+ return ret;
+
return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val);
}
@@ -794,6 +855,7 @@ static const struct iio_backend_ops axi_ad3552r_ops = {
.request_buffer = axi_dac_request_buffer,
.free_buffer = axi_dac_free_buffer,
.data_source_set = axi_dac_data_source_set,
+ .data_source_get = axi_dac_data_source_get,
.ddr_enable = axi_dac_ddr_enable,
.ddr_disable = axi_dac_ddr_disable,
.data_stream_enable = axi_dac_data_stream_enable,
@@ -961,7 +1023,7 @@ static const struct axi_dac_info dac_ad3552r = {
static const struct of_device_id axi_dac_of_match[] = {
{ .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic },
{ .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, axi_dac_of_match);
diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c
index f36f10bfb6be..d1b8441051ae 100644
--- a/drivers/iio/dac/dpot-dac.c
+++ b/drivers/iio/dac/dpot-dac.c
@@ -237,7 +237,7 @@ static void dpot_dac_remove(struct platform_device *pdev)
static const struct of_device_id dpot_dac_match[] = {
{ .compatible = "dpot-dac" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, dpot_dac_match);
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c
index e89e4c054653..a26a99753418 100644
--- a/drivers/iio/dac/ds4424.c
+++ b/drivers/iio/dac/ds4424.c
@@ -301,7 +301,7 @@ MODULE_DEVICE_TABLE(i2c, ds4424_id);
static const struct of_device_id ds4424_of_match[] = {
{ .compatible = "maxim,ds4422" },
{ .compatible = "maxim,ds4424" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, ds4424_of_match);
diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c
index 2332b0c22691..aa1c73f8429d 100644
--- a/drivers/iio/dac/lpc18xx_dac.c
+++ b/drivers/iio/dac/lpc18xx_dac.c
@@ -179,7 +179,7 @@ static void lpc18xx_dac_remove(struct platform_device *pdev)
static const struct of_device_id lpc18xx_dac_match[] = {
{ .compatible = "nxp,lpc1850-dac" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c
index 2758fc8a5ad5..6e80b49f4665 100644
--- a/drivers/iio/dac/ltc1660.c
+++ b/drivers/iio/dac/ltc1660.c
@@ -219,14 +219,14 @@ static void ltc1660_remove(struct spi_device *spi)
static const struct of_device_id ltc1660_dt_ids[] = {
{ .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },
{ .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);
static const struct spi_device_id ltc1660_id[] = {
{"ltc1660", ID_LTC1660},
{"ltc1665", ID_LTC1665},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(spi, ltc1660_id);
diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c
index 999348836d87..105f939f7e54 100644
--- a/drivers/iio/dac/ltc2632.c
+++ b/drivers/iio/dac/ltc2632.c
@@ -176,7 +176,7 @@ static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
.write = ltc2632_write_dac_powerdown,
.shared = IIO_SEPARATE,
},
- { },
+ { }
};
#define LTC2632_CHANNEL(_chan, _bits) { \
@@ -372,7 +372,7 @@ static const struct spi_device_id ltc2632_id[] = {
{ "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
{ "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
{ "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ltc2632_id);
@@ -432,7 +432,7 @@ static const struct of_device_id ltc2632_of_match[] = {
.compatible = "lltc,ltc2636-h8",
.data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ltc2632_of_match);
diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c
index bdc857c7fa6d..1f24f07d1ad2 100644
--- a/drivers/iio/dac/ltc2688.c
+++ b/drivers/iio/dac/ltc2688.c
@@ -104,13 +104,11 @@ static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size,
struct spi_transfer xfers[] = {
{
.tx_buf = st->tx_data,
- .bits_per_word = 8,
.len = reg_size + val_size,
.cs_change = 1,
}, {
.tx_buf = st->tx_data + 3,
.rx_buf = st->rx_data,
- .bits_per_word = 8,
.len = reg_size + val_size,
},
};
@@ -608,7 +606,7 @@ static const struct iio_chan_spec_ext_info ltc2688_toggle_sym_ext_info[] = {
ltc2688_reg_bool_get, ltc2688_reg_bool_set),
LTC2688_CHAN_EXT_INFO("symbol", LTC2688_CMD_SW_TOGGLE, IIO_SEPARATE,
ltc2688_reg_bool_get, ltc2688_reg_bool_set),
- {}
+ { }
};
static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = {
@@ -621,7 +619,7 @@ static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = {
ltc2688_dither_toggle_set),
LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
ltc2688_reg_bool_get, ltc2688_reg_bool_set),
- {}
+ { }
};
static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = {
@@ -649,13 +647,13 @@ static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = {
ltc2688_dither_toggle_set),
LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
ltc2688_reg_bool_get, ltc2688_reg_bool_set),
- {}
+ { }
};
static const struct iio_chan_spec_ext_info ltc2688_ext_info[] = {
LTC2688_CHAN_EXT_INFO("powerdown", LTC2688_CMD_POWERDOWN, IIO_SEPARATE,
ltc2688_reg_bool_get, ltc2688_reg_bool_set),
- {}
+ { }
};
#define LTC2688_CHANNEL(_chan) { \
@@ -991,13 +989,13 @@ static int ltc2688_probe(struct spi_device *spi)
static const struct of_device_id ltc2688_of_id[] = {
{ .compatible = "adi,ltc2688" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ltc2688_of_id);
static const struct spi_device_id ltc2688_id[] = {
{ "ltc2688" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ltc2688_id);
diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c
index 9f72155dcbc7..1b8fe6b8d26e 100644
--- a/drivers/iio/dac/max5522.c
+++ b/drivers/iio/dac/max5522.c
@@ -174,7 +174,7 @@ static int max5522_spi_probe(struct spi_device *spi)
static const struct spi_device_id max5522_ids[] = {
{ "max5522", (kernel_ulong_t)&max5522_chip_info_tbl[ID_MAX5522] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, max5522_ids);
@@ -183,7 +183,7 @@ static const struct of_device_id max5522_of_match[] = {
.compatible = "maxim,max5522",
.data = &max5522_chip_info_tbl[ID_MAX5522],
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, max5522_of_match);
diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c
index b062a18be5e7..e7e29359f8fe 100644
--- a/drivers/iio/dac/max5821.c
+++ b/drivers/iio/dac/max5821.c
@@ -137,7 +137,7 @@ static const struct iio_chan_spec_ext_info max5821_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &max5821_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &max5821_powerdown_mode_enum),
- { },
+ { }
};
#define MAX5821_CHANNEL(chan) { \
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 1337fb02ccf5..62972494a229 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -241,7 +241,7 @@ static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = {
&mcp472x_powerdown_mode_enum[MCP4725]),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
&mcp472x_powerdown_mode_enum[MCP4725]),
- { },
+ { }
};
static const struct iio_chan_spec_ext_info mcp4726_ext_info[] = {
@@ -255,7 +255,7 @@ static const struct iio_chan_spec_ext_info mcp4726_ext_info[] = {
&mcp472x_powerdown_mode_enum[MCP4726]),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
&mcp472x_powerdown_mode_enum[MCP4726]),
- { },
+ { }
};
static const struct iio_chan_spec mcp472x_channel[] = {
diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c
index 192175dc6419..4f30b99110b7 100644
--- a/drivers/iio/dac/mcp4728.c
+++ b/drivers/iio/dac/mcp4728.c
@@ -286,7 +286,7 @@ static const struct iio_chan_spec_ext_info mcp4728_ext_info[] = {
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &mcp4728_powerdown_mode_enum),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
&mcp4728_powerdown_mode_enum),
- {},
+ { }
};
static const struct iio_chan_spec mcp4728_channels[MCP4728_N_CHANNELS] = {
@@ -573,13 +573,13 @@ static int mcp4728_probe(struct i2c_client *client)
static const struct i2c_device_id mcp4728_id[] = {
{ "mcp4728" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mcp4728_id);
static const struct of_device_id mcp4728_of_match[] = {
{ .compatible = "microchip,mcp4728" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mcp4728_of_match);
diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c
index c1a59bbbba3c..748bdca9a964 100644
--- a/drivers/iio/dac/mcp4821.c
+++ b/drivers/iio/dac/mcp4821.c
@@ -206,7 +206,7 @@ static const struct of_device_id mcp4821_of_table[] = {
MCP4821_COMPATIBLE("microchip,mcp4812", ID_MCP4812),
MCP4821_COMPATIBLE("microchip,mcp4821", ID_MCP4821),
MCP4821_COMPATIBLE("microchip,mcp4822", ID_MCP4822),
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mcp4821_of_table);
@@ -217,7 +217,7 @@ static const struct spi_device_id mcp4821_id_table[] = {
{ "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]},
{ "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]},
{ "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]},
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(spi, mcp4821_id_table);
diff --git a/drivers/iio/dac/mcp4922.c b/drivers/iio/dac/mcp4922.c
index 26aa99059813..74f338afcab9 100644
--- a/drivers/iio/dac/mcp4922.c
+++ b/drivers/iio/dac/mcp4922.c
@@ -161,7 +161,7 @@ static const struct spi_device_id mcp4922_id[] = {
{"mcp4912", ID_MCP4912},
{"mcp4921", ID_MCP4921},
{"mcp4922", ID_MCP4922},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, mcp4922_id);
diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c
index e998ab51052e..a35c37d2261d 100644
--- a/drivers/iio/dac/rohm-bd79703.c
+++ b/drivers/iio/dac/rohm-bd79703.c
@@ -38,11 +38,20 @@ static const struct regmap_config bd79703_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+/* Dynamic driver private data */
struct bd79703_data {
struct regmap *regmap;
int vfs;
};
+/* Static, IC type specific data for different variants */
+struct bd7970x_chip_data {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ bool has_vfs;
+};
+
static int bd79703_read_raw(struct iio_dev *idev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -67,7 +76,7 @@ static int bd79703_write_raw(struct iio_dev *idev,
if (val < 0 || val >= 1 << BD79703_DAC_BITS)
return -EINVAL;
- return regmap_write(data->regmap, chan->channel + 1, val);
+ return regmap_write(data->regmap, chan->address, val);
};
static const struct iio_info bd79703_info = {
@@ -75,16 +84,42 @@ static const struct iio_info bd79703_info = {
.write_raw = bd79703_write_raw,
};
-#define BD79703_CHAN(_chan) { \
+#define BD79703_CHAN_ADDR(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .address = (_chan), \
+ .address = (_addr), \
}
+#define BD79703_CHAN(_chan) BD79703_CHAN_ADDR((_chan), (_chan) + 1)
+
+static const struct iio_chan_spec bd79700_channels[] = {
+ BD79703_CHAN(0),
+ BD79703_CHAN(1),
+};
+
+static const struct iio_chan_spec bd79701_channels[] = {
+ BD79703_CHAN(0),
+ BD79703_CHAN(1),
+ BD79703_CHAN(2),
+};
+
+/*
+ * The BD79702 has 4 channels. They aren't mapped to BD79703 channels 0, 1, 2
+ * and 3, but to the channels 0, 1, 4, 5. So the addressing used with SPI
+ * accesses is 1, 2, 5 and 6 for them. Thus, they're not constant offset to
+ * the channel number as with other IC variants.
+ */
+static const struct iio_chan_spec bd79702_channels[] = {
+ BD79703_CHAN_ADDR(0, 1),
+ BD79703_CHAN_ADDR(1, 2),
+ BD79703_CHAN_ADDR(2, 5),
+ BD79703_CHAN_ADDR(3, 6),
+};
+
static const struct iio_chan_spec bd79703_channels[] = {
BD79703_CHAN(0),
BD79703_CHAN(1),
@@ -94,13 +129,46 @@ static const struct iio_chan_spec bd79703_channels[] = {
BD79703_CHAN(5),
};
+static const struct bd7970x_chip_data bd79700_chip_data = {
+ .name = "bd79700",
+ .channels = bd79700_channels,
+ .num_channels = ARRAY_SIZE(bd79700_channels),
+ .has_vfs = false,
+};
+
+static const struct bd7970x_chip_data bd79701_chip_data = {
+ .name = "bd79701",
+ .channels = bd79701_channels,
+ .num_channels = ARRAY_SIZE(bd79701_channels),
+ .has_vfs = false,
+};
+
+static const struct bd7970x_chip_data bd79702_chip_data = {
+ .name = "bd79702",
+ .channels = bd79702_channels,
+ .num_channels = ARRAY_SIZE(bd79702_channels),
+ .has_vfs = true,
+};
+
+static const struct bd7970x_chip_data bd79703_chip_data = {
+ .name = "bd79703",
+ .channels = bd79703_channels,
+ .num_channels = ARRAY_SIZE(bd79703_channels),
+ .has_vfs = true,
+};
+
static int bd79703_probe(struct spi_device *spi)
{
+ const struct bd7970x_chip_data *cd;
struct device *dev = &spi->dev;
struct bd79703_data *data;
struct iio_dev *idev;
int ret;
+ cd = spi_get_device_match_data(spi);
+ if (!cd)
+ return -ENODEV;
+
idev = devm_iio_device_alloc(dev, sizeof(*data));
if (!idev)
return -ENOMEM;
@@ -112,20 +180,30 @@ static int bd79703_probe(struct spi_device *spi)
return dev_err_probe(dev, PTR_ERR(data->regmap),
"Failed to initialize Regmap\n");
- ret = devm_regulator_get_enable(dev, "vcc");
- if (ret)
- return dev_err_probe(dev, ret, "Failed to enable VCC\n");
-
- ret = devm_regulator_get_enable_read_voltage(dev, "vfs");
- if (ret < 0)
- return dev_err_probe(dev, ret, "Failed to get Vfs\n");
-
+ /*
+ * BD79703 has a separate VFS pin, whereas the BD79700 and BD79701 use
+ * VCC for their full-scale output voltage.
+ */
+ if (cd->has_vfs) {
+ ret = devm_regulator_get_enable(dev, "vcc");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable VCC\n");
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "vfs");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get Vfs\n");
+ } else {
+ ret = devm_regulator_get_enable_read_voltage(dev, "vcc");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get VCC\n");
+ }
data->vfs = ret;
- idev->channels = bd79703_channels;
- idev->num_channels = ARRAY_SIZE(bd79703_channels);
+
+ idev->channels = cd->channels;
+ idev->num_channels = cd->num_channels;
idev->modes = INDIO_DIRECT_MODE;
idev->info = &bd79703_info;
- idev->name = "bd79703";
+ idev->name = cd->name;
/* Initialize all to output zero */
ret = regmap_write(data->regmap, BD79703_REG_OUT_ALL, 0);
@@ -136,13 +214,19 @@ static int bd79703_probe(struct spi_device *spi)
}
static const struct spi_device_id bd79703_id[] = {
- { "bd79703", },
+ { "bd79700", (kernel_ulong_t)&bd79700_chip_data },
+ { "bd79701", (kernel_ulong_t)&bd79701_chip_data },
+ { "bd79702", (kernel_ulong_t)&bd79702_chip_data },
+ { "bd79703", (kernel_ulong_t)&bd79703_chip_data },
{ }
};
MODULE_DEVICE_TABLE(spi, bd79703_id);
static const struct of_device_id bd79703_of_match[] = {
- { .compatible = "rohm,bd79703", },
+ { .compatible = "rohm,bd79700", .data = &bd79700_chip_data },
+ { .compatible = "rohm,bd79701", .data = &bd79701_chip_data },
+ { .compatible = "rohm,bd79702", .data = &bd79702_chip_data },
+ { .compatible = "rohm,bd79703", .data = &bd79703_chip_data },
{ }
};
MODULE_DEVICE_TABLE(of, bd79703_of_match);
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
index 95ed5197d16f..8ef702917060 100644
--- a/drivers/iio/dac/stm32-dac-core.c
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -239,7 +239,7 @@ static const struct of_device_id stm32_dac_of_match[] = {
.compatible = "st,stm32h7-dac-core",
.data = (void *)&stm32h7_dac_cfg,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
index 3bfb368b3a23..344388338d9b 100644
--- a/drivers/iio/dac/stm32-dac.c
+++ b/drivers/iio/dac/stm32-dac.c
@@ -250,7 +250,7 @@ static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &stm32_dac_powerdown_mode_en),
- {},
+ { }
};
#define STM32_DAC_CHANNEL(chan, name) { \
@@ -392,7 +392,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_dac_pm_ops, stm32_dac_suspend,
static const struct of_device_id stm32_dac_of_match[] = {
{ .compatible = "st,stm32-dac", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c
index 8e1590e3cc8b..715870c8a9c4 100644
--- a/drivers/iio/dac/ti-dac082s085.c
+++ b/drivers/iio/dac/ti-dac082s085.c
@@ -161,7 +161,7 @@ static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
- { },
+ { }
};
#define TI_DAC_CHANNEL(chan) { \
diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c
index c5162b72951a..bdc3f94aef98 100644
--- a/drivers/iio/dac/ti-dac5571.c
+++ b/drivers/iio/dac/ti-dac5571.c
@@ -216,7 +216,7 @@ static const struct iio_chan_spec_ext_info dac5571_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &dac5571_powerdown_mode),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode),
- {},
+ { }
};
#define dac5571_CHANNEL(chan, name) { \
@@ -398,7 +398,7 @@ static const struct of_device_id dac5571_of_id[] = {
{.compatible = "ti,dac5573", .data = &dac5571_spec[quad_8bit] },
{.compatible = "ti,dac6573", .data = &dac5571_spec[quad_10bit] },
{.compatible = "ti,dac7573", .data = &dac5571_spec[quad_12bit] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, dac5571_of_id);
@@ -414,7 +414,7 @@ static const struct i2c_device_id dac5571_id[] = {
{"dac5573", (kernel_ulong_t)&dac5571_spec[quad_8bit] },
{"dac6573", (kernel_ulong_t)&dac5571_spec[quad_10bit] },
{"dac7573", (kernel_ulong_t)&dac5571_spec[quad_12bit] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, dac5571_id);
diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c
index 6f4aa4794a0c..3d2ce61f0db6 100644
--- a/drivers/iio/dac/ti-dac7311.c
+++ b/drivers/iio/dac/ti-dac7311.c
@@ -147,7 +147,7 @@ static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
- { },
+ { }
};
#define TI_DAC_CHANNEL(chan) { \
diff --git a/drivers/iio/dac/ti-dac7612.c b/drivers/iio/dac/ti-dac7612.c
index 8195815de26f..c308eca02b88 100644
--- a/drivers/iio/dac/ti-dac7612.c
+++ b/drivers/iio/dac/ti-dac7612.c
@@ -166,7 +166,7 @@ static int dac7612_probe(struct spi_device *spi)
static const struct spi_device_id dac7612_id[] = {
{"ti-dac7612"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, dac7612_id);
@@ -174,7 +174,7 @@ static const struct of_device_id dac7612_of_match[] = {
{ .compatible = "ti,dac7612" },
{ .compatible = "ti,dac7612u" },
{ .compatible = "ti,dac7612ub" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, dac7612_of_match);
diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c
index 82a078fa98ad..b30ff7bb4400 100644
--- a/drivers/iio/dac/vf610_dac.c
+++ b/drivers/iio/dac/vf610_dac.c
@@ -99,7 +99,7 @@ static const struct iio_enum vf610_conversion_mode = {
static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR,
&vf610_conversion_mode),
- {},
+ { }
};
#define VF610_DAC_CHAN(_chan_type) { \
@@ -166,7 +166,7 @@ static const struct iio_info vf610_dac_iio_info = {
static const struct of_device_id vf610_dac_match[] = {
{ .compatible = "fsl,vf610-dac", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, vf610_dac_match);
diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
index 288880346707..e35e0596cbfb 100644
--- a/drivers/iio/dummy/iio_simple_dummy_buffer.c
+++ b/drivers/iio/dummy/iio_simple_dummy_buffer.c
@@ -31,6 +31,11 @@ static const s16 fakedata[] = {
[DUMMY_INDEX_ACCELX] = 344,
};
+struct dummy_scan {
+ s16 data[ARRAY_SIZE(fakedata)];
+ aligned_s64 timestamp;
+};
+
/**
* iio_simple_dummy_trigger_h() - the trigger handler function
* @irq: the interrupt number
@@ -45,11 +50,18 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
+ struct dummy_scan *scan;
int i = 0, j;
- u16 *data;
- data = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (!data)
+ /*
+ * Note that some buses such as SPI require DMA safe buffers which
+ * cannot be on the stack. Two easy ways to do this:
+ * - Local kzalloc (as done here)
+ * - A buffer at the end of the structure accessed via iio_priv()
+ * that is marked __aligned(IIO_DMA_MINALIGN).
+ */
+ scan = kzalloc(sizeof(*scan), GFP_KERNEL);
+ if (!scan)
goto done;
/*
@@ -69,13 +81,12 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
* constant table fakedata.
*/
iio_for_each_active_channel(indio_dev, j)
- data[i++] = fakedata[j];
-
- iio_push_to_buffers_with_timestamp(indio_dev, data,
- iio_get_time_ns(indio_dev));
+ scan->data[i++] = fakedata[j];
- kfree(data);
+ iio_push_to_buffers_with_ts(indio_dev, scan, sizeof(*scan),
+ iio_get_time_ns(indio_dev));
+ kfree(scan);
done:
/*
* Tell the core we are done with this trigger and ready for the
diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c
index d85b7d3de866..19f823446cda 100644
--- a/drivers/iio/filter/admv8818.c
+++ b/drivers/iio/filter/admv8818.c
@@ -14,6 +14,7 @@
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/units.h>
@@ -70,6 +71,16 @@
#define ADMV8818_HPF_WR0_MSK GENMASK(7, 4)
#define ADMV8818_LPF_WR0_MSK GENMASK(3, 0)
+#define ADMV8818_BAND_BYPASS 0
+#define ADMV8818_BAND_MIN 1
+#define ADMV8818_BAND_MAX 4
+#define ADMV8818_BAND_CORNER_LOW 0
+#define ADMV8818_BAND_CORNER_HIGH 1
+
+#define ADMV8818_STATE_MIN 0
+#define ADMV8818_STATE_MAX 15
+#define ADMV8818_NUM_STATES 16
+
enum {
ADMV8818_BW_FREQ,
ADMV8818_CENTER_FREQ
@@ -90,20 +101,24 @@ struct admv8818_state {
struct mutex lock;
unsigned int filter_mode;
u64 cf_hz;
+ u64 lpf_margin_hz;
+ u64 hpf_margin_hz;
};
-static const unsigned long long freq_range_hpf[4][2] = {
+static const unsigned long long freq_range_hpf[5][2] = {
+ {0ULL, 0ULL}, /* bypass */
{1750000000ULL, 3550000000ULL},
{3400000000ULL, 7250000000ULL},
{6600000000, 12000000000},
{12500000000, 19900000000}
};
-static const unsigned long long freq_range_lpf[4][2] = {
+static const unsigned long long freq_range_lpf[5][2] = {
+ {U64_MAX, U64_MAX}, /* bypass */
{2050000000ULL, 3850000000ULL},
{3350000000ULL, 7250000000ULL},
{7000000000, 13000000000},
- {12550000000, 18500000000}
+ {12550000000, 18850000000}
};
static const struct regmap_config admv8818_regmap_config = {
@@ -121,44 +136,59 @@ static const char * const admv8818_modes[] = {
static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq)
{
- unsigned int hpf_step = 0, hpf_band = 0, i, j;
- u64 freq_step;
- int ret;
+ int band, state, ret;
+ unsigned int hpf_state = ADMV8818_STATE_MIN, hpf_band = ADMV8818_BAND_BYPASS;
+ u64 freq_error, min_freq_error, freq_corner, freq_step;
- if (freq < freq_range_hpf[0][0])
+ if (freq < freq_range_hpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW])
goto hpf_write;
- if (freq > freq_range_hpf[3][1]) {
- hpf_step = 15;
- hpf_band = 4;
-
+ if (freq >= freq_range_hpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH]) {
+ hpf_state = ADMV8818_STATE_MAX;
+ hpf_band = ADMV8818_BAND_MAX;
goto hpf_write;
}
- for (i = 0; i < 4; i++) {
- freq_step = div_u64((freq_range_hpf[i][1] -
- freq_range_hpf[i][0]), 15);
+ /* Close HPF frequency gap between 12 and 12.5 GHz */
+ if (freq >= 12000ULL * HZ_PER_MHZ && freq < 12500ULL * HZ_PER_MHZ) {
+ hpf_state = ADMV8818_STATE_MAX;
+ hpf_band = 3;
+ goto hpf_write;
+ }
- if (freq > freq_range_hpf[i][0] &&
- (freq < freq_range_hpf[i][1] + freq_step)) {
- hpf_band = i + 1;
+ min_freq_error = U64_MAX;
+ for (band = ADMV8818_BAND_MIN; band <= ADMV8818_BAND_MAX; band++) {
+ /*
+ * This (and therefore all other ranges) have a corner
+ * frequency higher than the target frequency.
+ */
+ if (freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] > freq)
+ break;
- for (j = 1; j <= 16; j++) {
- if (freq < (freq_range_hpf[i][0] + (freq_step * j))) {
- hpf_step = j - 1;
- break;
- }
+ freq_step = freq_range_hpf[band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW];
+ freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
+
+ for (state = ADMV8818_STATE_MIN; state <= ADMV8818_STATE_MAX; state++) {
+ freq_corner = freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] +
+ freq_step * state;
+
+ /*
+ * This (and therefore all other states) have a corner
+ * frequency higher than the target frequency.
+ */
+ if (freq_corner > freq)
+ break;
+
+ freq_error = freq - freq_corner;
+ if (freq_error < min_freq_error) {
+ min_freq_error = freq_error;
+ hpf_state = state;
+ hpf_band = band;
}
- break;
}
}
- /* Close HPF frequency gap between 12 and 12.5 GHz */
- if (freq >= 12000 * HZ_PER_MHZ && freq <= 12500 * HZ_PER_MHZ) {
- hpf_band = 3;
- hpf_step = 15;
- }
-
hpf_write:
ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
ADMV8818_SW_IN_SET_WR0_MSK |
@@ -170,7 +200,7 @@ hpf_write:
return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
ADMV8818_HPF_WR0_MSK,
- FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_step));
+ FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_state));
}
static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
@@ -186,31 +216,52 @@ static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq)
{
- unsigned int lpf_step = 0, lpf_band = 0, i, j;
- u64 freq_step;
- int ret;
+ int band, state, ret;
+ unsigned int lpf_state = ADMV8818_STATE_MIN, lpf_band = ADMV8818_BAND_BYPASS;
+ u64 freq_error, min_freq_error, freq_corner, freq_step;
- if (freq > freq_range_lpf[3][1])
+ if (freq > freq_range_lpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH])
goto lpf_write;
- if (freq < freq_range_lpf[0][0]) {
- lpf_band = 1;
-
+ if (freq < freq_range_lpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW]) {
+ lpf_state = ADMV8818_STATE_MIN;
+ lpf_band = ADMV8818_BAND_MIN;
goto lpf_write;
}
- for (i = 0; i < 4; i++) {
- if (freq > freq_range_lpf[i][0] && freq < freq_range_lpf[i][1]) {
- lpf_band = i + 1;
- freq_step = div_u64((freq_range_lpf[i][1] - freq_range_lpf[i][0]), 15);
+ min_freq_error = U64_MAX;
+ for (band = ADMV8818_BAND_MAX; band >= ADMV8818_BAND_MIN; --band) {
+ /*
+ * At this point the highest corner frequency of
+ * all remaining ranges is below the target.
+ * LPF corner should be >= the target.
+ */
+ if (freq > freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH])
+ break;
+
+ freq_step = freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW];
+ freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
+
+ for (state = ADMV8818_STATE_MAX; state >= ADMV8818_STATE_MIN; --state) {
+
+ freq_corner = freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW] +
+ state * freq_step;
- for (j = 0; j <= 15; j++) {
- if (freq < (freq_range_lpf[i][0] + (freq_step * j))) {
- lpf_step = j;
- break;
- }
+ /*
+ * At this point all other states in range will
+ * place the corner frequency below the target
+ * LPF corner should >= the target.
+ */
+ if (freq > freq_corner)
+ break;
+
+ freq_error = freq_corner - freq;
+ if (freq_error < min_freq_error) {
+ min_freq_error = freq_error;
+ lpf_state = state;
+ lpf_band = band;
}
- break;
}
}
@@ -225,7 +276,7 @@ lpf_write:
return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
ADMV8818_LPF_WR0_MSK,
- FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_step));
+ FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_state));
}
static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
@@ -242,16 +293,28 @@ static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
static int admv8818_rfin_band_select(struct admv8818_state *st)
{
int ret;
+ u64 hpf_corner_target, lpf_corner_target;
st->cf_hz = clk_get_rate(st->clkin);
+ /* Check for underflow */
+ if (st->cf_hz > st->hpf_margin_hz)
+ hpf_corner_target = st->cf_hz - st->hpf_margin_hz;
+ else
+ hpf_corner_target = 0;
+
+ /* Check for overflow */
+ lpf_corner_target = st->cf_hz + st->lpf_margin_hz;
+ if (lpf_corner_target < st->cf_hz)
+ lpf_corner_target = U64_MAX;
+
mutex_lock(&st->lock);
- ret = __admv8818_hpf_select(st, st->cf_hz);
+ ret = __admv8818_hpf_select(st, hpf_corner_target);
if (ret)
goto exit;
- ret = __admv8818_lpf_select(st, st->cf_hz);
+ ret = __admv8818_lpf_select(st, lpf_corner_target);
exit:
mutex_unlock(&st->lock);
return ret;
@@ -278,8 +341,11 @@ static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data);
- *hpf_freq = div_u64(freq_range_hpf[hpf_band - 1][1] - freq_range_hpf[hpf_band - 1][0], 15);
- *hpf_freq = freq_range_hpf[hpf_band - 1][0] + (*hpf_freq * hpf_state);
+ *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW];
+ *hpf_freq = div_u64(*hpf_freq, ADMV8818_NUM_STATES - 1);
+ *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW] +
+ (*hpf_freq * hpf_state);
return ret;
}
@@ -316,8 +382,11 @@ static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data);
- *lpf_freq = div_u64(freq_range_lpf[lpf_band - 1][1] - freq_range_lpf[lpf_band - 1][0], 15);
- *lpf_freq = freq_range_lpf[lpf_band - 1][0] + (*lpf_freq * lpf_state);
+ *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW];
+ *lpf_freq = div_u64(*lpf_freq, ADMV8818_NUM_STATES - 1);
+ *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW] +
+ (*lpf_freq * lpf_state);
return ret;
}
@@ -333,6 +402,19 @@ static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
return ret;
}
+static int admv8818_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
+ return IIO_VAL_INT_64;
+ default:
+ return -EINVAL;
+ }
+}
+
static int admv8818_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
@@ -341,6 +423,9 @@ static int admv8818_write_raw(struct iio_dev *indio_dev,
u64 freq = ((u64)val2 << 32 | (u32)val);
+ if ((s64)freq < 0)
+ return -EINVAL;
+
switch (info) {
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return admv8818_lpf_select(st, freq);
@@ -502,6 +587,7 @@ set_mode:
static const struct iio_info admv8818_info = {
.write_raw = admv8818_write_raw,
+ .write_raw_get_fmt = admv8818_write_raw_get_fmt,
.read_raw = admv8818_read_raw,
.debugfs_reg_access = &admv8818_reg_access,
};
@@ -516,7 +602,7 @@ static const struct iio_enum admv8818_mode_enum = {
static const struct iio_chan_spec_ext_info admv8818_ext_info[] = {
IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL, &admv8818_mode_enum),
- { },
+ { }
};
#define ADMV8818_CHAN(_channel) { \
@@ -641,6 +727,32 @@ static int admv8818_clk_setup(struct admv8818_state *st)
return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);
}
+static int admv8818_read_properties(struct admv8818_state *st)
+{
+ struct spi_device *spi = st->spi;
+ u32 mhz;
+ int ret;
+
+ ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz);
+ if (ret == 0)
+ st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
+ else if (ret == -EINVAL)
+ st->lpf_margin_hz = 0;
+ else
+ return ret;
+
+
+ ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz);
+ if (ret == 0)
+ st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
+ else if (ret == -EINVAL)
+ st->hpf_margin_hz = 0;
+ else if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int admv8818_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -672,6 +784,10 @@ static int admv8818_probe(struct spi_device *spi)
mutex_init(&st->lock);
+ ret = admv8818_read_properties(st);
+ if (ret)
+ return ret;
+
ret = admv8818_init(st);
if (ret)
return ret;
@@ -681,13 +797,13 @@ static int admv8818_probe(struct spi_device *spi)
static const struct spi_device_id admv8818_id[] = {
{ "admv8818", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, admv8818_id);
static const struct of_device_id admv8818_of_match[] = {
{ .compatible = "adi,admv8818" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, admv8818_of_match);
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index b1554ced7a26..63c485e9e44c 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -1032,7 +1032,7 @@ static int ad9523_probe(struct spi_device *spi)
static const struct spi_device_id ad9523_id[] = {
{"ad9523-1", 9523},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad9523_id);
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 61828e61e275..47f1c7e9efa9 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -373,7 +373,7 @@ static const struct iio_chan_spec_ext_info adf4350_ext_info[] = {
_ADF4350_EXT_INFO("frequency_resolution", ADF4350_FREQ_RESOLUTION),
_ADF4350_EXT_INFO("refin_frequency", ADF4350_FREQ_REFIN),
_ADF4350_EXT_INFO("powerdown", ADF4350_PWRDOWN),
- { },
+ { }
};
static const struct iio_chan_spec adf4350_chan = {
@@ -682,14 +682,14 @@ static int adf4350_probe(struct spi_device *spi)
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);
diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c
index 9a84e81787b1..d6dc7827fb41 100644
--- a/drivers/iio/frequency/adf4371.c
+++ b/drivers/iio/frequency/adf4371.c
@@ -438,7 +438,7 @@ static const struct iio_chan_spec_ext_info adf4371_ext_info[] = {
_ADF4371_EXT_INFO("frequency", ADF4371_FREQ),
_ADF4371_EXT_INFO("powerdown", ADF4371_POWER_DOWN),
_ADF4371_EXT_INFO("name", ADF4371_CHANNEL_NAME),
- { },
+ { }
};
#define ADF4371_CHANNEL(index) { \
@@ -626,14 +626,14 @@ static int adf4371_probe(struct spi_device *spi)
static const struct spi_device_id adf4371_id_table[] = {
{ "adf4371", (kernel_ulong_t)&adf4371_chip_info },
{ "adf4372", (kernel_ulong_t)&adf4372_chip_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adf4371_id_table);
static const struct of_device_id adf4371_of_match[] = {
{ .compatible = "adi,adf4371", .data = &adf4371_chip_info },
{ .compatible = "adi,adf4372", .data = &adf4372_chip_info},
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adf4371_of_match);
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
index 45ceeb828d6b..08833b7035e4 100644
--- a/drivers/iio/frequency/adf4377.c
+++ b/drivers/iio/frequency/adf4377.c
@@ -985,14 +985,14 @@ static int adf4377_probe(struct spi_device *spi)
static const struct spi_device_id adf4377_id[] = {
{ "adf4377", (kernel_ulong_t)&adf4377_chip_info },
{ "adf4378", (kernel_ulong_t)&adf4378_chip_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adf4377_id);
static const struct of_device_id adf4377_of_match[] = {
{ .compatible = "adi,adf4377", .data = &adf4377_chip_info },
{ .compatible = "adi,adf4378", .data = &adf4378_chip_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, adf4377_of_match);
diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c
index 8ef583680ad0..d8e8d541990f 100644
--- a/drivers/iio/frequency/admv1013.c
+++ b/drivers/iio/frequency/admv1013.c
@@ -319,7 +319,7 @@ static ssize_t admv1013_write(struct iio_dev *indio_dev,
return -EINVAL;
}
- return ret ? ret : len;
+ return len;
}
static int admv1013_update_quad_filters(struct admv1013_state *st)
@@ -407,7 +407,7 @@ static int admv1013_freq_change(struct notifier_block *nb, unsigned long action,
static const struct iio_chan_spec_ext_info admv1013_ext_info[] = {
_ADMV1013_EXT_INFO("i_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_I_CALIBPHASE),
_ADMV1013_EXT_INFO("q_calibphase", IIO_SEPARATE, ADMV1013_RFMOD_Q_CALIBPHASE),
- { },
+ { }
};
#define ADMV1013_CHAN_PHASE(_channel, _channel2, _admv1013_ext_info) { \
@@ -615,13 +615,13 @@ static int admv1013_probe(struct spi_device *spi)
static const struct spi_device_id admv1013_id[] = {
{ "admv1013", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, admv1013_id);
static const struct of_device_id admv1013_of_match[] = {
{ .compatible = "adi,admv1013" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, admv1013_of_match);
diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c
index 986b87a72577..7a8f92ec80a2 100644
--- a/drivers/iio/frequency/admv1014.c
+++ b/drivers/iio/frequency/admv1014.c
@@ -792,13 +792,13 @@ static int admv1014_probe(struct spi_device *spi)
static const struct spi_device_id admv1014_id[] = {
{ "admv1014", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, admv1014_id);
static const struct of_device_id admv1014_of_match[] = {
{ .compatible = "adi,admv1014" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, admv1014_of_match);
diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c
index 57ee908fc747..a7a21f929970 100644
--- a/drivers/iio/frequency/adrf6780.c
+++ b/drivers/iio/frequency/adrf6780.c
@@ -487,13 +487,13 @@ static int adrf6780_probe(struct spi_device *spi)
static const struct spi_device_id adrf6780_id[] = {
{ "adrf6780", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adrf6780_id);
static const struct of_device_id adrf6780_of_match[] = {
{ .compatible = "adi,adrf6780" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, adrf6780_of_match);
diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c
index 14b3abf6dce9..178bba95a709 100644
--- a/drivers/iio/gyro/adis16080.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -214,7 +214,7 @@ static int adis16080_probe(struct spi_device *spi)
static const struct spi_device_id adis16080_ids[] = {
{ "adis16080", ID_ADIS16080 },
{ "adis16100", ID_ADIS16100 },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, adis16080_ids);
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index c151fbb59ffe..586e6cfa14a9 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -414,7 +414,7 @@ static const struct spi_device_id adis16260_id[] = {
{"adis16250", ADIS16260},
{"adis16255", ADIS16260},
{"adis16251", ADIS16251},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adis16260_id);
diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c
index 223fc181109c..8fcb41f45baa 100644
--- a/drivers/iio/gyro/adxrs290.c
+++ b/drivers/iio/gyro/adxrs290.c
@@ -290,9 +290,8 @@ static int adxrs290_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
switch (chan->type) {
case IIO_ANGL_VEL:
@@ -316,7 +315,7 @@ static int adxrs290_read_raw(struct iio_dev *indio_dev,
break;
}
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
@@ -366,9 +365,8 @@ static int adxrs290_write_raw(struct iio_dev *indio_dev,
struct adxrs290_state *st = iio_priv(indio_dev);
int ret, lpf_idx, hpf_idx;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
switch (mask) {
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
@@ -408,7 +406,7 @@ static int adxrs290_write_raw(struct iio_dev *indio_dev,
break;
}
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c
index f84438e0c42c..a1d8d3cb301b 100644
--- a/drivers/iio/gyro/adxrs450.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -95,12 +95,10 @@ static int adxrs450_spi_read_reg_16(struct iio_dev *indio_dev,
struct spi_transfer xfers[] = {
{
.tx_buf = &st->tx,
- .bits_per_word = 8,
.len = sizeof(st->tx),
.cs_change = 1,
}, {
.rx_buf = &st->rx,
- .bits_per_word = 8,
.len = sizeof(st->rx),
},
};
@@ -169,12 +167,10 @@ static int adxrs450_spi_sensor_data(struct iio_dev *indio_dev, s16 *val)
struct spi_transfer xfers[] = {
{
.tx_buf = &st->tx,
- .bits_per_word = 8,
.len = sizeof(st->tx),
.cs_change = 1,
}, {
.rx_buf = &st->rx,
- .bits_per_word = 8,
.len = sizeof(st->rx),
},
};
@@ -209,7 +205,6 @@ static int adxrs450_spi_initial(struct adxrs450_state *st,
struct spi_transfer xfers = {
.tx_buf = &st->tx,
.rx_buf = &st->rx,
- .bits_per_word = 8,
.len = sizeof(st->tx),
};
@@ -446,7 +441,7 @@ static int adxrs450_probe(struct spi_device *spi)
static const struct spi_device_id adxrs450_id[] = {
{"adxrs450", ID_ADXRS450},
{"adxrs453", ID_ADXRS453},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adxrs450_id);
diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c
index e6caab49f98a..1fb8a7969c25 100644
--- a/drivers/iio/gyro/bmg160_i2c.c
+++ b/drivers/iio/gyro/bmg160_i2c.c
@@ -41,7 +41,7 @@ static void bmg160_i2c_remove(struct i2c_client *client)
static const struct acpi_device_id bmg160_acpi_match[] = {
{"BMG0160", 0},
- {},
+ { }
};
MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
@@ -50,7 +50,7 @@ static const struct i2c_device_id bmg160_i2c_id[] = {
{ "bmg160" },
{ "bmi055_gyro" },
{ "bmi088_gyro" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c
index ac04b3b1b554..6aecc5eb8347 100644
--- a/drivers/iio/gyro/bmg160_spi.c
+++ b/drivers/iio/gyro/bmg160_spi.c
@@ -36,7 +36,7 @@ static const struct spi_device_id bmg160_spi_id[] = {
{"bmg160", 0},
{"bmi055_gyro", 0},
{"bmi088_gyro", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bmg160_spi_id);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 54b6f6fbdcaa..c43990c518f7 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -375,7 +375,7 @@ static const struct platform_device_id hid_gyro_3d_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200076",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);
diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c
index d66224bed8e3..16553948c5c3 100644
--- a/drivers/iio/gyro/mpu3050-core.c
+++ b/drivers/iio/gyro/mpu3050-core.c
@@ -684,7 +684,7 @@ mpu3050_get_mount_matrix(const struct iio_dev *indio_dev,
static const struct iio_chan_spec_ext_info mpu3050_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mpu3050_get_mount_matrix),
- { },
+ { }
};
#define MPU3050_AXIS_CHANNEL(axis, index) \
diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c
index 29ecfa6fd633..8e284f47242c 100644
--- a/drivers/iio/gyro/mpu3050-i2c.c
+++ b/drivers/iio/gyro/mpu3050-i2c.c
@@ -95,7 +95,7 @@ static void mpu3050_i2c_remove(struct i2c_client *client)
*/
static const struct i2c_device_id mpu3050_i2c_id[] = {
{ "mpu3050" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mpu3050_i2c_id);
@@ -103,7 +103,7 @@ static const struct of_device_id mpu3050_i2c_of_match[] = {
{ .compatible = "invensense,mpu3050", .data = "mpu3050" },
/* Deprecated vendor ID from the Input driver */
{ .compatible = "invn,mpu3050", .data = "mpu3050" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, mpu3050_i2c_of_match);
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index d4b11bdba666..aef5ec8f9dee 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -54,7 +54,7 @@ static const struct of_device_id st_gyro_of_match[] = {
.compatible = "st,lsm9ds0-gyro",
.data = LSM9DS0_GYRO_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
@@ -102,7 +102,7 @@ static const struct i2c_device_id st_gyro_id_table[] = {
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{ LSM9DS0_GYRO_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index 811f712711f5..f645da157372 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -59,7 +59,7 @@ static const struct of_device_id st_gyro_of_match[] = {
.compatible = "st,lsm9ds0-gyro",
.data = LSM9DS0_GYRO_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
@@ -107,7 +107,7 @@ static const struct spi_device_id st_gyro_id_table[] = {
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{ LSM9DS0_GYRO_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c
index 13e1dd4dd62c..1582cfc03579 100644
--- a/drivers/iio/health/afe4403.c
+++ b/drivers/iio/health/afe4403.c
@@ -411,7 +411,7 @@ static const struct regmap_config afe4403_regmap_config = {
static const struct of_device_id afe4403_of_match[] = {
{ .compatible = "ti,afe4403", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, afe4403_of_match);
@@ -574,7 +574,7 @@ static int afe4403_probe(struct spi_device *spi)
static const struct spi_device_id afe4403_ids[] = {
{ "afe4403", 0 },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(spi, afe4403_ids);
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
index d49e1572a439..99ff68aed27c 100644
--- a/drivers/iio/health/afe4404.c
+++ b/drivers/iio/health/afe4404.c
@@ -419,7 +419,7 @@ static const struct regmap_config afe4404_regmap_config = {
static const struct of_device_id afe4404_of_match[] = {
{ .compatible = "ti,afe4404", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, afe4404_of_match);
@@ -581,7 +581,7 @@ static int afe4404_probe(struct i2c_client *client)
static const struct i2c_device_id afe4404_ids[] = {
{ "afe4404" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, afe4404_ids);
diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c
index e08d143a707c..846664a4ee90 100644
--- a/drivers/iio/health/max30100.c
+++ b/drivers/iio/health/max30100.c
@@ -483,7 +483,7 @@ static void max30100_remove(struct i2c_client *client)
static const struct i2c_device_id max30100_id[] = {
{ "max30100" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, max30100_id);
diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c
index 1d074eb6a8c5..f5f29d2fec57 100644
--- a/drivers/iio/health/max30102.c
+++ b/drivers/iio/health/max30102.c
@@ -484,11 +484,11 @@ any_mode_retry:
* things cannot concurrently change. And we just keep
* trying until we get one of the modes...
*/
- if (iio_device_claim_direct_mode(indio_dev))
+ if (!iio_device_claim_direct(indio_dev))
goto any_mode_retry;
ret = max30102_get_temp(data, val, true);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
} else {
ret = max30102_get_temp(data, val, false);
iio_device_release_buffer_mode(indio_dev);
@@ -615,7 +615,7 @@ static const struct i2c_device_id max30102_id[] = {
{ "max30101", max30105 },
{ "max30102", max30102 },
{ "max30105", max30105 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, max30102_id);
diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c
index 2323974b805c..f021c3e6d886 100644
--- a/drivers/iio/humidity/am2315.c
+++ b/drivers/iio/humidity/am2315.c
@@ -253,7 +253,7 @@ static int am2315_probe(struct i2c_client *client)
static const struct i2c_device_id am2315_i2c_id[] = {
{ "am2315" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index a303f704b7ed..c2b36e682e06 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -13,6 +13,7 @@
* https://www.ti.com/product/HDC1080/datasheet
*/
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -206,26 +207,20 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW: {
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
if (chan->type == IIO_CURRENT) {
*val = hdc100x_get_heater_status(data);
- ret = IIO_VAL_INT;
- } else {
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret) {
- mutex_unlock(&data->lock);
- return ret;
- }
-
- ret = hdc100x_get_measurement(data, chan);
- iio_device_release_direct_mode(indio_dev);
- if (ret >= 0) {
- *val = ret;
- ret = IIO_VAL_INT;
- }
+ return IIO_VAL_INT;
}
- mutex_unlock(&data->lock);
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = hdc100x_get_measurement(data, chan);
+ iio_device_release_direct(indio_dev);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
}
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
@@ -256,26 +251,23 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev,
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:
+ 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:
+ guard(mutex)(&data->lock);
+ return hdc100x_set_it_time(data, chan->address, val2);
+ }
+ 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;
+ guard(mutex)(&data->lock);
+ return hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
+ val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
+ }
default:
return -EINVAL;
}
@@ -284,27 +276,19 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev,
static int hdc100x_buffer_postenable(struct iio_dev *indio_dev)
{
struct hdc100x_data *data = iio_priv(indio_dev);
- int ret;
/* Buffer is enabled. First set ACQ Mode, then attach poll func */
- mutex_lock(&data->lock);
- ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE,
- HDC100X_REG_CONFIG_ACQ_MODE);
- mutex_unlock(&data->lock);
-
- return ret;
+ guard(mutex)(&data->lock);
+ return hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE,
+ HDC100X_REG_CONFIG_ACQ_MODE);
}
static int hdc100x_buffer_predisable(struct iio_dev *indio_dev)
{
struct hdc100x_data *data = iio_priv(indio_dev);
- int ret;
- mutex_lock(&data->lock);
- ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
- mutex_unlock(&data->lock);
-
- return ret;
+ guard(mutex)(&data->lock);
+ return hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
}
static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = {
diff --git a/drivers/iio/humidity/hdc2010.c b/drivers/iio/humidity/hdc2010.c
index f5867659e00f..894a8b4ab193 100644
--- a/drivers/iio/humidity/hdc2010.c
+++ b/drivers/iio/humidity/hdc2010.c
@@ -169,13 +169,12 @@ static int hdc2010_read_raw(struct iio_dev *indio_dev,
*val = hdc2010_get_heater_status(data);
return IIO_VAL_INT;
}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&data->lock);
ret = hdc2010_get_prim_measurement_word(data, chan);
mutex_unlock(&data->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
*val = ret;
@@ -184,13 +183,12 @@ static int hdc2010_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PEAK: {
int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&data->lock);
ret = hdc2010_get_peak_measurement_byte(data, chan);
mutex_unlock(&data->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
/* Scaling up the value so we can use same offset as RAW */
diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c
index a40e1eb6e98c..be2338d5f407 100644
--- a/drivers/iio/humidity/hid-sensor-humidity.c
+++ b/drivers/iio/humidity/hid-sensor-humidity.c
@@ -276,7 +276,7 @@ static const struct platform_device_id hid_humidity_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200032",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_humidity_ids);
diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c
index 0be11470730c..bfeb0a60d3af 100644
--- a/drivers/iio/humidity/hts221_core.c
+++ b/drivers/iio/humidity/hts221_core.c
@@ -418,31 +418,22 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
return IIO_VAL_INT;
}
-static int hts221_read_raw(struct iio_dev *iio_dev,
- struct iio_chan_spec const *ch,
- int *val, int *val2, long mask)
+static int __hts221_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
{
struct hts221_hw *hw = iio_priv(iio_dev);
- int ret;
-
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = hts221_read_oneshot(hw, ch->address, val);
- break;
+ return hts221_read_oneshot(hw, ch->address, val);
case IIO_CHAN_INFO_SCALE:
- ret = hts221_get_sensor_scale(hw, ch->type, val, val2);
- break;
+ return hts221_get_sensor_scale(hw, ch->type, val, val2);
case IIO_CHAN_INFO_OFFSET:
- ret = hts221_get_sensor_offset(hw, ch->type, val, val2);
- break;
+ return hts221_get_sensor_offset(hw, ch->type, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
*val = hw->odr;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {
u8 idx;
const struct hts221_avg *avg;
@@ -452,64 +443,72 @@ static int hts221_read_raw(struct iio_dev *iio_dev,
avg = &hts221_avg_list[HTS221_SENSOR_H];
idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;
*val = avg->avg_avl[idx];
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_TEMP:
avg = &hts221_avg_list[HTS221_SENSOR_T];
idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;
*val = avg->avg_avl[idx];
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
}
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
+}
+
+static int hts221_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
- iio_device_release_direct_mode(iio_dev);
+ ret = __hts221_read_raw(iio_dev, ch, val, val2, mask);
+
+ iio_device_release_direct(iio_dev);
return ret;
}
-static int hts221_write_raw(struct iio_dev *iio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+static int __hts221_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, long mask)
{
struct hts221_hw *hw = iio_priv(iio_dev);
- int ret;
-
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
- ret = hts221_update_odr(hw, val);
- break;
+ return hts221_update_odr(hw, val);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
- ret = hts221_update_avg(hw, HTS221_SENSOR_H, val);
- break;
+ return hts221_update_avg(hw, HTS221_SENSOR_H, val);
case IIO_TEMP:
- ret = hts221_update_avg(hw, HTS221_SENSOR_T, val);
- break;
+ return hts221_update_avg(hw, HTS221_SENSOR_T, val);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
+}
+
+static int hts221_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
+
+ ret = __hts221_write_raw(iio_dev, chan, val, mask);
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return ret;
}
diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c
index 87a8e3c8d277..cbaa7d1af6c4 100644
--- a/drivers/iio/humidity/hts221_i2c.c
+++ b/drivers/iio/humidity/hts221_i2c.c
@@ -42,19 +42,19 @@ static int hts221_i2c_probe(struct i2c_client *client)
static const struct acpi_device_id hts221_acpi_match[] = {
{"SMO9100", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, hts221_acpi_match);
static const struct of_device_id hts221_i2c_of_match[] = {
{ .compatible = "st,hts221", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, hts221_i2c_of_match);
static const struct i2c_device_id hts221_i2c_id_table[] = {
{ HTS221_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c
index 00154b9d66b5..e6fef2acd523 100644
--- a/drivers/iio/humidity/hts221_spi.c
+++ b/drivers/iio/humidity/hts221_spi.c
@@ -42,13 +42,13 @@ static int hts221_spi_probe(struct spi_device *spi)
static const struct of_device_id hts221_spi_of_match[] = {
{ .compatible = "st,hts221", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, hts221_spi_of_match);
static const struct spi_device_id hts221_spi_id_table[] = {
{ HTS221_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
index 6402e393edb8..7f1775bd26fd 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -232,14 +232,14 @@ static int htu21_probe(struct i2c_client *client)
static const struct i2c_device_id htu21_id[] = {
{"htu21", HTU21},
{"ms8607-humidity", MS8607},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, htu21_id);
static const struct of_device_id htu21_of_match[] = {
{ .compatible = "meas,htu21", },
{ .compatible = "meas,ms8607-humidity", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, htu21_of_match);
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 0ea072a4c966..d160147cce0b 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -39,34 +39,29 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 6,
- .bits_per_word = 8,
.len = 2,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 8,
- .bits_per_word = 8,
.len = 2,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
@@ -133,14 +128,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
struct spi_transfer xfers[] = {
{
.tx_buf = adis->tx,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->read_delay,
@@ -148,14 +141,12 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
}, {
.tx_buf = adis->tx + 4,
.rx_buf = adis->rx,
- .bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.rx_buf = adis->rx + 2,
- .bits_per_word = 8,
.len = 2,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c
index 3086dd536203..90ed3f9bb39c 100644
--- a/drivers/iio/imu/adis16400.c
+++ b/drivers/iio/imu/adis16400.c
@@ -1212,7 +1212,7 @@ static const struct spi_device_id adis16400_id[] = {
{"adis16405", ADIS16400},
{"adis16445", ADIS16445},
{"adis16448", ADIS16448},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adis16400_id);
diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c
index ecf74046fde1..ba1887d36577 100644
--- a/drivers/iio/imu/adis16460.c
+++ b/drivers/iio/imu/adis16460.c
@@ -395,13 +395,13 @@ static int adis16460_probe(struct spi_device *spi)
static const struct spi_device_id adis16460_ids[] = {
{ "adis16460", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, adis16460_ids);
static const struct of_device_id adis16460_of_match[] = {
{ .compatible = "adi,adis16460" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, adis16460_of_match);
diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c
index df8c6cd91169..924395b7e3b4 100644
--- a/drivers/iio/imu/adis16475.c
+++ b/drivers/iio/imu/adis16475.c
@@ -2058,7 +2058,7 @@ static const struct of_device_id adis16475_of_match[] = {
.data = &adis16475_chip_info[ADIS16577_2] },
{ .compatible = "adi,adis16577-3",
.data = &adis16475_chip_info[ADIS16577_3] },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adis16475_of_match);
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 727e0a11eac1..543d5c4bfb11 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -1852,7 +1852,7 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16547-1" },
{ .compatible = "adi,adis16547-2" },
{ .compatible = "adi,adis16547-3" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adis16480_of_match);
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index fdfc0538734c..cd3db2388164 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -49,12 +49,10 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
tx[1] = 0;
adis->xfer[0].tx_buf = tx;
- adis->xfer[0].bits_per_word = 8;
adis->xfer[0].len = 2;
if (adis->data->burst_max_speed_hz)
adis->xfer[0].speed_hz = adis->data->burst_max_speed_hz;
adis->xfer[1].rx_buf = adis->buffer;
- adis->xfer[1].bits_per_word = 8;
adis->xfer[1].len = burst_length;
if (adis->data->burst_max_speed_hz)
adis->xfer[1].speed_hz = adis->data->burst_max_speed_hz;
@@ -100,7 +98,6 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
spi_message_init(&adis->msg);
for (j = 0; j <= scan_count; j++) {
- adis->xfer[j].bits_per_word = 8;
if (j != scan_count)
adis->xfer[j].cs_change = 1;
adis->xfer[j].len = 2;
diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c
index 214503fa4af5..9fa3a19a8977 100644
--- a/drivers/iio/imu/bmi160/bmi160_i2c.c
+++ b/drivers/iio/imu/bmi160/bmi160_i2c.c
@@ -39,7 +39,7 @@ static int bmi160_i2c_probe(struct i2c_client *client)
static const struct i2c_device_id bmi160_i2c_id[] = {
{ "bmi120" },
{ "bmi160" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
@@ -55,14 +55,14 @@ static const struct acpi_device_id bmi160_acpi_match[] = {
{"10EC5280", 0},
{"BMI0120", 0},
{"BMI0160", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
{ .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bmi160_of_match);
diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c
index 8fbaab22db81..ebb586904215 100644
--- a/drivers/iio/imu/bmi160/bmi160_spi.c
+++ b/drivers/iio/imu/bmi160/bmi160_spi.c
@@ -36,21 +36,21 @@ static int bmi160_spi_probe(struct spi_device *spi)
static const struct spi_device_id bmi160_spi_id[] = {
{"bmi120", 0},
{"bmi160", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
{"BMI0120", 0},
{"BMI0160", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static const struct of_device_id bmi160_of_match[] = {
{ .compatible = "bosch,bmi120" },
{ .compatible = "bosch,bmi160" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bmi160_of_match);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index 18787a43477b..f893dbe69965 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -426,7 +426,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval);
-int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip,
inv_icm42600_bus_setup bus_setup);
struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 388520ec60b5..e6cd9dcb0687 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -157,7 +157,7 @@ static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = {
&inv_icm42600_accel_power_mode_enum),
IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE,
&inv_icm42600_accel_power_mode_enum),
- {},
+ { }
};
static const struct iio_chan_spec inv_icm42600_accel_channels[] = {
@@ -685,11 +685,10 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
*val = data;
@@ -747,20 +746,18 @@ static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_accel_write_scale(indio_dev, val, val2);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return inv_icm42600_accel_write_odr(indio_dev, val, val2);
case IIO_CHAN_INFO_CALIBBIAS:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_accel_write_offset(st, chan, val, val2);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
default:
return -EINVAL;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index ef9875d3b79d..63d46619ebfa 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -683,12 +683,13 @@ static void inv_icm42600_disable_pm(void *_data)
pm_runtime_disable(dev);
}
-int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip,
inv_icm42600_bus_setup bus_setup)
{
struct device *dev = regmap_get_device(regmap);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct inv_icm42600_state *st;
- int irq_type;
+ int irq, irq_type;
bool open_drain;
int ret;
@@ -697,6 +698,15 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
return -ENODEV;
}
+ /* get INT1 only supported interrupt or fallback to first interrupt */
+ irq = fwnode_irq_get_byname(fwnode, "INT1");
+ if (irq < 0 && irq != -EPROBE_DEFER) {
+ dev_info(dev, "no INT1 interrupt defined, fallback to first interrupt\n");
+ irq = fwnode_irq_get(fwnode, 0);
+ }
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "error missing INT1 interrupt\n");
+
irq_type = irq_get_trigger_type(irq);
if (!irq_type)
irq_type = IRQF_TRIGGER_FALLING;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 591ed78a55bb..b4d7ce1432a4 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -57,7 +57,7 @@ enum inv_icm42600_gyro_scan {
static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix),
- {},
+ { }
};
static const struct iio_chan_spec inv_icm42600_gyro_channels[] = {
@@ -591,11 +591,10 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_gyro_read_sensor(st, chan, &data);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
*val = data;
@@ -653,20 +652,18 @@ static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return inv_icm42600_gyro_write_odr(indio_dev, val, val2);
case IIO_CHAN_INFO_CALIBBIAS:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_gyro_write_offset(st, chan, val, val2);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
default:
return -EINVAL;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 04e440fe023a..7e4d3ea68721 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -67,8 +67,7 @@ static int inv_icm42600_probe(struct i2c_client *client)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return inv_icm42600_core_probe(regmap, chip, client->irq,
- inv_icm42600_i2c_bus_setup);
+ return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup);
}
/*
@@ -110,7 +109,7 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
.compatible = "invensense,icm42631",
.data = (void *)INV_CHIP_ICM42631,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index 2bd2c4c8e50c..13e2e7d38638 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -64,8 +64,7 @@ static int inv_icm42600_probe(struct spi_device *spi)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return inv_icm42600_core_probe(regmap, chip, spi->irq,
- inv_icm42600_spi_bus_setup);
+ return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup);
}
/*
@@ -107,7 +106,7 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
.compatible = "invensense,icm42631",
.data = (void *)INV_CHIP_ICM42631,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
index 213cce1c3111..988f227f6563 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
@@ -56,27 +56,28 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = inv_icm42600_temp_read(st, &temp);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
*val = temp;
return IIO_VAL_INT;
/*
* T°C = (temp / 132.48) + 25
- * Tm°C = 1000 * ((temp * 100 / 13248) + 25)
+ * Tm°C = 1000 * ((temp / 132.48) + 25)
+ * Tm°C = 7.548309 * temp + 25000
+ * Tm°C = (temp + 3312) * 7.548309
* scale: 100000 / 13248 ~= 7.548309
- * offset: 25000
+ * offset: 3312
*/
case IIO_CHAN_INFO_SCALE:
*val = 7;
*val2 = 548309;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OFFSET:
- *val = 25000;
+ *val = 3312;
return IIO_VAL_INT;
default:
return -EINVAL;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
index 373e59f6d91a..a9bcf02e5b43 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
@@ -39,7 +39,7 @@ static const struct dmi_system_id inv_mpu_dev_list[] = {
},
},
/* Add more matching tables here..*/
- {}
+ { }
};
static int asus_acpi_get_sensor_info(struct acpi_device *adev,
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 5bcd5e797046..b8656c02354a 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -755,13 +755,12 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&st->lock);
ret = inv_mpu6050_read_channel_data(indio_dev, chan, val);
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
@@ -895,9 +894,8 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
* we should only update scale when the chip is disabled, i.e.
* not running
*/
- result = iio_device_claim_direct_mode(indio_dev);
- if (result)
- return result;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&st->lock);
result = pm_runtime_resume_and_get(pdev);
@@ -944,7 +942,7 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
pm_runtime_put_autosuspend(pdev);
error_write_raw_unlock:
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return result;
}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 91d77f94d204..8dc61812a8fc 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -192,7 +192,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"iam20680", INV_IAM20680},
{"iam20680hp", INV_IAM20680HP},
{"iam20680ht", INV_IAM20680HT},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
@@ -276,7 +276,7 @@ MODULE_DEVICE_TABLE(of, inv_of_match);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6500", INV_MPU6500},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
index 20de6eb5cd35..1f4c62142b60 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
@@ -83,7 +83,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"iam20680", INV_IAM20680},
{"iam20680hp", INV_IAM20680HP},
{"iam20680ht", INV_IAM20680HT},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, inv_mpu_id);
@@ -163,7 +163,7 @@ MODULE_DEVICE_TABLE(of, inv_of_match);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6000", INV_MPU6000},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index e19c5d3137c6..2bdfb2619137 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1487,7 +1487,7 @@ static const struct dev_pm_ops kmx61_pm_ops = {
static const struct i2c_device_id kmx61_id[] = {
{ "kmx611021" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, kmx61_id);
diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c
index 4492c4d013bd..d159ee59acdd 100644
--- a/drivers/iio/imu/smi240.c
+++ b/drivers/iio/imu/smi240.c
@@ -414,11 +414,10 @@ static int smi240_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = smi240_get_data(data, chan->type, chan->channel2, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
return IIO_VAL_INT;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 96c6106b95ee..c65ad49829e7 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -1804,12 +1804,11 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- break;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = sensor->odr / 1000;
@@ -1834,11 +1833,10 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
int val, int val2, long mask)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
- int err;
+ int err = 0;
- err = iio_device_claim_direct_mode(iio_dev);
- if (err)
- return err;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -1860,7 +1858,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
break;
}
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return err;
}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 25e1de89b6e4..7c933218036b 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -138,13 +138,13 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,asm330lhhxg1",
.data = (void *)ST_ASM330LHHXG1_ID,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
static const struct acpi_device_id st_lsm6dsx_i2c_acpi_match[] = {
{ "SMO8B30", ST_LSM6DS3TRC_ID, },
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, st_lsm6dsx_i2c_acpi_match);
@@ -173,7 +173,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
{ ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
index f968f32890d1..cb5c5d7e1f3d 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c
@@ -17,7 +17,7 @@
static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = {
I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID),
I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID),
- { /* sentinel */ },
+ { }
};
MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
index c1b444520d2a..3c5e65dc0f97 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
@@ -558,12 +558,11 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- break;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
ret = st_lsm6dsx_shub_read_oneshot(sensor, ch, val);
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = sensor->ext_info.slv_odr / 1000;
@@ -614,53 +613,57 @@ st_lsm6dsx_shub_set_full_scale(struct st_lsm6dsx_sensor *sensor,
}
static int
-st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+__st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
int err;
- err = iio_device_claim_direct_mode(iio_dev);
- if (err)
- return err;
-
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ: {
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ struct st_lsm6dsx_sensor *ref_sensor;
+ u8 odr_val;
u16 data;
+ int odr;
val = val * 1000 + val2 / 1000;
err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data);
- if (!err) {
- struct st_lsm6dsx_hw *hw = sensor->hw;
- struct st_lsm6dsx_sensor *ref_sensor;
- u8 odr_val;
- int odr;
-
- ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
- odr = st_lsm6dsx_check_odr(ref_sensor, val, &odr_val);
- if (odr < 0) {
- err = odr;
- goto release;
- }
-
- sensor->ext_info.slv_odr = val;
- sensor->odr = odr;
- }
- break;
+ if (err)
+ return err;
+
+ ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+ odr = st_lsm6dsx_check_odr(ref_sensor, val, &odr_val);
+ if (odr < 0)
+ return odr;
+
+ sensor->ext_info.slv_odr = val;
+ sensor->odr = odr;
+ return 0;
}
case IIO_CHAN_INFO_SCALE:
- err = st_lsm6dsx_shub_set_full_scale(sensor, val2);
- break;
+ return st_lsm6dsx_shub_set_full_scale(sensor, val2);
default:
- err = -EINVAL;
- break;
+ return -EINVAL;
}
+}
+
+static int
+st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
-release:
- iio_device_release_direct_mode(iio_dev);
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
- return err;
+ ret = __st_lsm6dsx_shub_write_raw(iio_dev, chan, val, val2, mask);
+
+ iio_device_release_direct(iio_dev);
+
+ return ret;
}
static ssize_t
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 4b4b6d45524f..3389b15df0bc 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -133,7 +133,7 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,asm330lhhxg1",
.data = (void *)ST_ASM330LHHXG1_ID,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -162,7 +162,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
{ ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
{ ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
index 8cc071463249..4232a9d800fc 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
@@ -28,20 +28,20 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
.compatible = "st,lsm9ds0-imu",
.data = LSM9DS0_IMU_DEV_NAME,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
static const struct i2c_device_id st_lsm9ds0_id_table[] = {
{ LSM303D_IMU_DEV_NAME },
{ LSM9DS0_IMU_DEV_NAME },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
static const struct acpi_device_id st_lsm9ds0_acpi_match[] = {
{"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME},
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match);
diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
index 806e55f75f65..acea8a0757d7 100644
--- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
+++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
@@ -28,14 +28,14 @@ static const struct of_device_id st_lsm9ds0_of_match[] = {
.compatible = "st,lsm9ds0-imu",
.data = LSM9DS0_IMU_DEV_NAME,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, st_lsm9ds0_of_match);
static const struct spi_device_id st_lsm9ds0_id_table[] = {
{ LSM303D_IMU_DEV_NAME },
{ LSM9DS0_IMU_DEV_NAME },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, st_lsm9ds0_id_table);
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
index a43c8d1bb3d0..c1eb9ef9db08 100644
--- a/drivers/iio/industrialio-backend.c
+++ b/drivers/iio/industrialio-backend.c
@@ -381,6 +381,34 @@ int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan,
EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, "IIO_BACKEND");
/**
+ * iio_backend_data_source_get - Get current data source
+ * @back: Backend device
+ * @chan: Channel number
+ * @data: Pointer to receive the current source value
+ *
+ * A given backend may have different sources to stream/sync data. This allows
+ * to know what source is in use.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_source_get(struct iio_backend *back, unsigned int chan,
+ enum iio_backend_data_source *data)
+{
+ int ret;
+
+ ret = iio_backend_op_call(back, data_source_get, chan, data);
+ if (ret)
+ return ret;
+
+ if (*data >= IIO_BACKEND_DATA_SOURCE_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_get, "IIO_BACKEND");
+
+/**
* iio_backend_set_sampling_freq - Set channel sampling rate
* @back: Backend device
* @chan: Channel number
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index b9f4113ae5fc..178e99b111de 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -26,6 +26,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wait.h>
+#include <linux/wordpart.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
@@ -966,8 +967,10 @@ static ssize_t iio_write_channel_info(struct device *dev,
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, fract_mult = 100000;
int integer, fract = 0;
+ long long integer64;
bool is_char = false;
bool scale_db = false;
+ bool is_64bit = false;
/* Assumes decimal - precision based on number of digits */
if (!indio_dev->info->write_raw)
@@ -991,6 +994,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
case IIO_VAL_CHAR:
is_char = true;
break;
+ case IIO_VAL_INT_64:
+ is_64bit = true;
+ break;
default:
return -EINVAL;
}
@@ -1001,6 +1007,13 @@ static ssize_t iio_write_channel_info(struct device *dev,
if (sscanf(buf, "%c", &ch) != 1)
return -EINVAL;
integer = ch;
+ } else if (is_64bit) {
+ ret = kstrtoll(buf, 0, &integer64);
+ if (ret)
+ return ret;
+
+ fract = upper_32_bits(integer64);
+ integer = lower_32_bits(integer64);
} else {
ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
scale_db);
@@ -2144,17 +2157,19 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev,
EXPORT_SYMBOL_GPL(__devm_iio_device_register);
/**
- * iio_device_claim_direct_mode - Keep device in direct mode
+ * __iio_device_claim_direct - Keep device in direct mode
* @indio_dev: the iio_dev associated with the device
*
* If the device is in direct mode it is guaranteed to stay
- * that way until iio_device_release_direct_mode() is called.
+ * that way until __iio_device_release_direct() is called.
*
- * Use with iio_device_release_direct_mode()
+ * Use with __iio_device_release_direct().
*
- * Returns: 0 on success, -EBUSY on failure.
+ * Drivers should only call iio_device_claim_direct().
+ *
+ * Returns: true on success, false on failure.
*/
-int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
+bool __iio_device_claim_direct(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
@@ -2162,26 +2177,28 @@ int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&iio_dev_opaque->mlock);
- return -EBUSY;
+ return false;
}
- return 0;
+ return true;
}
-EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
+EXPORT_SYMBOL_GPL(__iio_device_claim_direct);
/**
- * iio_device_release_direct_mode - releases claim on direct mode
+ * __iio_device_release_direct - releases claim on direct mode
* @indio_dev: the iio_dev associated with the device
*
* Release the claim. Device is no longer guaranteed to stay
* in direct mode.
*
- * Use with iio_device_claim_direct_mode()
+ * Drivers should only call iio_device_release_direct().
+ *
+ * Use with __iio_device_claim_direct()
*/
-void iio_device_release_direct_mode(struct iio_dev *indio_dev)
+void __iio_device_release_direct(struct iio_dev *indio_dev)
{
mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
}
-EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
+EXPORT_SYMBOL_GPL(__iio_device_release_direct);
/**
* iio_device_claim_buffer_mode - Keep device in buffer mode
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index 2d91caf24dd0..032e6cae8b80 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -230,7 +230,7 @@ static int acpi_als_add(struct acpi_device *device)
static const struct acpi_device_id acpi_als_device_ids[] = {
{"ACPI0008", 0},
- {},
+ { }
};
MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids);
diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c
index 9240983a6cc4..e321f89c5340 100644
--- a/drivers/iio/light/adux1020.c
+++ b/drivers/iio/light/adux1020.c
@@ -820,7 +820,7 @@ static int adux1020_probe(struct i2c_client *client)
static const struct i2c_device_id adux1020_id[] = {
{ "adux1020" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, adux1020_id);
diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c
index e2fbb1270040..6f301c067045 100644
--- a/drivers/iio/light/al3000a.c
+++ b/drivers/iio/light/al3000a.c
@@ -85,12 +85,17 @@ static void al3000a_set_pwr_off(void *_data)
static int al3000a_init(struct al3000a_data *data)
{
+ struct device *dev = regmap_get_device(data->regmap);
int ret;
ret = al3000a_set_pwr_on(data);
if (ret)
return ret;
+ ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add action\n");
+
ret = regmap_write(data->regmap, AL3000A_REG_SYSTEM, AL3000A_CONFIG_RESET);
if (ret)
return ret;
@@ -157,10 +162,6 @@ static int al3000a_probe(struct i2c_client *client)
if (ret)
return dev_err_probe(dev, ret, "failed to init ALS\n");
- ret = devm_add_action_or_reset(dev, al3000a_set_pwr_off, data);
- if (ret)
- return dev_err_probe(dev, ret, "failed to add action\n");
-
return devm_iio_device_register(dev, indio_dev);
}
@@ -189,7 +190,7 @@ MODULE_DEVICE_TABLE(i2c, al3000a_id);
static const struct of_device_id al3000a_of_match[] = {
{ .compatible = "dynaimage,al3000a" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, al3000a_of_match);
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
index 7cbb8b203300..0932fa2b49fa 100644
--- a/drivers/iio/light/al3010.c
+++ b/drivers/iio/light/al3010.c
@@ -17,13 +17,12 @@
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#define AL3010_DRV_NAME "al3010"
-
#define AL3010_REG_SYSTEM 0x00
#define AL3010_REG_DATA_LOW 0x0c
#define AL3010_REG_CONFIG 0x10
@@ -46,8 +45,14 @@ static const int al3010_scales[][2] = {
{0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
};
+static const struct regmap_config al3010_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AL3010_REG_CONFIG,
+};
+
struct al3010_data {
- struct i2c_client *client;
+ struct regmap *regmap;
};
static const struct iio_chan_spec al3010_channels[] = {
@@ -69,40 +74,36 @@ static const struct attribute_group al3010_attribute_group = {
.attrs = al3010_attributes,
};
-static int al3010_set_pwr(struct i2c_client *client, bool pwr)
+static int al3010_set_pwr_on(struct al3010_data *data)
{
- u8 val = pwr ? AL3010_CONFIG_ENABLE : AL3010_CONFIG_DISABLE;
- return i2c_smbus_write_byte_data(client, AL3010_REG_SYSTEM, val);
+ return regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_ENABLE);
}
static void al3010_set_pwr_off(void *_data)
{
struct al3010_data *data = _data;
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
- al3010_set_pwr(data->client, false);
+ ret = regmap_write(data->regmap, AL3010_REG_SYSTEM, AL3010_CONFIG_DISABLE);
+ if (ret)
+ dev_err(dev, "failed to write system register\n");
}
static int al3010_init(struct al3010_data *data)
{
+ struct device *dev = regmap_get_device(data->regmap);
int ret;
- ret = al3010_set_pwr(data->client, true);
- if (ret < 0)
+ ret = al3010_set_pwr_on(data);
+ if (ret)
return ret;
- ret = devm_add_action_or_reset(&data->client->dev,
- al3010_set_pwr_off,
- data);
- if (ret < 0)
+ ret = devm_add_action_or_reset(dev, al3010_set_pwr_off, data);
+ if (ret)
return ret;
-
- ret = i2c_smbus_write_byte_data(data->client, AL3010_REG_CONFIG,
- FIELD_PREP(AL3010_GAIN_MASK,
- AL3XXX_RANGE_3));
- if (ret < 0)
- return ret;
-
- return 0;
+ return regmap_write(data->regmap, AL3010_REG_CONFIG,
+ FIELD_PREP(AL3010_GAIN_MASK, AL3XXX_RANGE_3));
}
static int al3010_read_raw(struct iio_dev *indio_dev,
@@ -110,7 +111,7 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3010_data *data = iio_priv(indio_dev);
- int ret;
+ int ret, gain, raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -119,21 +120,21 @@ static int al3010_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3010_REG_DATA_LOW
* - high byte of output is stored at AL3010_REG_DATA_LOW + 1
*/
- ret = i2c_smbus_read_word_data(data->client,
- AL3010_REG_DATA_LOW);
- if (ret < 0)
+ ret = regmap_read(data->regmap, AL3010_REG_DATA_LOW, &raw);
+ if (ret)
return ret;
- *val = ret;
+
+ *val = raw;
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = i2c_smbus_read_byte_data(data->client,
- AL3010_REG_CONFIG);
- if (ret < 0)
+ ret = regmap_read(data->regmap, AL3010_REG_CONFIG, &gain);
+ if (ret)
return ret;
- ret = FIELD_GET(AL3010_GAIN_MASK, ret);
- *val = al3010_scales[ret][0];
- *val2 = al3010_scales[ret][1];
+ gain = FIELD_GET(AL3010_GAIN_MASK, gain);
+ *val = al3010_scales[gain][0];
+ *val2 = al3010_scales[gain][1];
return IIO_VAL_INT_PLUS_MICRO;
}
@@ -145,7 +146,7 @@ static int al3010_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct al3010_data *data = iio_priv(indio_dev);
- int i;
+ unsigned int i;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -154,9 +155,8 @@ static int al3010_write_raw(struct iio_dev *indio_dev,
val2 != al3010_scales[i][1])
continue;
- return i2c_smbus_write_byte_data(data->client,
- AL3010_REG_CONFIG,
- FIELD_PREP(AL3010_GAIN_MASK, i));
+ return regmap_write(data->regmap, AL3010_REG_CONFIG,
+ FIELD_PREP(AL3010_GAIN_MASK, i));
}
break;
}
@@ -172,59 +172,66 @@ static const struct iio_info al3010_info = {
static int al3010_probe(struct i2c_client *client)
{
struct al3010_data *data;
+ struct device *dev = &client->dev;
struct iio_dev *indio_dev;
int ret;
- 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;
+ data->regmap = devm_regmap_init_i2c(client, &al3010_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "cannot allocate regmap\n");
indio_dev->info = &al3010_info;
- indio_dev->name = AL3010_DRV_NAME;
+ indio_dev->name = "al3010";
indio_dev->channels = al3010_channels;
indio_dev->num_channels = ARRAY_SIZE(al3010_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = al3010_init(data);
- if (ret < 0) {
- dev_err(&client->dev, "al3010 chip init failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to init ALS\n");
- return devm_iio_device_register(&client->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static int al3010_suspend(struct device *dev)
{
- return al3010_set_pwr(to_i2c_client(dev), false);
+ struct al3010_data *data = iio_priv(dev_get_drvdata(dev));
+
+ al3010_set_pwr_off(data);
+ return 0;
}
static int al3010_resume(struct device *dev)
{
- return al3010_set_pwr(to_i2c_client(dev), true);
+ struct al3010_data *data = iio_priv(dev_get_drvdata(dev));
+
+ return al3010_set_pwr_on(data);
}
static DEFINE_SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume);
static const struct i2c_device_id al3010_id[] = {
{"al3010", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, al3010_id);
static const struct of_device_id al3010_of_match[] = {
{ .compatible = "dynaimage,al3010", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, al3010_of_match);
static struct i2c_driver al3010_driver = {
.driver = {
- .name = AL3010_DRV_NAME,
+ .name = "al3010",
.of_match_table = al3010_of_match,
.pm = pm_sleep_ptr(&al3010_pm_ops),
},
diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c
index 497ea3fe3377..63f5a85912fc 100644
--- a/drivers/iio/light/al3320a.c
+++ b/drivers/iio/light/al3320a.c
@@ -15,13 +15,12 @@
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#define AL3320A_DRV_NAME "al3320a"
-
#define AL3320A_REG_CONFIG 0x00
#define AL3320A_REG_STATUS 0x01
#define AL3320A_REG_INT 0x02
@@ -59,8 +58,14 @@ static const int al3320a_scales[][2] = {
{0, 512000}, {0, 128000}, {0, 32000}, {0, 10000}
};
+static const struct regmap_config al3320a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AL3320A_REG_HIGH_THRESH_HIGH,
+};
+
struct al3320a_data {
- struct i2c_client *client;
+ struct regmap *regmap;
};
static const struct iio_chan_spec al3320a_channels[] = {
@@ -82,45 +87,47 @@ static const struct attribute_group al3320a_attribute_group = {
.attrs = al3320a_attributes,
};
-static int al3320a_set_pwr(struct i2c_client *client, bool pwr)
+static int al3320a_set_pwr_on(struct al3320a_data *data)
{
- u8 val = pwr ? AL3320A_CONFIG_ENABLE : AL3320A_CONFIG_DISABLE;
- return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG, val);
+ return regmap_write(data->regmap, AL3320A_REG_CONFIG, AL3320A_CONFIG_ENABLE);
}
static void al3320a_set_pwr_off(void *_data)
{
struct al3320a_data *data = _data;
+ struct device *dev = regmap_get_device(data->regmap);
+ int ret;
- al3320a_set_pwr(data->client, false);
+ ret = regmap_write(data->regmap, AL3320A_REG_CONFIG, AL3320A_CONFIG_DISABLE);
+ if (ret)
+ dev_err(dev, "failed to write system register\n");
}
static int al3320a_init(struct al3320a_data *data)
{
+ struct device *dev = regmap_get_device(data->regmap);
int ret;
- ret = al3320a_set_pwr(data->client, true);
-
- if (ret < 0)
+ ret = al3320a_set_pwr_on(data);
+ if (ret)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE,
- FIELD_PREP(AL3320A_GAIN_MASK,
- AL3320A_RANGE_3));
- if (ret < 0)
+ ret = devm_add_action_or_reset(dev, al3320a_set_pwr_off, data);
+ if (ret)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME,
- AL3320A_DEFAULT_MEAN_TIME);
- if (ret < 0)
+ ret = regmap_write(data->regmap, AL3320A_REG_CONFIG_RANGE,
+ FIELD_PREP(AL3320A_GAIN_MASK, AL3320A_RANGE_3));
+ if (ret)
return ret;
- ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT,
- AL3320A_DEFAULT_WAIT_TIME);
- if (ret < 0)
+ ret = regmap_write(data->regmap, AL3320A_REG_MEAN_TIME,
+ AL3320A_DEFAULT_MEAN_TIME);
+ if (ret)
return ret;
- return 0;
+ return regmap_write(data->regmap, AL3320A_REG_WAIT,
+ AL3320A_DEFAULT_WAIT_TIME);
}
static int al3320a_read_raw(struct iio_dev *indio_dev,
@@ -128,7 +135,7 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct al3320a_data *data = iio_priv(indio_dev);
- int ret;
+ int ret, gain, raw;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -137,21 +144,21 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
* - low byte of output is stored at AL3320A_REG_DATA_LOW
* - high byte of output is stored at AL3320A_REG_DATA_LOW + 1
*/
- ret = i2c_smbus_read_word_data(data->client,
- AL3320A_REG_DATA_LOW);
- if (ret < 0)
+ ret = regmap_read(data->regmap, AL3320A_REG_DATA_LOW, &raw);
+ if (ret)
return ret;
- *val = ret;
+
+ *val = raw;
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- ret = i2c_smbus_read_byte_data(data->client,
- AL3320A_REG_CONFIG_RANGE);
- if (ret < 0)
+ ret = regmap_read(data->regmap, AL3320A_REG_CONFIG_RANGE, &gain);
+ if (ret)
return ret;
- ret = FIELD_GET(AL3320A_GAIN_MASK, ret);
- *val = al3320a_scales[ret][0];
- *val2 = al3320a_scales[ret][1];
+ gain = FIELD_GET(AL3320A_GAIN_MASK, gain);
+ *val = al3320a_scales[gain][0];
+ *val2 = al3320a_scales[gain][1];
return IIO_VAL_INT_PLUS_MICRO;
}
@@ -163,7 +170,7 @@ static int al3320a_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct al3320a_data *data = iio_priv(indio_dev);
- int i;
+ unsigned int i;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -172,9 +179,8 @@ static int al3320a_write_raw(struct iio_dev *indio_dev,
val2 != al3320a_scales[i][1])
continue;
- return i2c_smbus_write_byte_data(data->client,
- AL3320A_REG_CONFIG_RANGE,
- FIELD_PREP(AL3320A_GAIN_MASK, i));
+ return regmap_write(data->regmap, AL3320A_REG_CONFIG_RANGE,
+ FIELD_PREP(AL3320A_GAIN_MASK, i));
}
break;
}
@@ -190,46 +196,50 @@ static const struct iio_info al3320a_info = {
static int al3320a_probe(struct i2c_client *client)
{
struct al3320a_data *data;
+ struct device *dev = &client->dev;
struct iio_dev *indio_dev;
int ret;
- 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;
+
+ data->regmap = devm_regmap_init_i2c(client, &al3320a_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "cannot allocate regmap\n");
indio_dev->info = &al3320a_info;
- indio_dev->name = AL3320A_DRV_NAME;
+ indio_dev->name = "al3320a";
indio_dev->channels = al3320a_channels;
indio_dev->num_channels = ARRAY_SIZE(al3320a_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = al3320a_init(data);
if (ret < 0) {
- dev_err(&client->dev, "al3320a chip init failed\n");
+ dev_err(dev, "al3320a chip init failed\n");
return ret;
}
- ret = devm_add_action_or_reset(&client->dev,
- al3320a_set_pwr_off,
- data);
- if (ret < 0)
- return ret;
-
- return devm_iio_device_register(&client->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static int al3320a_suspend(struct device *dev)
{
- return al3320a_set_pwr(to_i2c_client(dev), false);
+ struct al3320a_data *data = iio_priv(dev_get_drvdata(dev));
+
+ al3320a_set_pwr_off(data);
+ return 0;
}
static int al3320a_resume(struct device *dev)
{
- return al3320a_set_pwr(to_i2c_client(dev), true);
+ struct al3320a_data *data = iio_priv(dev_get_drvdata(dev));
+
+ return al3320a_set_pwr_on(data);
}
static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend,
@@ -237,25 +247,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend,
static const struct i2c_device_id al3320a_id[] = {
{ "al3320a" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, al3320a_id);
static const struct of_device_id al3320a_of_match[] = {
{ .compatible = "dynaimage,al3320a", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, al3320a_of_match);
static const struct acpi_device_id al3320a_acpi_match[] = {
{"CALS0001"},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, al3320a_acpi_match);
static struct i2c_driver al3320a_driver = {
.driver = {
- .name = AL3320A_DRV_NAME,
+ .name = "al3320a",
.of_match_table = al3320a_of_match,
.pm = pm_sleep_ptr(&al3320a_pm_ops),
.acpi_match_table = al3320a_acpi_match,
diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c
index 5ed7e17f49e7..e9b237de180a 100644
--- a/drivers/iio/light/apds9306.c
+++ b/drivers/iio/light/apds9306.c
@@ -831,11 +831,10 @@ static int apds9306_read_raw(struct iio_dev *indio_dev,
* Changing device parameters during adc operation, resets
* the ADC which has to avoided.
*/
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = apds9306_read_data(data, val, reg);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index d30441d33703..0003a29bf264 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -1157,7 +1157,7 @@ static const struct dev_pm_ops apds9960_pm_ops = {
static const struct i2c_device_id apds9960_id[] = {
{ "apds9960" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, apds9960_id);
diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c
index 37fffce35dd1..68f60dc3c79d 100644
--- a/drivers/iio/light/as73211.c
+++ b/drivers/iio/light/as73211.c
@@ -16,6 +16,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -418,18 +419,17 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons
case IIO_CHAN_INFO_RAW: {
int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret < 0)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = as73211_req_data(data);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
ret = i2c_smbus_read_word_data(data->client, chan->address);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -517,6 +517,16 @@ static int _as73211_write_raw(struct iio_dev *indio_dev,
struct as73211_data *data = iio_priv(indio_dev);
int ret;
+ /* Need to switch to config mode ... */
+ if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) {
+ data->osr &= ~AS73211_OSR_DOS_MASK;
+ data->osr |= AS73211_OSR_DOS_CONFIG;
+
+ ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
+ if (ret < 0)
+ return ret;
+ }
+
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ: {
int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */
@@ -601,28 +611,14 @@ static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec con
struct as73211_data *data = iio_priv(indio_dev);
int ret;
- mutex_lock(&data->mutex);
-
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret < 0)
- goto error_unlock;
-
- /* Need to switch to config mode ... */
- if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) {
- data->osr &= ~AS73211_OSR_DOS_MASK;
- data->osr |= AS73211_OSR_DOS_CONFIG;
+ guard(mutex)(&data->mutex);
- ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
- if (ret < 0)
- goto error_release;
- }
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = _as73211_write_raw(indio_dev, chan, val, val2, mask);
+ iio_device_release_direct(indio_dev);
-error_release:
- iio_device_release_direct_mode(indio_dev);
-error_unlock:
- mutex_unlock(&data->mutex);
return ret;
}
diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c
index 4b869fa9e5b1..764f88826fcb 100644
--- a/drivers/iio/light/bh1750.c
+++ b/drivers/iio/light/bh1750.c
@@ -22,12 +22,16 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
+#include <linux/gpio/consumer.h>
#define BH1750_POWER_DOWN 0x00
#define BH1750_ONE_TIME_H_RES_MODE 0x20 /* auto-mode for BH1721 */
#define BH1750_CHANGE_INT_TIME_H_BIT 0x40
#define BH1750_CHANGE_INT_TIME_L_BIT 0x60
+/* Define the reset delay time in microseconds */
+#define BH1750_RESET_DELAY_US 10000 /* 10ms */
+
enum {
BH1710,
BH1721,
@@ -40,6 +44,7 @@ struct bh1750_data {
struct mutex lock;
const struct bh1750_chip_info *chip_info;
u16 mtreg;
+ struct gpio_desc *reset_gpio;
};
struct bh1750_chip_info {
@@ -248,6 +253,25 @@ static int bh1750_probe(struct i2c_client *client)
data->client = client;
data->chip_info = &bh1750_chip_info_tbl[id->driver_data];
+ /* Get reset GPIO from device tree */
+ data->reset_gpio = devm_gpiod_get_optional(&client->dev,
+ "reset", GPIOD_OUT_HIGH);
+
+ if (IS_ERR(data->reset_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(data->reset_gpio),
+ "Failed to get reset GPIO\n");
+
+ /* Perform hardware reset if GPIO is provided */
+ if (data->reset_gpio) {
+ /* Perform reset sequence: low-high */
+ gpiod_set_value_cansleep(data->reset_gpio, 1);
+ fsleep(BH1750_RESET_DELAY_US);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
+ fsleep(BH1750_RESET_DELAY_US);
+
+ dev_dbg(&client->dev, "BH1750 reset completed via GPIO\n");
+ }
+
usec = data->chip_info->mtreg_to_usec * data->chip_info->mtreg_default;
ret = bh1750_change_int_time(data, usec);
if (ret < 0)
diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c
index 475f44954f61..c7c877d2fe67 100644
--- a/drivers/iio/light/bh1780.c
+++ b/drivers/iio/light/bh1780.c
@@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(i2c, bh1780_id);
static const struct of_device_id of_bh1780_match[] = {
{ .compatible = "rohm,bh1780gli", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, of_bh1780_match);
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index 5b00ad2a014e..e864d2ef036e 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -369,7 +369,7 @@ static void cm3232_remove(struct i2c_client *client)
static const struct i2c_device_id cm3232_id[] = {
{ "cm3232" },
- {}
+ { }
};
static int cm3232_suspend(struct device *dev)
@@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(i2c, cm3232_id);
static const struct of_device_id cm3232_of_match[] = {
{.compatible = "capella,cm3232"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, cm3232_of_match);
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
index 79a64e2ff812..79ad6e2209ca 100644
--- a/drivers/iio/light/cm3323.c
+++ b/drivers/iio/light/cm3323.c
@@ -251,13 +251,13 @@ static int cm3323_probe(struct i2c_client *client)
static const struct i2c_device_id cm3323_id[] = {
{ "cm3323" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, cm3323_id);
static const struct of_device_id cm3323_of_match[] = {
{ .compatible = "capella,cm3323", },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, cm3323_of_match);
diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c
index 675c0fd44db4..0c17378e27d1 100644
--- a/drivers/iio/light/cm3605.c
+++ b/drivers/iio/light/cm3605.c
@@ -307,7 +307,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cm3605_dev_pm_ops, cm3605_pm_suspend,
static const struct of_device_id cm3605_of_match[] = {
{.compatible = "capella,cm3605"},
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, cm3605_of_match);
diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c
index 19e529c84e95..815806ceb5c8 100644
--- a/drivers/iio/light/cros_ec_light_prox.c
+++ b/drivers/iio/light/cros_ec_light_prox.c
@@ -249,7 +249,7 @@ static const struct platform_device_id cros_ec_light_prox_ids[] = {
{
.name = "cros-ec-light",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
index d56ee217fe53..42859e5b1089 100644
--- a/drivers/iio/light/gp2ap002.c
+++ b/drivers/iio/light/gp2ap002.c
@@ -700,7 +700,7 @@ MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);
static const struct of_device_id gp2ap002_of_match[] = {
{ .compatible = "sharp,gp2ap002a00f" },
{ .compatible = "sharp,gp2ap002s00f" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, gp2ap002_of_match);
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 1a352c88598e..c7df4b258e2c 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -1283,12 +1283,11 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,
int err = -EINVAL;
if (mask == IIO_CHAN_INFO_RAW) {
- err = iio_device_claim_direct_mode(indio_dev);
- if (err)
- return err;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
err = gp2ap020a00f_read_channel(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
}
return err < 0 ? err : IIO_VAL_INT;
}
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index aa4c72d4849e..830e5ae7f34a 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -456,7 +456,7 @@ static const struct platform_device_id hid_als_ids[] = {
/* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-LISS-0041",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_als_ids);
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index 4c65b32d34ce..efa904a70d0e 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -215,6 +215,9 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
case 1:
prox_state->human_presence[chan] = *(u8 *)raw_data * multiplier;
return 0;
+ case 2:
+ prox_state->human_presence[chan] = *(u16 *)raw_data * multiplier;
+ return 0;
case 4:
prox_state->human_presence[chan] = *(u32 *)raw_data * multiplier;
return 0;
@@ -362,7 +365,7 @@ static const struct platform_device_id hid_prox_ids[] = {
/* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-LISS-0226",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_prox_ids);
diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c
index 201eae1c4589..1b4c18423048 100644
--- a/drivers/iio/light/isl29018.c
+++ b/drivers/iio/light/isl29018.c
@@ -824,7 +824,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = {
{"ISL29018", isl29018},
{"ISL29023", isl29023},
{"ISL29035", isl29035},
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match);
@@ -832,7 +832,7 @@ static const struct i2c_device_id isl29018_id[] = {
{"isl29018", isl29018},
{"isl29023", isl29023},
{"isl29035", isl29035},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, isl29018_id);
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
index 95bfb3ffa519..609ebf0f7313 100644
--- a/drivers/iio/light/isl29028.c
+++ b/drivers/iio/light/isl29028.c
@@ -680,7 +680,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(isl29028_pm_ops, isl29028_suspend,
static const struct i2c_device_id isl29028_id[] = {
{ "isl29028" },
{ "isl29030" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, isl29028_id);
@@ -688,7 +688,7 @@ static const struct of_device_id isl29028_of_match[] = {
{ .compatible = "isl,isl29028", }, /* for backward compat., don't use */
{ .compatible = "isil,isl29028", },
{ .compatible = "isil,isl29030", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, isl29028_of_match);
diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c
index 326dc39e7929..6bc23b164cc5 100644
--- a/drivers/iio/light/isl29125.c
+++ b/drivers/iio/light/isl29125.c
@@ -131,11 +131,10 @@ static int isl29125_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = isl29125_read_data(data, chan->scan_index);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
*val = ret;
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
index e7ba934c8e69..fa4677c28931 100644
--- a/drivers/iio/light/jsa1212.c
+++ b/drivers/iio/light/jsa1212.c
@@ -424,7 +424,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend,
static const struct acpi_device_id jsa1212_acpi_match[] = {
{"JSA1212", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c
index df664f360903..ee59bbb8aa09 100644
--- a/drivers/iio/light/ltr390.c
+++ b/drivers/iio/light/ltr390.c
@@ -717,13 +717,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume);
static const struct i2c_device_id ltr390_id[] = {
{ "ltr390" },
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, ltr390_id);
static const struct of_device_id ltr390_of_table[] = {
{ .compatible = "liteon,ltr390" },
- { /* Sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, ltr390_of_table);
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c
index 669da0840eba..8d8051cf6927 100644
--- a/drivers/iio/light/ltr501.c
+++ b/drivers/iio/light/ltr501.c
@@ -541,7 +541,7 @@ static const struct iio_chan_spec_ext_info ltr501_ext_info[] = {
.shared = IIO_SEPARATE,
.read = ltr501_read_near_level,
},
- { /* sentinel */ }
+ { }
};
static const struct iio_event_spec ltr501_als_event_spec[] = {
@@ -646,6 +646,36 @@ static const struct iio_chan_spec ltr301_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+static int ltr501_read_info_raw(struct ltr501_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ __le16 buf[2];
+ int ret;
+
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ mutex_lock(&data->lock_als);
+ ret = ltr501_read_als(data, buf);
+ mutex_unlock(&data->lock_als);
+ if (ret < 0)
+ return ret;
+ *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
+ buf[0] : buf[1]);
+ return IIO_VAL_INT;
+ case IIO_PROXIMITY:
+ mutex_lock(&data->lock_ps);
+ ret = ltr501_read_ps(data);
+ mutex_unlock(&data->lock_ps);
+ if (ret < 0)
+ return ret;
+ *val = ret & LTR501_PS_DATA_MASK;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ltr501_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -658,14 +688,13 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&data->lock_als);
ret = ltr501_read_als(data, buf);
mutex_unlock(&data->lock_als);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
*val = ltr501_calculate_lux(le16_to_cpu(buf[1]),
@@ -675,36 +704,12 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
- switch (chan->type) {
- case IIO_INTENSITY:
- mutex_lock(&data->lock_als);
- ret = ltr501_read_als(data, buf);
- mutex_unlock(&data->lock_als);
- if (ret < 0)
- break;
- *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
- buf[0] : buf[1]);
- ret = IIO_VAL_INT;
- break;
- case IIO_PROXIMITY:
- mutex_lock(&data->lock_ps);
- ret = ltr501_read_ps(data);
- mutex_unlock(&data->lock_ps);
- if (ret < 0)
- break;
- *val = ret & LTR501_PS_DATA_MASK;
- ret = IIO_VAL_INT;
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ ret = ltr501_read_info_raw(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
@@ -756,18 +761,14 @@ static int ltr501_get_gain_index(const struct ltr501_gain *gain, int size,
return -1;
}
-static int ltr501_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+static int __ltr501_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
struct ltr501_data *data = iio_priv(indio_dev);
int i, ret, freq_val, freq_val2;
const struct ltr501_chip_info *info = data->chip_info;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
switch (mask) {
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
@@ -775,53 +776,43 @@ static int ltr501_write_raw(struct iio_dev *indio_dev,
i = ltr501_get_gain_index(info->als_gain,
info->als_gain_tbl_size,
val, val2);
- if (i < 0) {
- ret = -EINVAL;
- break;
- }
+ if (i < 0)
+ return -EINVAL;
data->als_contr &= ~info->als_gain_mask;
data->als_contr |= i << info->als_gain_shift;
- ret = regmap_write(data->regmap, LTR501_ALS_CONTR,
- data->als_contr);
- break;
+ return regmap_write(data->regmap, LTR501_ALS_CONTR,
+ data->als_contr);
case IIO_PROXIMITY:
i = ltr501_get_gain_index(info->ps_gain,
info->ps_gain_tbl_size,
val, val2);
- if (i < 0) {
- ret = -EINVAL;
- break;
- }
+ if (i < 0)
+ return -EINVAL;
+
data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
- ret = regmap_write(data->regmap, LTR501_PS_CONTR,
- data->ps_contr);
- break;
+ return regmap_write(data->regmap, LTR501_PS_CONTR,
+ data->ps_contr);
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
case IIO_CHAN_INFO_INT_TIME:
switch (chan->type) {
case IIO_INTENSITY:
- if (val != 0) {
- ret = -EINVAL;
- break;
- }
+ if (val != 0)
+ return -EINVAL;
+
mutex_lock(&data->lock_als);
ret = ltr501_set_it_time(data, val2);
mutex_unlock(&data->lock_als);
- break;
+ return ret;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
@@ -829,50 +820,61 @@ static int ltr501_write_raw(struct iio_dev *indio_dev,
ret = ltr501_als_read_samp_freq(data, &freq_val,
&freq_val2);
if (ret < 0)
- break;
+ return ret;
ret = ltr501_als_write_samp_freq(data, val, val2);
if (ret < 0)
- break;
+ return ret;
/* update persistence count when changing frequency */
ret = ltr501_write_intr_prst(data, chan->type,
0, data->als_period);
if (ret < 0)
- ret = ltr501_als_write_samp_freq(data, freq_val,
- freq_val2);
- break;
+ /* Do not ovewrite error */
+ ltr501_als_write_samp_freq(data, freq_val,
+ freq_val2);
+ return ret;
case IIO_PROXIMITY:
ret = ltr501_ps_read_samp_freq(data, &freq_val,
&freq_val2);
if (ret < 0)
- break;
+ return ret;
ret = ltr501_ps_write_samp_freq(data, val, val2);
if (ret < 0)
- break;
+ return ret;
/* update persistence count when changing frequency */
ret = ltr501_write_intr_prst(data, chan->type,
0, data->ps_period);
if (ret < 0)
- ret = ltr501_ps_write_samp_freq(data, freq_val,
- freq_val2);
- break;
+ /* Do not overwrite error */
+ ltr501_ps_write_samp_freq(data, freq_val,
+ freq_val2);
+ return ret;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- break;
-
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
+}
+
+static int ltr501_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = __ltr501_write_raw(indio_dev, chan, val, val2, mask);
+
+ iio_device_release_direct(indio_dev);
- iio_device_release_direct_mode(indio_dev);
return ret;
}
@@ -1600,7 +1602,7 @@ static const struct acpi_device_id ltr_acpi_match[] = {
{ "LTER0301", ltr301 },
/* https://www.catalog.update.microsoft.com/Search.aspx?q=lter0303 */
{ "LTER0303", ltr303 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ltr_acpi_match);
@@ -1618,7 +1620,7 @@ static const struct of_device_id ltr501_of_match[] = {
{ .compatible = "liteon,ltr559", },
{ .compatible = "liteon,ltr301", },
{ .compatible = "liteon,ltr303", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ltr501_of_match);
diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c
index dbec1e7cfeb8..61f57a82b872 100644
--- a/drivers/iio/light/ltrf216a.c
+++ b/drivers/iio/light/ltrf216a.c
@@ -554,7 +554,7 @@ static const struct ltr_chip_info ltrf216a_chip_info = {
static const struct i2c_device_id ltrf216a_id[] = {
{ "ltr308", .driver_data = (kernel_ulong_t)&ltr308_chip_info },
{ "ltrf216a", .driver_data = (kernel_ulong_t)&ltrf216a_chip_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ltrf216a_id);
@@ -563,7 +563,7 @@ static const struct of_device_id ltrf216a_of_match[] = {
{ .compatible = "liteon,ltrf216a", .data = &ltrf216a_chip_info },
/* For Valve's Steamdeck device, an ACPI platform using PRP0001 */
{ .compatible = "ltr,ltrf216a", .data = &ltrf216a_chip_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ltrf216a_of_match);
diff --git a/drivers/iio/light/opt4001.c b/drivers/iio/light/opt4001.c
index 6cf60151b3d8..ba4eb82d9bc2 100644
--- a/drivers/iio/light/opt4001.c
+++ b/drivers/iio/light/opt4001.c
@@ -448,7 +448,7 @@ MODULE_DEVICE_TABLE(i2c, opt4001_id);
static const struct of_device_id opt4001_of_match[] = {
{ .compatible = "ti,opt4001-sot-5x3", .data = &opt4001_sot_5x3_info},
{ .compatible = "ti,opt4001-picostar", .data = &opt4001_picostar_info},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, opt4001_of_match);
diff --git a/drivers/iio/light/opt4060.c b/drivers/iio/light/opt4060.c
index ab55f8d2ea0c..f4085020e03e 100644
--- a/drivers/iio/light/opt4060.c
+++ b/drivers/iio/light/opt4060.c
@@ -311,7 +311,7 @@ any_mode_retry:
* concurrently change. And we just keep trying until we get one
* of the modes...
*/
- if (iio_device_claim_direct_mode(indio_dev))
+ if (!iio_device_claim_direct(indio_dev))
goto any_mode_retry;
/*
* This path means that we managed to claim direct mode. In
@@ -320,7 +320,8 @@ any_mode_retry:
*/
ret = opt4060_set_state_common(chip, continuous_sampling,
continuous_irq);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
+ return ret;
} else {
/*
* This path means that we managed to claim buffer mode. In
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index b920bf82c102..8885852bef22 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -456,14 +456,14 @@ static const struct dev_pm_ops pa12203001_pm_ops = {
static const struct acpi_device_id pa12203001_acpi_match[] = {
{ "TXCPA122", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
static const struct i2c_device_id pa12203001_id[] = {
{ "txcpa122" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, pa12203001_id);
diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c
index cc25596cb248..7cec5e943373 100644
--- a/drivers/iio/light/rohm-bu27034.c
+++ b/drivers/iio/light/rohm-bu27034.c
@@ -998,9 +998,8 @@ static int bu27034_read_raw(struct iio_dev *idev,
return -EINVAL;
/* Don't mess with measurement enabling while buffering */
- ret = iio_device_claim_direct_mode(idev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(idev))
+ return -EBUSY;
mutex_lock(&data->mutex);
/*
@@ -1011,7 +1010,7 @@ static int bu27034_read_raw(struct iio_dev *idev,
ret = result_get(data, chan->channel, val);
mutex_unlock(&data->mutex);
- iio_device_release_direct_mode(idev);
+ iio_device_release_direct(idev);
if (ret)
return ret;
@@ -1050,9 +1049,8 @@ static int bu27034_write_raw(struct iio_dev *idev,
struct bu27034_data *data = iio_priv(idev);
int ret;
- ret = iio_device_claim_direct_mode(idev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(idev))
+ return -EBUSY;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -1069,7 +1067,7 @@ static int bu27034_write_raw(struct iio_dev *idev,
break;
}
- iio_device_release_direct_mode(idev);
+ iio_device_release_direct(idev);
return ret;
}
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 2ba917c5c138..92e7552f3e39 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -704,50 +705,58 @@ static int rpr0521_write_ps_offset(struct rpr0521_data *data, int offset)
return ret;
}
+static int rpr0521_read_info_raw(struct rpr0521_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ u8 device_mask;
+ __le16 raw_data;
+ int ret;
+
+ device_mask = rpr0521_data_reg[chan->address].device_mask;
+
+ guard(mutex)(&data->lock);
+ ret = rpr0521_set_power_state(data, true, device_mask);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap,
+ rpr0521_data_reg[chan->address].address,
+ &raw_data, sizeof(raw_data));
+ if (ret < 0) {
+ rpr0521_set_power_state(data, false, device_mask);
+ return ret;
+ }
+
+ ret = rpr0521_set_power_state(data, false, device_mask);
+ if (ret < 0)
+ return ret;
+
+ *val = le16_to_cpu(raw_data);
+
+ return 0;
+}
+
static int rpr0521_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct rpr0521_data *data = iio_priv(indio_dev);
int ret;
- int busy;
- u8 device_mask;
- __le16 raw_data;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
return -EINVAL;
- busy = iio_device_claim_direct_mode(indio_dev);
- if (busy)
+ if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- device_mask = rpr0521_data_reg[chan->address].device_mask;
-
- mutex_lock(&data->lock);
- ret = rpr0521_set_power_state(data, true, device_mask);
- if (ret < 0)
- goto rpr0521_read_raw_out;
-
- ret = regmap_bulk_read(data->regmap,
- rpr0521_data_reg[chan->address].address,
- &raw_data, sizeof(raw_data));
- if (ret < 0) {
- rpr0521_set_power_state(data, false, device_mask);
- goto rpr0521_read_raw_out;
- }
-
- ret = rpr0521_set_power_state(data, false, device_mask);
-
-rpr0521_read_raw_out:
- mutex_unlock(&data->lock);
- iio_device_release_direct_mode(indio_dev);
+ ret = rpr0521_read_info_raw(data, chan, val);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
- *val = le16_to_cpu(raw_data);
-
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
diff --git a/drivers/iio/light/si1145.c b/drivers/iio/light/si1145.c
index 66abda021696..4aa02afd853e 100644
--- a/drivers/iio/light/si1145.c
+++ b/drivers/iio/light/si1145.c
@@ -633,11 +633,10 @@ static int si1145_read_raw(struct iio_dev *indio_dev,
case IIO_VOLTAGE:
case IIO_TEMP:
case IIO_UVINDEX:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = si1145_measure(indio_dev, chan);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -750,18 +749,17 @@ static int si1145_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = si1145_param_set(data, reg1, val);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
/* Set recovery period to one's complement of gain */
ret = si1145_param_set(data, reg2, (~val & 0x07) << 4);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_CURRENT)
@@ -773,19 +771,18 @@ static int si1145_write_raw(struct iio_dev *indio_dev,
reg1 = SI1145_PS_LED_REG(chan->channel);
shift = SI1145_PS_LED_SHIFT(chan->channel);
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = i2c_smbus_read_byte_data(data->client, reg1);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
ret = i2c_smbus_write_byte_data(data->client, reg1,
(ret & ~(0x0f << shift)) |
((val & 0x0f) << shift));
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return si1145_store_samp_freq(data, val);
diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c
index 40a810000df0..124a8f9204a9 100644
--- a/drivers/iio/light/st_uvis25_core.c
+++ b/drivers/iio/light/st_uvis25_core.c
@@ -117,9 +117,8 @@ static int st_uvis25_read_raw(struct iio_dev *iio_dev,
{
int ret;
- ret = iio_device_claim_direct_mode(iio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(iio_dev))
+ return -EBUSY;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED: {
@@ -144,7 +143,7 @@ static int st_uvis25_read_raw(struct iio_dev *iio_dev,
break;
}
- iio_device_release_direct_mode(iio_dev);
+ iio_device_release_direct(iio_dev);
return ret;
}
diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c
index f54282476d11..5d9bb4d9be63 100644
--- a/drivers/iio/light/st_uvis25_i2c.c
+++ b/drivers/iio/light/st_uvis25_i2c.c
@@ -41,13 +41,13 @@ static int st_uvis25_i2c_probe(struct i2c_client *client)
static const struct of_device_id st_uvis25_i2c_of_match[] = {
{ .compatible = "st,uvis25", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match);
static const struct i2c_device_id st_uvis25_i2c_id_table[] = {
{ ST_UVIS25_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table);
diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c
index 18edc6a5a4a4..a5aad74ce73e 100644
--- a/drivers/iio/light/st_uvis25_spi.c
+++ b/drivers/iio/light/st_uvis25_spi.c
@@ -42,13 +42,13 @@ static int st_uvis25_spi_probe(struct spi_device *spi)
static const struct of_device_id st_uvis25_spi_of_match[] = {
{ .compatible = "st,uvis25", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match);
static const struct spi_device_id st_uvis25_spi_id_table[] = {
{ ST_UVIS25_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table);
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index b81cc44db43c..deada9ba4748 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -165,7 +165,7 @@ static const struct iio_chan_spec_ext_info stk3310_ext_info[] = {
.shared = IIO_SEPARATE,
.read = stk3310_read_near_level,
},
- { /* sentinel */ }
+ { }
};
static const struct iio_chan_spec stk3310_channels[] = {
@@ -703,7 +703,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
{ "STK3310" },
{ "STK3311" },
{ "STK3335" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
@@ -711,7 +711,7 @@ static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3013", 0},
{"STK3310", 0},
{"STK3311", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
@@ -721,7 +721,7 @@ static const struct of_device_id stk3310_of_match[] = {
{ .compatible = "sensortek,stk3310", },
{ .compatible = "sensortek,stk3311", },
{ .compatible = "sensortek,stk3335", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, stk3310_of_match);
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index 884e43e4cda4..39268f855c77 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -134,16 +134,15 @@ static int tcs3414_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = tcs3414_req_data(data);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
ret = i2c_smbus_read_word_data(data->client, chan->address);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
*val = ret;
diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c
index 2bd36a344ea5..0f8bf8503edd 100644
--- a/drivers/iio/light/tcs3472.c
+++ b/drivers/iio/light/tcs3472.c
@@ -148,16 +148,15 @@ static int tcs3472_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = tcs3472_req_data(data);
if (ret < 0) {
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
ret = i2c_smbus_read_word_data(data->client, chan->address);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
*val = ret;
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index f1fe7640fce6..f2af1cd7c2d1 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -843,7 +843,7 @@ static const struct i2c_device_id tsl2563_id[] = {
{ "tsl2561", 1 },
{ "tsl2562", 2 },
{ "tsl2563", 3 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tsl2563_id);
@@ -852,7 +852,7 @@ static const struct of_device_id tsl2563_of_match[] = {
{ .compatible = "amstaos,tsl2561" },
{ .compatible = "amstaos,tsl2562" },
{ .compatible = "amstaos,tsl2563" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, tsl2563_of_match);
diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c
index 02ad11611b9c..fc3b0c4226be 100644
--- a/drivers/iio/light/tsl2583.c
+++ b/drivers/iio/light/tsl2583.c
@@ -922,7 +922,7 @@ static const struct i2c_device_id tsl2583_idtable[] = {
{ "tsl2580", 0 },
{ "tsl2581", 1 },
{ "tsl2583", 2 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tsl2583_idtable);
@@ -930,7 +930,7 @@ static const struct of_device_id tsl2583_of_match[] = {
{ .compatible = "amstaos,tsl2580", },
{ .compatible = "amstaos,tsl2581", },
{ .compatible = "amstaos,tsl2583", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, tsl2583_of_match);
diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c
index b81ca6f73f92..08476f193a44 100644
--- a/drivers/iio/light/tsl2591.c
+++ b/drivers/iio/light/tsl2591.c
@@ -1204,7 +1204,7 @@ static int tsl2591_probe(struct i2c_client *client)
static const struct of_device_id tsl2591_of_match[] = {
{ .compatible = "amstaos,tsl2591"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, tsl2591_of_match);
diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c
index 349afdcbe30d..0b171106441a 100644
--- a/drivers/iio/light/tsl2772.c
+++ b/drivers/iio/light/tsl2772.c
@@ -1899,7 +1899,7 @@ static const struct i2c_device_id tsl2772_idtable[] = {
{ "tsl2772", tsl2772 },
{ "tmd2772", tmd2772 },
{ "apds9930", apds9930 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tsl2772_idtable);
@@ -1916,7 +1916,7 @@ static const struct of_device_id tsl2772_of_match[] = {
{ .compatible = "amstaos,tsl2772" },
{ .compatible = "amstaos,tmd2772" },
{ .compatible = "avago,apds9930" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, tsl2772_of_match);
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index c83114aed6b2..61a0957317a1 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -949,21 +949,21 @@ static const struct dev_pm_ops us5182d_pm_ops = {
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" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, us5182d_id);
static const struct of_device_id us5182d_of_match[] = {
{ .compatible = "upisemi,usd5182" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, us5182d_of_match);
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index e19199b17f2e..90e7d4421abf 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -1084,9 +1084,8 @@ static int vcnl4010_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_SCALE:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
/* Protect against event capture. */
if (vcnl4010_is_in_periodic_mode(data)) {
@@ -1096,7 +1095,7 @@ static int vcnl4010_read_raw(struct iio_dev *indio_dev,
mask);
}
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
@@ -1157,9 +1156,8 @@ static int vcnl4010_write_raw(struct iio_dev *indio_dev,
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
/* Protect against event capture. */
if (vcnl4010_is_in_periodic_mode(data)) {
@@ -1183,7 +1181,7 @@ static int vcnl4010_write_raw(struct iio_dev *indio_dev,
}
end:
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -1410,46 +1408,52 @@ static int vcnl4010_read_event_config(struct iio_dev *indio_dev,
}
}
-static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
+static int vcnl4010_config_threshold_enable(struct vcnl4000_data *data)
{
- struct vcnl4000_data *data = iio_priv(indio_dev);
int ret;
- int icr;
- int command;
- if (state) {
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ /* Enable periodic measurement of proximity data. */
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
+ VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN);
+ if (ret < 0)
+ return ret;
- /* Enable periodic measurement of proximity data. */
- command = VCNL4000_SELF_TIMED_EN | VCNL4000_PROX_EN;
+ /*
+ * Enable interrupts on threshold, for proximity data by
+ * default.
+ */
+ return i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL,
+ VCNL4010_INT_THR_EN);
+}
- /*
- * Enable interrupts on threshold, for proximity data by
- * default.
- */
- icr = VCNL4010_INT_THR_EN;
- } else {
- if (!vcnl4010_is_thr_enabled(data))
- return 0;
+static int vcnl4010_config_threshold_disable(struct vcnl4000_data *data)
+{
+ int ret;
- command = 0;
- icr = 0;
- }
+ if (!vcnl4010_is_thr_enabled(data))
+ return 0;
- ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
- command);
+ ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, 0);
if (ret < 0)
- goto end;
+ return ret;
- ret = i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, icr);
+ return i2c_smbus_write_byte_data(data->client, VCNL4010_INT_CTRL, 0);
+}
-end:
- if (state)
- iio_device_release_direct_mode(indio_dev);
+static int vcnl4010_config_threshold(struct iio_dev *indio_dev, bool state)
+{
+ struct vcnl4000_data *data = iio_priv(indio_dev);
+ int ret;
- return ret;
+ if (state) {
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = vcnl4010_config_threshold_enable(data);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ } else {
+ return vcnl4010_config_threshold_disable(data);
+ }
}
static int vcnl4010_write_event_config(struct iio_dev *indio_dev,
@@ -1741,7 +1745,7 @@ static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = {
.shared = IIO_SEPARATE,
.read = vcnl4000_read_near_level,
},
- { /* sentinel */ }
+ { }
};
static const struct iio_event_spec vcnl4000_event_spec[] = {
@@ -2064,7 +2068,7 @@ static const struct of_device_id vcnl_4000_of_match[] = {
.compatible = "vishay,vcnl4200",
.data = (void *)VCNL4200,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
index 67c94be02018..b2bede9d3daa 100644
--- a/drivers/iio/light/vcnl4035.c
+++ b/drivers/iio/light/vcnl4035.c
@@ -156,6 +156,31 @@ static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
return ret;
}
+static int vcnl4035_read_info_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct vcnl4035_data *data = iio_priv(indio_dev);
+ int ret;
+ int raw_data;
+ unsigned int reg;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ if (chan->channel)
+ reg = VCNL4035_ALS_DATA;
+ else
+ reg = VCNL4035_WHITE_DATA;
+ ret = regmap_read(data->regmap, reg, &raw_data);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ *val = raw_data;
+
+ return IIO_VAL_INT;
+}
+
/*
* Device IT INT Time (ms) Scale (lux/step)
* 000 50 0.064
@@ -175,28 +200,13 @@ static int vcnl4035_read_raw(struct iio_dev *indio_dev,
{
struct vcnl4035_data *data = iio_priv(indio_dev);
int ret;
- int raw_data;
- unsigned int reg;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = vcnl4035_set_pm_runtime_state(data, true);
if (ret < 0)
return ret;
-
- ret = iio_device_claim_direct_mode(indio_dev);
- if (!ret) {
- if (chan->channel)
- reg = VCNL4035_ALS_DATA;
- else
- reg = VCNL4035_WHITE_DATA;
- ret = regmap_read(data->regmap, reg, &raw_data);
- iio_device_release_direct_mode(indio_dev);
- if (!ret) {
- *val = raw_data;
- ret = IIO_VAL_INT;
- }
- }
+ ret = vcnl4035_read_info_raw(indio_dev, chan, val);
vcnl4035_set_pm_runtime_state(data, false);
return ret;
case IIO_CHAN_INFO_INT_TIME:
diff --git a/drivers/iio/light/veml6040.c b/drivers/iio/light/veml6040.c
index 216e271001a8..71a594b2ec85 100644
--- a/drivers/iio/light/veml6040.c
+++ b/drivers/iio/light/veml6040.c
@@ -256,13 +256,13 @@ static int veml6040_probe(struct i2c_client *client)
static const struct i2c_device_id veml6040_id_table[] = {
{"veml6040"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, veml6040_id_table);
static const struct of_device_id veml6040_of_match[] = {
{.compatible = "vishay,veml6040"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, veml6040_of_match);
diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c
index 859891e8f115..edbb43407054 100644
--- a/drivers/iio/light/veml6075.c
+++ b/drivers/iio/light/veml6075.c
@@ -458,7 +458,7 @@ MODULE_DEVICE_TABLE(i2c, veml6075_id);
static const struct of_device_id veml6075_of_match[] = {
{ .compatible = "vishay,veml6075" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, veml6075_of_match);
diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c
index 6e2183a4243e..cc4f2e5404aa 100644
--- a/drivers/iio/light/vl6180.c
+++ b/drivers/iio/light/vl6180.c
@@ -745,7 +745,7 @@ static int vl6180_probe(struct i2c_client *client)
static const struct of_device_id vl6180_of_match[] = {
{ .compatible = "st,vl6180", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, vl6180_of_match);
diff --git a/drivers/iio/light/zopt2201.c b/drivers/iio/light/zopt2201.c
index 604be60e92ac..1e5e9bf2935f 100644
--- a/drivers/iio/light/zopt2201.c
+++ b/drivers/iio/light/zopt2201.c
@@ -113,11 +113,13 @@ static const struct {
{ 13, 3125 },
};
-static const struct {
+struct zopt2201_scale {
unsigned int scale, uscale; /* scale factor as integer + micro */
u8 gain; /* gain register value */
u8 res; /* resolution register value */
-} zopt2201_scale_als[] = {
+};
+
+static struct zopt2201_scale zopt2201_scale_als[] = {
{ 19, 200000, 0, 5 },
{ 6, 400000, 1, 5 },
{ 3, 200000, 2, 5 },
@@ -142,11 +144,7 @@ static const struct {
{ 0, 8333, 4, 0 },
};
-static const struct {
- unsigned int scale, uscale; /* scale factor as integer + micro */
- u8 gain; /* gain register value */
- u8 res; /* resolution register value */
-} zopt2201_scale_uvb[] = {
+static struct zopt2201_scale zopt2201_scale_uvb[] = {
{ 0, 460800, 0, 5 },
{ 0, 153600, 1, 5 },
{ 0, 76800, 2, 5 },
@@ -348,16 +346,17 @@ static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
return 0;
}
-static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
+static int zopt2201_write_scale_by_idx(struct zopt2201_data *data, int idx,
+ struct zopt2201_scale *zopt2201_scale_array)
{
int ret;
mutex_lock(&data->lock);
- ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
+ ret = zopt2201_set_resolution(data, zopt2201_scale_array[idx].res);
if (ret < 0)
goto unlock;
- ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
+ ret = zopt2201_set_gain(data, zopt2201_scale_array[idx].gain);
unlock:
mutex_unlock(&data->lock);
@@ -371,29 +370,12 @@ static int zopt2201_write_scale_als(struct zopt2201_data *data,
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
if (val == zopt2201_scale_als[i].scale &&
- val2 == zopt2201_scale_als[i].uscale) {
- return zopt2201_write_scale_als_by_idx(data, i);
- }
+ val2 == zopt2201_scale_als[i].uscale)
+ return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_als);
return -EINVAL;
}
-static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
-{
- int ret;
-
- mutex_lock(&data->lock);
- ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
- if (ret < 0)
- goto unlock;
-
- ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
-
-unlock:
- mutex_unlock(&data->lock);
- return ret;
-}
-
static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
int val, int val2)
{
@@ -402,7 +384,7 @@ static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
if (val == zopt2201_scale_uvb[i].scale &&
val2 == zopt2201_scale_uvb[i].uscale)
- return zopt2201_write_scale_uvb_by_idx(data, i);
+ return zopt2201_write_scale_by_idx(data, i, zopt2201_scale_uvb);
return -EINVAL;
}
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
index c1fc339e85b4..192ba2da94e2 100644
--- a/drivers/iio/magnetometer/af8133j.c
+++ b/drivers/iio/magnetometer/af8133j.c
@@ -370,7 +370,8 @@ static irqreturn_t af8133j_trigger_handler(int irq, void *p)
if (ret)
goto out_done;
- iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &sample, sizeof(sample),
+ timestamp);
out_done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c
index 7bc341c69697..947fe8a475f2 100644
--- a/drivers/iio/magnetometer/ak8974.c
+++ b/drivers/iio/magnetometer/ak8974.c
@@ -673,8 +673,8 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev)
goto out_unlock;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &ak8974->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &ak8974->scan, sizeof(ak8974->scan),
+ iio_get_time_ns(indio_dev));
out_unlock:
mutex_unlock(&ak8974->lock);
@@ -704,7 +704,7 @@ ak8974_get_mount_matrix(const struct iio_dev *indio_dev,
static const struct iio_chan_spec_ext_info ak8974_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8974_get_mount_matrix),
- { },
+ { }
};
#define AK8974_AXIS_CHANNEL(axis, index, bits) \
@@ -1023,14 +1023,14 @@ static const struct i2c_device_id ak8974_id[] = {
{ "ami306" },
{ "ak8974" },
{ "hscdtd008a" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ak8974_id);
static const struct of_device_id ak8974_of_match[] = {
{ .compatible = "asahi-kasei,ak8974", },
{ .compatible = "alps,hscdtd008a", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ak8974_of_match);
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index ef1363126cc2..a1e92b2abffd 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -882,8 +882,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
data->scan.channels[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range);
data->scan.channels[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
return;
@@ -1107,7 +1107,7 @@ static const struct i2c_device_id ak8975_id[] = {
{"ak09912", (kernel_ulong_t)&ak_def_array[AK09912] },
{"ak09916", (kernel_ulong_t)&ak_def_array[AK09916] },
{"ak09918", (kernel_ulong_t)&ak_def_array[AK09918] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ak8975_id);
@@ -1122,7 +1122,7 @@ static const struct of_device_id ak8975_of_match[] = {
{ .compatible = "ak09912", .data = &ak_def_array[AK09912] },
{ .compatible = "asahi-kasei,ak09916", .data = &ak_def_array[AK09916] },
{ .compatible = "asahi-kasei,ak09918", .data = &ak_def_array[AK09918] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ak8975_of_match);
diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c
index 87b60c4e81fa..f72af829715f 100644
--- a/drivers/iio/magnetometer/als31300.c
+++ b/drivers/iio/magnetometer/als31300.c
@@ -245,8 +245,7 @@ static irqreturn_t als31300_trigger_handler(int irq, void *p)
scan.channels[0] = x;
scan.channels[1] = y;
scan.channels[2] = z;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp);
trigger_out:
iio_trigger_notify_done(indio_dev->trig);
@@ -457,7 +456,7 @@ static const struct i2c_device_id als31300_id[] = {
.name = "als31300-2000",
.driver_data = (kernel_ulong_t)&al31300_variant_2000,
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, als31300_id);
@@ -474,7 +473,7 @@ static const struct of_device_id als31300_of_match[] = {
.compatible = "allegromicro,als31300-2000",
.data = &al31300_variant_2000,
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, als31300_of_match);
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index 88bb673e40d8..f9c51ceae011 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -678,8 +678,8 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c
index 8cbeda924bda..b110791f688a 100644
--- a/drivers/iio/magnetometer/bmc150_magn_i2c.c
+++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c
@@ -42,7 +42,7 @@ static const struct i2c_device_id bmc150_magn_i2c_id[] = {
{ "bmc150_magn" },
{ "bmc156_magn" },
{ "bmm150_magn" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmc150_magn_i2c_id);
diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c
index 2d4b8cba32f1..896b1d280731 100644
--- a/drivers/iio/magnetometer/bmc150_magn_spi.c
+++ b/drivers/iio/magnetometer/bmc150_magn_spi.c
@@ -37,7 +37,7 @@ static const struct spi_device_id bmc150_magn_spi_id[] = {
{"bmc150_magn", 0},
{"bmc156_magn", 0},
{"bmm150_magn", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, bmc150_magn_spi_id);
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 97ddaa2a03f6..c673f9323e47 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -563,7 +563,7 @@ static const struct platform_device_id hid_magn_3d_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200083",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids);
diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h
index ffd669b1ee7c..7a3faf7ffed4 100644
--- a/drivers/iio/magnetometer/hmc5843.h
+++ b/drivers/iio/magnetometer/hmc5843.h
@@ -34,7 +34,7 @@ enum hmc5843_ids {
* @regmap: hardware access register maps
* @variant: describe chip variants
* @scan: buffer to pack data for passing to
- * iio_push_to_buffers_with_timestamp()
+ * iio_push_to_buffers_with_ts()
*/
struct hmc5843_data {
struct device *dev;
diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c
index 2fc84310e2cc..fc16ebd314f7 100644
--- a/drivers/iio/magnetometer/hmc5843_core.c
+++ b/drivers/iio/magnetometer/hmc5843_core.c
@@ -452,8 +452,8 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
if (ret < 0)
goto done;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c
index 657a309e2bd5..b41709959e2b 100644
--- a/drivers/iio/magnetometer/hmc5843_i2c.c
+++ b/drivers/iio/magnetometer/hmc5843_i2c.c
@@ -84,7 +84,7 @@ static const struct of_device_id hmc5843_of_match[] = {
{ .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID },
{ .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID },
{ .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, hmc5843_of_match);
diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c
index b7fde331069d..6a55c1559b0d 100644
--- a/drivers/iio/magnetometer/hmc5843_spi.c
+++ b/drivers/iio/magnetometer/hmc5843_spi.c
@@ -60,7 +60,6 @@ static int hmc5843_spi_probe(struct spi_device *spi)
spi->mode = SPI_MODE_3;
spi->max_speed_hz = 8000000;
- spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret)
return ret;
diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c
index 2fe8e97f2cf8..ff09250a06e7 100644
--- a/drivers/iio/magnetometer/mag3110.c
+++ b/drivers/iio/magnetometer/mag3110.c
@@ -9,6 +9,7 @@
* TODO: irq, user offset, oversampling, continuous mode
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
@@ -102,17 +103,12 @@ static int mag3110_read(struct mag3110_data *data, __be16 buf[3])
{
int ret;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
ret = mag3110_request(data);
- if (ret < 0) {
- mutex_unlock(&data->lock);
+ if (ret < 0)
return ret;
- }
- ret = i2c_smbus_read_i2c_block_data(data->client,
- MAG3110_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
- mutex_unlock(&data->lock);
-
- return ret;
+ return i2c_smbus_read_i2c_block_data(data->client, MAG3110_OUT_X,
+ 3 * sizeof(__be16), (u8 *) buf);
}
static ssize_t mag3110_show_int_plus_micros(char *buf,
@@ -231,19 +227,17 @@ static int mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val)
int ret;
int is_active;
- mutex_lock(&data->lock);
+ guard(mutex)(&data->lock);
is_active = mag3110_is_active(data);
- if (is_active < 0) {
- ret = is_active;
- goto fail;
- }
+ if (is_active < 0)
+ return is_active;
/* config can only be changed when in standby */
if (is_active > 0) {
ret = mag3110_standby(data);
if (ret < 0)
- goto fail;
+ return ret;
}
/*
@@ -252,23 +246,52 @@ static int mag3110_change_config(struct mag3110_data *data, u8 reg, u8 val)
*/
ret = mag3110_wait_standby(data);
if (ret < 0)
- goto fail;
+ return ret;
ret = i2c_smbus_write_byte_data(data->client, reg, val);
if (ret < 0)
- goto fail;
+ return ret;
if (is_active > 0) {
ret = mag3110_active(data);
if (ret < 0)
- goto fail;
+ return ret;
}
- ret = 0;
-fail:
- mutex_unlock(&data->lock);
+ return 0;
+}
- return ret;
+static int __mag3110_read_info_raw(struct mag3110_data *data,
+ struct iio_chan_spec const *chan,
+ int *val)
+{
+ __be16 buffer[3];
+ int ret;
+
+ switch (chan->type) {
+ case IIO_MAGN: /* in 0.1 uT / LSB */
+ ret = mag3110_read(data, buffer);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]),
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+
+ case IIO_TEMP: { /* in 1 C / LSB */
+ guard(mutex)(&data->lock);
+ ret = mag3110_request(data);
+ if (ret < 0)
+ return ret;
+ ret = i2c_smbus_read_byte_data(data->client,
+ MAG3110_DIE_TEMP);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
}
static int mag3110_read_raw(struct iio_dev *indio_dev,
@@ -276,46 +299,14 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct mag3110_data *data = iio_priv(indio_dev);
- __be16 buffer[3];
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- switch (chan->type) {
- case IIO_MAGN: /* in 0.1 uT / LSB */
- ret = mag3110_read(data, buffer);
- if (ret < 0)
- goto release;
- *val = sign_extend32(
- be16_to_cpu(buffer[chan->scan_index]),
- chan->scan_type.realbits - 1);
- ret = IIO_VAL_INT;
- break;
- case IIO_TEMP: /* in 1 C / LSB */
- mutex_lock(&data->lock);
- ret = mag3110_request(data);
- if (ret < 0) {
- mutex_unlock(&data->lock);
- goto release;
- }
- ret = i2c_smbus_read_byte_data(data->client,
- MAG3110_DIE_TEMP);
- mutex_unlock(&data->lock);
- if (ret < 0)
- goto release;
- *val = sign_extend32(ret,
- chan->scan_type.realbits - 1);
- ret = IIO_VAL_INT;
- break;
- default:
- ret = -EINVAL;
- }
-release:
- iio_device_release_direct_mode(indio_dev);
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = __mag3110_read_info_raw(data, chan, val);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
@@ -346,24 +337,18 @@ release:
return -EINVAL;
}
-static int mag3110_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+static int __mag3110_write_raw(struct mag3110_data *data,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
- struct mag3110_data *data = iio_priv(indio_dev);
- int rate, ret;
-
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ int rate;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
rate = mag3110_get_samp_freq_index(data, val, val2);
- if (rate < 0) {
- ret = -EINVAL;
- break;
- }
+ if (rate < 0)
+ return -EINVAL;
+
data->ctrl_reg1 &= 0xff & ~MAG3110_CTRL_DR_MASK
& ~MAG3110_CTRL_AC;
data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT;
@@ -371,22 +356,32 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
if (data->sleep_val < 40)
data->ctrl_reg1 |= MAG3110_CTRL_AC;
- ret = mag3110_change_config(data, MAG3110_CTRL_REG1,
- data->ctrl_reg1);
- break;
+ return mag3110_change_config(data, MAG3110_CTRL_REG1,
+ data->ctrl_reg1);
+
case IIO_CHAN_INFO_CALIBBIAS:
- if (val < -10000 || val > 10000) {
- ret = -EINVAL;
- break;
- }
- ret = i2c_smbus_write_word_swapped(data->client,
+ if (val < -10000 || val > 10000)
+ return -EINVAL;
+
+ return i2c_smbus_write_word_swapped(data->client,
MAG3110_OFF_X + 2 * chan->scan_index, val << 1);
- break;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- iio_device_release_direct_mode(indio_dev);
+}
+
+static int mag3110_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mag3110_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = __mag3110_write_raw(data, chan, val, val2, mask);
+ iio_device_release_direct(indio_dev);
+
return ret;
}
@@ -409,8 +404,8 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
data->scan.temperature = ret;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index dd480a4a5f98..e08a57cd6de2 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -556,13 +556,13 @@ MODULE_DEVICE_TABLE(of, mmc35240_of_match);
static const struct acpi_device_id mmc35240_acpi_match[] = {
{"MMC35240", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
static const struct i2c_device_id mmc35240_id[] = {
{ "mmc35240" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mmc35240_id);
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
index c99694a77a14..2b2884425746 100644
--- a/drivers/iio/magnetometer/rm3100-core.c
+++ b/drivers/iio/magnetometer/rm3100-core.c
@@ -399,12 +399,11 @@ static int rm3100_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret < 0)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = rm3100_read_mag(data, chan->scan_index, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
@@ -516,8 +515,8 @@ static irqreturn_t rm3100_trigger_handler(int irq, void *p)
* Always using the same buffer so that we wouldn't need to set the
* paddings to 0 in case of leaking any data.
*/
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, data->buffer, sizeof(data->buffer),
+ pf->timestamp);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/magnetometer/rm3100-spi.c b/drivers/iio/magnetometer/rm3100-spi.c
index dd6d48043740..2f60a41c07f7 100644
--- a/drivers/iio/magnetometer/rm3100-spi.c
+++ b/drivers/iio/magnetometer/rm3100-spi.c
@@ -32,7 +32,6 @@ static int rm3100_probe(struct spi_device *spi)
spi->mode = SPI_MODE_0;
/* Data rates cannot exceed 1Mbits. */
spi->max_speed_hz = 1000000;
- spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret)
return ret;
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index 1672b274768d..ed70e782af5e 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -54,7 +54,7 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lsm303c-magn",
.data = LSM303C_MAGN_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -102,7 +102,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
{ LSM303C_MAGN_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index fe4d0e63133c..68816362bb95 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -49,7 +49,7 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lsm303c-magn",
.data = LSM303C_MAGN_DEV_NAME,
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -94,7 +94,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LSM9DS1_MAGN_DEV_NAME },
{ IIS2MDC_MAGN_DEV_NAME },
{ LSM303C_MAGN_DEV_NAME },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c
index 4187abe12784..2ca5c26f0091 100644
--- a/drivers/iio/magnetometer/tmag5273.c
+++ b/drivers/iio/magnetometer/tmag5273.c
@@ -712,13 +712,13 @@ static DEFINE_RUNTIME_DEV_PM_OPS(tmag5273_pm_ops,
static const struct i2c_device_id tmag5273_id[] = {
{ "tmag5273" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, tmag5273_id);
static const struct of_device_id tmag5273_of_match[] = {
{ .compatible = "ti,tmag5273" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, tmag5273_of_match);
diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c
index 28012b20c64f..340607111d9a 100644
--- a/drivers/iio/magnetometer/yamaha-yas530.c
+++ b/drivers/iio/magnetometer/yamaha-yas530.c
@@ -674,8 +674,8 @@ static void yas5xx_fill_buffer(struct iio_dev *indio_dev)
yas5xx->scan.channels[1] = x;
yas5xx->scan.channels[2] = y;
yas5xx->scan.channels[3] = z;
- iio_push_to_buffers_with_timestamp(indio_dev, &yas5xx->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &yas5xx->scan, sizeof(yas5xx->scan),
+ iio_get_time_ns(indio_dev));
}
static irqreturn_t yas5xx_handle_trigger(int irq, void *p)
@@ -1585,7 +1585,7 @@ static const struct i2c_device_id yas5xx_id[] = {
{"yas532", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas532] },
{"yas533", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas533] },
{"yas537", (kernel_ulong_t)&yas5xx_chip_info_tbl[yas537] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, yas5xx_id);
@@ -1594,7 +1594,7 @@ static const struct of_device_id yas5xx_of_match[] = {
{ .compatible = "yamaha,yas532", &yas5xx_chip_info_tbl[yas532] },
{ .compatible = "yamaha,yas533", &yas5xx_chip_info_tbl[yas533] },
{ .compatible = "yamaha,yas537", &yas5xx_chip_info_tbl[yas537] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, yas5xx_of_match);
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index c309d991490c..b742ca9a99d1 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -448,7 +448,7 @@ static int mux_probe(struct platform_device *pdev)
static const struct of_device_id mux_match[] = {
{ .compatible = "io-channel-mux" },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mux_match);
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 429035b65c65..4e23a598a3fb 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -399,7 +399,7 @@ static const struct platform_device_id hid_incl_3d_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200086",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids);
diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index 96f03988640c..e759f91a710a 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -19,7 +19,7 @@ struct dev_rot_state {
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info quaternion;
struct {
- s32 sampled_vals[4] __aligned(16);
+ s32 sampled_vals[4];
aligned_s64 timestamp;
} scan;
int scale_pre_decml;
@@ -351,7 +351,7 @@ static const struct platform_device_id hid_dev_rot_ids[] = {
/* Geomagnetic orientation(AM) sensor */
.name = "HID-SENSOR-2000c1",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids);
diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
index 423bbb8a3b38..bff7039690ac 100644
--- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c
+++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c
@@ -358,7 +358,7 @@ static const struct platform_device_id hid_hinge_ids[] = {
/* Format: HID-SENSOR-INT-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-INT-020b",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_hinge_ids);
diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c
index b17941e4c2f7..672b1ca3a920 100644
--- a/drivers/iio/potentiometer/ad5272.c
+++ b/drivers/iio/potentiometer/ad5272.c
@@ -199,7 +199,7 @@ static const struct of_device_id ad5272_dt_ids[] = {
{ .compatible = "adi,ad5272-100", .data = (void *)AD5272_100 },
{ .compatible = "adi,ad5274-020", .data = (void *)AD5274_020 },
{ .compatible = "adi,ad5274-100", .data = (void *)AD5274_100 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad5272_dt_ids);
@@ -209,7 +209,7 @@ static const struct i2c_device_id ad5272_id[] = {
{ "ad5272-100", AD5272_100 },
{ "ad5274-020", AD5274_020 },
{ "ad5274-100", AD5274_100 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5272_id);
diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c
index e0526dd0e3cb..5761f69c538a 100644
--- a/drivers/iio/potentiometer/ds1803.c
+++ b/drivers/iio/potentiometer/ds1803.c
@@ -231,7 +231,7 @@ static const struct of_device_id ds1803_dt_ids[] = {
{ .compatible = "maxim,ds1803-050", .data = &ds1803_cfg[DS1803_050] },
{ .compatible = "maxim,ds1803-100", .data = &ds1803_cfg[DS1803_100] },
{ .compatible = "maxim,ds3502", .data = &ds1803_cfg[DS3502] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ds1803_dt_ids);
@@ -240,7 +240,7 @@ static const struct i2c_device_id ds1803_id[] = {
{ "ds1803-050", (kernel_ulong_t)&ds1803_cfg[DS1803_050] },
{ "ds1803-100", (kernel_ulong_t)&ds1803_cfg[DS1803_100] },
{ "ds3502", (kernel_ulong_t)&ds1803_cfg[DS3502] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ds1803_id);
diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c
index c8e2481dadb5..26390be79d02 100644
--- a/drivers/iio/potentiometer/max5432.c
+++ b/drivers/iio/potentiometer/max5432.c
@@ -114,7 +114,7 @@ static const struct of_device_id max5432_dt_ids[] = {
{ .compatible = "maxim,max5433", .data = (void *)MAX5432_OHM_100K },
{ .compatible = "maxim,max5434", .data = (void *)MAX5432_OHM_50K },
{ .compatible = "maxim,max5435", .data = (void *)MAX5432_OHM_100K },
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, max5432_dt_ids);
diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c
index 4838d2e72f53..3b11b991940b 100644
--- a/drivers/iio/potentiometer/max5487.c
+++ b/drivers/iio/potentiometer/max5487.c
@@ -137,7 +137,7 @@ static const struct acpi_device_id max5487_acpi_match[] = {
{ "MAX5487", 10 },
{ "MAX5488", 50 },
{ "MAX5489", 100 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, max5487_acpi_match);
diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c
index 44678d372126..a88bb2231850 100644
--- a/drivers/iio/potentiometer/mcp4018.c
+++ b/drivers/iio/potentiometer/mcp4018.c
@@ -117,7 +117,7 @@ static const struct i2c_device_id mcp4018_id[] = {
MCP4018_ID_TABLE("mcp4019-103", MCP4018_103),
MCP4018_ID_TABLE("mcp4019-503", MCP4018_503),
MCP4018_ID_TABLE("mcp4019-104", MCP4018_104),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, mcp4018_id);
@@ -139,7 +139,7 @@ static const struct of_device_id mcp4018_of_match[] = {
MCP4018_COMPATIBLE("microchip,mcp4019-103", MCP4018_103),
MCP4018_COMPATIBLE("microchip,mcp4019-503", MCP4018_503),
MCP4018_COMPATIBLE("microchip,mcp4019-104", MCP4018_104),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mcp4018_of_match);
diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c
index 2b73c7540209..f35fc4a6c55b 100644
--- a/drivers/iio/potentiometer/mcp41010.c
+++ b/drivers/iio/potentiometer/mcp41010.c
@@ -171,7 +171,7 @@ static const struct of_device_id mcp41010_match[] = {
{ .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] },
{ .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] },
{ .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mcp41010_match);
@@ -182,7 +182,7 @@ static const struct spi_device_id mcp41010_id[] = {
{ "mcp42010", MCP42010 },
{ "mcp42050", MCP42050 },
{ "mcp42100", MCP42100 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, mcp41010_id);
diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c
index 7890c0993ec4..9082b559d029 100644
--- a/drivers/iio/potentiometer/mcp4131.c
+++ b/drivers/iio/potentiometer/mcp4131.c
@@ -403,7 +403,7 @@ static const struct of_device_id mcp4131_dt_ids[] = {
.data = &mcp4131_cfg[MCP426x_503] },
{ .compatible = "microchip,mcp4262-104",
.data = &mcp4131_cfg[MCP426x_104] },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
@@ -472,7 +472,7 @@ static const struct spi_device_id mcp4131_id[] = {
{ "mcp4262-103", MCP426x_103 },
{ "mcp4262-503", MCP426x_503 },
{ "mcp4262-104", MCP426x_104 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, mcp4131_id);
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
index f28880ebd758..9912e91ff7b4 100644
--- a/drivers/iio/potentiometer/mcp4531.c
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -276,7 +276,7 @@ static const struct i2c_device_id mcp4531_id[] = {
MCP4531_ID_TABLE("mcp4662-103", MCP466x_103),
MCP4531_ID_TABLE("mcp4662-503", MCP466x_503),
MCP4531_ID_TABLE("mcp4662-104", MCP466x_104),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(i2c, mcp4531_id);
@@ -350,7 +350,7 @@ static const struct of_device_id mcp4531_of_match[] = {
MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103),
MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503),
MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(of, mcp4531_of_match);
diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c
index 8923ccb0fc4f..a42b57733363 100644
--- a/drivers/iio/potentiometer/tpl0102.c
+++ b/drivers/iio/potentiometer/tpl0102.c
@@ -153,7 +153,7 @@ static const struct i2c_device_id tpl0102_id[] = {
{ "cat5140-104", CAT5140_104 },
{ "tpl0102-104", TPL0102_104 },
{ "tpl0401-103", TPL0401_103 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tpl0102_id);
diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c
index c2c6b2b29867..030498d0b763 100644
--- a/drivers/iio/potentiostat/lmp91000.c
+++ b/drivers/iio/potentiostat/lmp91000.c
@@ -400,14 +400,14 @@ static void lmp91000_remove(struct i2c_client *client)
static const struct of_device_id lmp91000_of_match[] = {
{ .compatible = "ti,lmp91000", },
{ .compatible = "ti,lmp91002", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, lmp91000_of_match);
static const struct i2c_device_id lmp91000_id[] = {
{ "lmp91000" },
{ "lmp91002" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, lmp91000_id);
diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c
index 752a63c06b44..a0d956c3e254 100644
--- a/drivers/iio/pressure/abp060mg.c
+++ b/drivers/iio/pressure/abp060mg.c
@@ -247,7 +247,7 @@ static const struct i2c_device_id abp060mg_id_table[] = {
{ "abp015pd", ABP015PD },
{ "abp030pd", ABP030PD },
{ "abp060pd", ABP060PD },
- { /* empty */ },
+ { }
};
MODULE_DEVICE_TABLE(i2c, abp060mg_id_table);
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index d44ab65c94cb..f37f20776c89 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -46,6 +46,7 @@
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/types.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -1105,9 +1106,13 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
- u32 adc_temp, adc_press, comp_press;
- s32 t_fine, comp_temp;
- s32 *chans = (s32 *)data->sensor_data;
+ u32 adc_temp, adc_press;
+ s32 t_fine;
+ struct {
+ u32 comp_press;
+ s32 comp_temp;
+ aligned_s64 timestamp;
+ } buffer;
int ret;
guard(mutex)(&data->lock);
@@ -1127,7 +1132,7 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p)
goto out;
}
- comp_temp = bmp280_compensate_temp(data, adc_temp);
+ buffer.comp_temp = bmp280_compensate_temp(data, adc_temp);
/* Pressure calculations */
adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0]));
@@ -1137,13 +1142,10 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p)
}
t_fine = bmp280_calc_t_fine(data, adc_temp);
- comp_press = bmp280_compensate_press(data, adc_press, t_fine);
-
- chans[0] = comp_press;
- chans[1] = comp_temp;
+ buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine);
- iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -1225,11 +1227,19 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
- u32 adc_temp, adc_press, adc_humidity, comp_press, comp_humidity;
- s32 t_fine, comp_temp;
- s32 *chans = (s32 *)data->sensor_data;
+ u32 adc_temp, adc_press, adc_humidity;
+ s32 t_fine;
+ struct {
+ u32 comp_press;
+ s32 comp_temp;
+ u32 comp_humidity;
+ aligned_s64 timestamp;
+ } buffer;
int ret;
+ /* Don't leak uninitialized stack to userspace. */
+ memset(&buffer, 0, sizeof(buffer));
+
guard(mutex)(&data->lock);
/* Burst read data registers */
@@ -1247,7 +1257,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p)
goto out;
}
- comp_temp = bmp280_compensate_temp(data, adc_temp);
+ buffer.comp_temp = bmp280_compensate_temp(data, adc_temp);
/* Pressure calculations */
adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0]));
@@ -1257,7 +1267,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p)
}
t_fine = bmp280_calc_t_fine(data, adc_temp);
- comp_press = bmp280_compensate_press(data, adc_press, t_fine);
+ buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine);
/* Humidity calculations */
adc_humidity = get_unaligned_be16(&data->buf[6]);
@@ -1267,14 +1277,11 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p)
goto out;
}
- comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine);
-
- chans[0] = comp_press;
- chans[1] = comp_temp;
- chans[2] = comp_humidity;
+ buffer.comp_humidity = bme280_compensate_humidity(data, adc_humidity,
+ t_fine);
- iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -1899,9 +1906,13 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
- u32 adc_temp, adc_press, comp_press;
- s32 t_fine, comp_temp;
- s32 *chans = (s32 *)data->sensor_data;
+ u32 adc_temp, adc_press;
+ s32 t_fine;
+ struct {
+ u32 comp_press;
+ s32 comp_temp;
+ aligned_s64 timestamp;
+ } buffer;
int ret;
guard(mutex)(&data->lock);
@@ -1921,7 +1932,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
goto out;
}
- comp_temp = bmp380_compensate_temp(data, adc_temp);
+ buffer.comp_temp = bmp380_compensate_temp(data, adc_temp);
/* Pressure calculations */
adc_press = get_unaligned_le24(&data->buf[0]);
@@ -1931,13 +1942,10 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
}
t_fine = bmp380_calc_t_fine(data, adc_temp);
- comp_press = bmp380_compensate_press(data, adc_press, t_fine);
+ buffer.comp_press = bmp380_compensate_press(data, adc_press, t_fine);
- chans[0] = comp_press;
- chans[1] = comp_temp;
-
- iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -2608,7 +2616,12 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
- int ret, offset;
+ struct {
+ __le32 comp_temp;
+ __le32 comp_press;
+ aligned_s64 timestamp;
+ } buffer;
+ int ret;
guard(mutex)(&data->lock);
@@ -2620,18 +2633,14 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p)
goto out;
}
- offset = 0;
-
/* Pressure calculations */
- memcpy(&data->sensor_data[offset], &data->buf[3], 3);
-
- offset += sizeof(s32);
+ memcpy(&buffer.comp_press, &data->buf[3], 3);
/* Temperature calculations */
- memcpy(&data->sensor_data[offset], &data->buf[0], 3);
+ memcpy(&buffer.comp_temp, &data->buf[0], 3);
- iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -2952,25 +2961,26 @@ static irqreturn_t bmp180_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
- int ret, comp_temp, comp_press;
- s32 *chans = (s32 *)data->sensor_data;
+ struct {
+ u32 comp_press;
+ s32 comp_temp;
+ aligned_s64 timestamp;
+ } buffer;
+ int ret;
guard(mutex)(&data->lock);
- ret = bmp180_read_temp(data, &comp_temp);
+ ret = bmp180_read_temp(data, &buffer.comp_temp);
if (ret)
goto out;
- ret = bmp180_read_press(data, &comp_press);
+ ret = bmp180_read_press(data, &buffer.comp_press);
if (ret)
goto out;
- chans[0] = comp_press;
- chans[1] = comp_temp;
-
- iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
out:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c
index 868e1b2ec711..8e459b6c97ff 100644
--- a/drivers/iio/pressure/bmp280-i2c.c
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -33,7 +33,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = {
{ .compatible = "bosch,bme280", .data = &bme280_chip_info },
{ .compatible = "bosch,bmp380", .data = &bmp380_chip_info },
{ .compatible = "bosch,bmp580", .data = &bmp580_chip_info },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
@@ -44,7 +44,7 @@ static const struct i2c_device_id bmp280_i2c_id[] = {
{"bme280", (kernel_ulong_t)&bme280_chip_info },
{"bmp380", (kernel_ulong_t)&bmp380_chip_info },
{"bmp580", (kernel_ulong_t)&bmp580_chip_info },
- { },
+ { }
};
MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index 0e6e27892f99..3b90384f17d7 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -81,14 +81,6 @@ static int bmp280_spi_probe(struct spi_device *spi)
const struct bmp280_chip_info *chip_info;
struct regmap_bus const *bmp_regmap_bus;
struct regmap *regmap;
- int ret;
-
- spi->bits_per_word = 8;
- ret = spi_setup(spi);
- if (ret < 0) {
- dev_err(&spi->dev, "spi_setup failed!\n");
- return ret;
- }
chip_info = spi_get_device_match_data(spi);
@@ -121,7 +113,7 @@ static const struct of_device_id bmp280_of_spi_match[] = {
{ .compatible = "bosch,bme280", .data = &bme280_chip_info },
{ .compatible = "bosch,bmp380", .data = &bmp380_chip_info },
{ .compatible = "bosch,bmp580", .data = &bmp580_chip_info },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 5b2ee1d0ee46..25bb9c743a05 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -349,7 +349,6 @@
BMP280_NUM_TEMP_BYTES + \
BME280_NUM_HUMIDITY_BYTES)
-#define BME280_NUM_MAX_CHANNELS 3
/* Core exported structs */
static const char *const bmp280_supply_names[] = {
@@ -452,13 +451,6 @@ struct bmp280_data {
*/
int sampling_freq;
- /*
- * Data to push to userspace triggered buffer. Up to 3 channels and
- * s64 timestamp, aligned.
- */
- u8 sensor_data[ALIGN(sizeof(s32) * BME280_NUM_MAX_CHANNELS, sizeof(s64))
- + sizeof(s64)] __aligned(sizeof(s64));
-
/* Value to hold the current operation mode of the device */
enum bmp280_op_mode op_mode;
diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c
index 2649c2f89e89..c6b950c596c1 100644
--- a/drivers/iio/pressure/cros_ec_baro.c
+++ b/drivers/iio/pressure/cros_ec_baro.c
@@ -192,7 +192,7 @@ static const struct platform_device_id cros_ec_baro_ids[] = {
{
.name = "cros-ec-baro",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_baro_ids);
diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c
index e99e97ea6300..48afe5c94000 100644
--- a/drivers/iio/pressure/dlhl60d.c
+++ b/drivers/iio/pressure/dlhl60d.c
@@ -147,12 +147,11 @@ static int dlh_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = dlh_read_direct(st, &pressure, &temperature);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
if (ret)
return ret;
@@ -344,14 +343,14 @@ static int dlh_probe(struct i2c_client *client)
static const struct of_device_id dlh_of_match[] = {
{ .compatible = "asc,dlhl60d" },
{ .compatible = "asc,dlhl60g" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, dlh_of_match);
static const struct i2c_device_id dlh_id[] = {
{ "dlhl60d", dlhl60d },
{ "dlhl60g", dlhl60g },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, dlh_id);
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index c6f44f0f4d2e..8edaa4d10a70 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -888,13 +888,13 @@ static int dps310_probe(struct i2c_client *client)
static const struct i2c_device_id dps310_id[] = {
{ DPS310_DEV_NAME },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, dps310_id);
static const struct acpi_device_id dps310_acpi_match[] = {
{ "IFX3100" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, dps310_acpi_match);
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index f7273d30c5f0..5f1d6abda3e4 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -176,8 +176,9 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev,
if (!press_state->timestamp)
press_state->timestamp = iio_get_time_ns(indio_dev);
- iio_push_to_buffers_with_timestamp(
- indio_dev, &press_state->scan, press_state->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &press_state->scan,
+ sizeof(press_state->scan),
+ press_state->timestamp);
}
return 0;
@@ -339,7 +340,7 @@ static const struct platform_device_id hid_press_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200031",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_press_ids);
diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c
index 6f7a16787143..cbb4aaf45e2c 100644
--- a/drivers/iio/pressure/hp03.c
+++ b/drivers/iio/pressure/hp03.c
@@ -273,7 +273,7 @@ MODULE_DEVICE_TABLE(i2c, hp03_id);
static const struct of_device_id hp03_of_match[] = {
{ .compatible = "hoperf,hp03" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, hp03_of_match);
diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c
index 442740941933..abe10ccb6770 100644
--- a/drivers/iio/pressure/hp206c.c
+++ b/drivers/iio/pressure/hp206c.c
@@ -396,13 +396,13 @@ static int hp206c_probe(struct i2c_client *client)
static const struct i2c_device_id hp206c_id[] = {
{"hp206c"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, hp206c_id);
static const struct acpi_device_id hp206c_acpi_match[] = {
{"HOP206C", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c
index 168245818cfe..2d00c0656259 100644
--- a/drivers/iio/pressure/hsc030pa.c
+++ b/drivers/iio/pressure/hsc030pa.c
@@ -314,8 +314,8 @@ static irqreturn_t hsc_trigger_handler(int irq, void *private)
memcpy(&data->scan.chan[0], &data->buffer[0], 2);
memcpy(&data->scan.chan[1], &data->buffer[2], 2);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
error:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c
index 7f2398aa8155..a34ef4653f34 100644
--- a/drivers/iio/pressure/hsc030pa_i2c.c
+++ b/drivers/iio/pressure/hsc030pa_i2c.c
@@ -48,13 +48,13 @@ static int hsc_i2c_probe(struct i2c_client *client)
static const struct of_device_id hsc_i2c_match[] = {
{ .compatible = "honeywell,hsc030pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, hsc_i2c_match);
static const struct i2c_device_id hsc_i2c_id[] = {
{ "hsc030pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, hsc_i2c_id);
diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c
index 60768726e9ad..5d331b3b6da8 100644
--- a/drivers/iio/pressure/hsc030pa_spi.c
+++ b/drivers/iio/pressure/hsc030pa_spi.c
@@ -35,13 +35,13 @@ static int hsc_spi_probe(struct spi_device *spi)
static const struct of_device_id hsc_spi_match[] = {
{ .compatible = "honeywell,hsc030pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, hsc_spi_match);
static const struct spi_device_id hsc_spi_id[] = {
{ "hsc030pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, hsc_spi_id);
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
index 3e0bf5d31ad7..1951c1cc84cf 100644
--- a/drivers/iio/pressure/icp10100.c
+++ b/drivers/iio/pressure/icp10100.c
@@ -343,9 +343,8 @@ static int icp10100_read_raw_measures(struct iio_dev *indio_dev,
uint32_t pressure_mPa;
int ret;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = icp10100_get_measures(st, &raw_pressure, &raw_temp);
if (ret)
@@ -370,7 +369,7 @@ static int icp10100_read_raw_measures(struct iio_dev *indio_dev,
}
error_release:
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -439,7 +438,6 @@ static int icp10100_write_raw(struct iio_dev *indio_dev,
{
struct icp10100_state *st = iio_priv(indio_dev);
unsigned int mode;
- int ret;
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
@@ -449,13 +447,12 @@ static int icp10100_write_raw(struct iio_dev *indio_dev,
mode = ilog2(val);
if (mode >= ICP10100_MODE_NB)
return -EINVAL;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&st->lock);
st->mode = mode;
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return 0;
default:
return -EINVAL;
diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c
index 888cfa666238..4e1d24beff94 100644
--- a/drivers/iio/pressure/mpl115_spi.c
+++ b/drivers/iio/pressure/mpl115_spi.c
@@ -85,7 +85,7 @@ static int mpl115_spi_probe(struct spi_device *spi)
static const struct spi_device_id mpl115_spi_ids[] = {
{ "mpl115", 0 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, mpl115_spi_ids);
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index 71ded2eee060..d6715997f137 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -69,6 +69,52 @@ static int mpl3115_request(struct mpl3115_data *data)
return 0;
}
+static int mpl3115_read_info_raw(struct mpl3115_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
+
+ switch (chan->type) {
+ case IIO_PRESSURE: { /* in 0.25 pascal / LSB */
+ __be32 tmp = 0;
+
+ guard(mutex)(&data->lock);
+ ret = mpl3115_request(data);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_i2c_block_data(data->client,
+ MPL3115_OUT_PRESS,
+ 3, (u8 *) &tmp);
+ if (ret < 0)
+ return ret;
+
+ *val = be32_to_cpu(tmp) >> chan->scan_type.shift;
+ return IIO_VAL_INT;
+ }
+ case IIO_TEMP: { /* in 0.0625 celsius / LSB */
+ __be16 tmp;
+
+ guard(mutex)(&data->lock);
+ ret = mpl3115_request(data);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_i2c_block_data(data->client,
+ MPL3115_OUT_TEMP,
+ 2, (u8 *) &tmp);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
static int mpl3115_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -78,54 +124,11 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
-
- switch (chan->type) {
- case IIO_PRESSURE: { /* in 0.25 pascal / LSB */
- __be32 tmp = 0;
-
- mutex_lock(&data->lock);
- ret = mpl3115_request(data);
- if (ret < 0) {
- mutex_unlock(&data->lock);
- break;
- }
- ret = i2c_smbus_read_i2c_block_data(data->client,
- MPL3115_OUT_PRESS, 3, (u8 *) &tmp);
- mutex_unlock(&data->lock);
- if (ret < 0)
- break;
- *val = be32_to_cpu(tmp) >> chan->scan_type.shift;
- ret = IIO_VAL_INT;
- break;
- }
- case IIO_TEMP: { /* in 0.0625 celsius / LSB */
- __be16 tmp;
-
- mutex_lock(&data->lock);
- ret = mpl3115_request(data);
- if (ret < 0) {
- mutex_unlock(&data->lock);
- break;
- }
- ret = i2c_smbus_read_i2c_block_data(data->client,
- MPL3115_OUT_TEMP, 2, (u8 *) &tmp);
- mutex_unlock(&data->lock);
- if (ret < 0)
- break;
- *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift,
- chan->scan_type.realbits - 1);
- ret = IIO_VAL_INT;
- break;
- }
- default:
- ret = -EINVAL;
- break;
- }
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
- iio_device_release_direct_mode(indio_dev);
+ ret = mpl3115_read_info_raw(data, chan, val);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
@@ -188,8 +191,8 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p)
}
mutex_unlock(&data->lock);
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, buffer, sizeof(buffer),
+ iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c
index 48b23a4256ce..1a48f8d43d71 100644
--- a/drivers/iio/pressure/mprls0025pa_i2c.c
+++ b/drivers/iio/pressure/mprls0025pa_i2c.c
@@ -74,13 +74,13 @@ static int mpr_i2c_probe(struct i2c_client *client)
static const struct of_device_id mpr_i2c_match[] = {
{ .compatible = "honeywell,mprls0025pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mpr_i2c_match);
static const struct i2c_device_id mpr_i2c_id[] = {
{ "mprls0025pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mpr_i2c_id);
diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c
index 09f724c76d70..d04102f8a4a0 100644
--- a/drivers/iio/pressure/mprls0025pa_spi.c
+++ b/drivers/iio/pressure/mprls0025pa_spi.c
@@ -66,13 +66,13 @@ static int mpr_spi_probe(struct spi_device *spi)
static const struct of_device_id mpr_spi_match[] = {
{ .compatible = "honeywell,mprls0025pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mpr_spi_match);
static const struct spi_device_id mpr_spi_id[] = {
{ "mprls0025pa" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, mpr_spi_id);
diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c
index 00c077b2a2a4..bdac27bd5a5d 100644
--- a/drivers/iio/pressure/ms5611_core.c
+++ b/drivers/iio/pressure/ms5611_core.c
@@ -308,7 +308,6 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
{
struct ms5611_state *st = iio_priv(indio_dev);
const struct ms5611_osr *osr = NULL;
- int ret;
if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
return -EINVAL;
@@ -322,9 +321,8 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
if (!osr)
return -EINVAL;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
mutex_lock(&st->lock);
@@ -334,7 +332,7 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
st->pressure_osr = osr;
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return 0;
}
diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c
index b5a91e885793..25c7bd2d8fdf 100644
--- a/drivers/iio/pressure/ms5611_spi.c
+++ b/drivers/iio/pressure/ms5611_spi.c
@@ -92,7 +92,6 @@ static int ms5611_spi_probe(struct spi_device *spi)
spi->mode = SPI_MODE_0;
spi->max_speed_hz = min(spi->max_speed_hz, 20000000U);
- spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0)
return ret;
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index a1767a17fdce..59705a666979 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -219,7 +219,7 @@ static const struct i2c_device_id ms5637_id[] = {
{"ms5805", (kernel_ulong_t)&ms5805_data },
{"ms5837", (kernel_ulong_t)&ms5837_data },
{"ms8607-temppressure", (kernel_ulong_t)&ms8607_data },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ms5637_id);
@@ -229,7 +229,7 @@ static const struct of_device_id ms5637_of_match[] = {
{ .compatible = "meas,ms5805", .data = &ms5805_data },
{ .compatible = "meas,ms5837", .data = &ms5837_data },
{ .compatible = "meas,ms8607-temppressure", .data = &ms8607_data },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, ms5637_of_match);
diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c
index 9c1197f0e742..dac27fd359ad 100644
--- a/drivers/iio/pressure/rohm-bm1390.c
+++ b/drivers/iio/pressure/rohm-bm1390.c
@@ -319,12 +319,11 @@ static int bm1390_read_raw(struct iio_dev *idev,
return -EINVAL;
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(idev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(idev))
+ return -EBUSY;
ret = bm1390_read_data(data, chan, val, val2);
- iio_device_release_direct_mode(idev);
+ iio_device_release_direct(idev);
if (ret)
return ret;
@@ -653,7 +652,8 @@ static irqreturn_t bm1390_trigger_handler(int irq, void *p)
}
}
- iio_push_to_buffers_with_timestamp(idev, &data->buf, data->timestamp);
+ iio_push_to_buffers_with_ts(idev, &data->buf, sizeof(data->buf),
+ data->timestamp);
iio_trigger_notify_done(idev->trig);
return IRQ_HANDLED;
@@ -883,13 +883,13 @@ static int bm1390_probe(struct i2c_client *i2c)
static const struct of_device_id bm1390_of_match[] = {
{ .compatible = "rohm,bm1390glv-z" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, bm1390_of_match);
static const struct i2c_device_id bm1390_id[] = {
{ "bm1390glv-z", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, bm1390_id);
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index b7b66ddc3a73..0f50bac1fb4d 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -50,13 +50,13 @@ static const struct of_device_id st_press_of_match[] = {
.compatible = "st,lps22df",
.data = LPS22DF_PRESS_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_press_of_match);
static const struct acpi_device_id st_press_acpi_match[] = {
{"SNO9210", LPS22HB},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
@@ -69,7 +69,7 @@ static const struct i2c_device_id st_press_id_table[] = {
{ LPS35HW_PRESS_DEV_NAME, LPS35HW },
{ LPS22HH_PRESS_DEV_NAME, LPS22HH },
{ LPS22DF_PRESS_DEV_NAME, LPS22DF },
- {},
+ { }
};
MODULE_DEVICE_TABLE(i2c, st_press_id_table);
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 1a4bd1a0f787..39827e6841ca 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -55,7 +55,7 @@ static const struct of_device_id st_press_of_match[] = {
.compatible = "st,lps22df",
.data = LPS22DF_PRESS_DEV_NAME,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, st_press_of_match);
@@ -106,7 +106,7 @@ static const struct spi_device_id st_press_id_table[] = {
{ "lps25h-press", },
{ "lps331ap-press" },
{ "lps22hb-press" },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, st_press_id_table);
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index 9db1c94dfc18..1640aa3717ed 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -582,7 +582,7 @@ static int zpa2326_fill_sample_buffer(struct iio_dev *indio_dev,
struct {
u32 pressure;
u16 temperature;
- u64 timestamp;
+ aligned_s64 timestamp;
} sample;
int err;
@@ -618,8 +618,8 @@ static int zpa2326_fill_sample_buffer(struct iio_dev *indio_dev,
*/
zpa2326_dbg(indio_dev, "filling raw samples buffer");
- iio_push_to_buffers_with_timestamp(indio_dev, &sample,
- private->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &sample, sizeof(sample),
+ private->timestamp);
return 0;
}
@@ -1062,9 +1062,8 @@ static int zpa2326_sample_oneshot(struct iio_dev *indio_dev,
int ret;
struct zpa2326_private *priv;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = zpa2326_resume(indio_dev);
if (ret < 0)
@@ -1120,7 +1119,7 @@ static int zpa2326_sample_oneshot(struct iio_dev *indio_dev,
suspend:
zpa2326_suspend(indio_dev);
release:
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -1438,7 +1437,6 @@ static int zpa2326_set_frequency(struct iio_dev *indio_dev, int hz)
{
struct zpa2326_private *priv = iio_priv(indio_dev);
int freq;
- int err;
/* Check if requested frequency is supported. */
for (freq = 0; freq < ARRAY_SIZE(zpa2326_sampling_frequencies); freq++)
@@ -1448,13 +1446,12 @@ static int zpa2326_set_frequency(struct iio_dev *indio_dev, int hz)
return -EINVAL;
/* Don't allow changing frequency if buffered sampling is ongoing. */
- err = iio_device_claim_direct_mode(indio_dev);
- if (err)
- return err;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
priv->frequency = &zpa2326_sampling_frequencies[freq];
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return 0;
}
diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c
index c678f5b96266..af756e2b0f31 100644
--- a/drivers/iio/pressure/zpa2326_spi.c
+++ b/drivers/iio/pressure/zpa2326_spi.c
@@ -47,7 +47,6 @@ static int zpa2326_probe_spi(struct spi_device *spi)
*/
spi->mode = SPI_MODE_3;
spi->max_speed_hz = min(spi->max_speed_hz, 1000000U);
- spi->bits_per_word = 8;
err = spi_setup(spi);
if (err < 0)
return err;
@@ -63,7 +62,7 @@ static void zpa2326_remove_spi(struct spi_device *spi)
static const struct spi_device_id zpa2326_spi_ids[] = {
{ "zpa2326", 0 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids);
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index 9d3caf2bef18..f1018b14aecf 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -231,8 +231,8 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private)
goto err_read;
st->scan.chan = val & AS3935_DATA_MASK;
- iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+ iio_get_time_ns(indio_dev));
err_read:
iio_trigger_notify_done(indio_dev->trig);
@@ -444,13 +444,13 @@ static int as3935_probe(struct spi_device *spi)
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},
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, as3935_id);
diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
index 667369be0555..1f9de7066ebf 100644
--- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c
+++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c
@@ -59,16 +59,11 @@ static int cros_ec_mkbp_proximity_parse_state(const void *data)
static int cros_ec_mkbp_proximity_query(struct cros_ec_device *ec_dev,
int *state)
{
- struct {
- struct cros_ec_command msg;
- union {
- struct ec_params_mkbp_info params;
- u32 switches;
- };
- } __packed buf = { };
- struct ec_params_mkbp_info *params = &buf.params;
- struct cros_ec_command *msg = &buf.msg;
- u32 *switches = &buf.switches;
+ DEFINE_RAW_FLEX(struct cros_ec_command, buf, data,
+ MAX(sizeof(u32), sizeof(struct ec_params_mkbp_info)));
+ struct ec_params_mkbp_info *params = (struct ec_params_mkbp_info *)buf->data;
+ struct cros_ec_command *msg = buf;
+ u32 *switches = (u32 *)buf->data;
size_t insize = sizeof(*switches);
int ret;
@@ -250,7 +245,7 @@ static void cros_ec_mkbp_proximity_remove(struct platform_device *pdev)
static const struct of_device_id cros_ec_mkbp_proximity_of_match[] = {
{ .compatible = "google,cros-ec-mkbp-proximity" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, cros_ec_mkbp_proximity_of_match);
diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c
index 5aa8e5a22f32..33781c314728 100644
--- a/drivers/iio/proximity/hx9023s.c
+++ b/drivers/iio/proximity/hx9023s.c
@@ -701,12 +701,11 @@ static int hx9023s_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = hx9023s_get_proximity(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return hx9023s_get_samp_freq(data, val, val2);
@@ -954,8 +953,8 @@ static irqreturn_t hx9023s_trigger_handler(int irq, void *private)
data->buffer.channels[i++] = cpu_to_le16(data->ch_data[index].diff);
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
+ sizeof(data->buffer), pf->timestamp);
out:
iio_trigger_notify_done(indio_dev->trig);
@@ -1191,13 +1190,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(hx9023s_pm_ops, hx9023s_suspend,
static const struct of_device_id hx9023s_of_match[] = {
{ .compatible = "tyhx,hx9023s" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, hx9023s_of_match);
static const struct i2c_device_id hx9023s_id[] = {
{ "hx9023s" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, hx9023s_id);
diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c
index b0ffd3574013..0d30b91dbcbc 100644
--- a/drivers/iio/proximity/irsd200.c
+++ b/drivers/iio/proximity/irsd200.c
@@ -760,15 +760,19 @@ static irqreturn_t irsd200_trigger_handler(int irq, void *pollf)
{
struct iio_dev *indio_dev = ((struct iio_poll_func *)pollf)->indio_dev;
struct irsd200_data *data = iio_priv(indio_dev);
- s64 buf[2] = {};
+ struct {
+ s16 channel;
+ aligned_s64 ts;
+ } scan;
int ret;
- ret = irsd200_read_data(data, (s16 *)buf);
+ memset(&scan, 0, sizeof(scan));
+ ret = irsd200_read_data(data, &scan.channel);
if (ret)
goto end;
- iio_push_to_buffers_with_timestamp(indio_dev, buf,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
end:
iio_trigger_notify_done(indio_dev->trig);
@@ -941,7 +945,7 @@ static const struct of_device_id irsd200_of_match[] = {
{
.compatible = "murata,irsd200",
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, irsd200_of_match);
diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c
index dc66ca9bba6b..d1510fe24050 100644
--- a/drivers/iio/proximity/isl29501.c
+++ b/drivers/iio/proximity/isl29501.c
@@ -481,7 +481,7 @@ static const struct iio_chan_spec_ext_info isl29501_ext_info[] = {
_ISL29501_EXT_INFO("calib_phase_temp_b", REG_CALIB_PHASE_TEMP_B),
_ISL29501_EXT_INFO("calib_phase_light_a", REG_CALIB_PHASE_LIGHT_A),
_ISL29501_EXT_INFO("calib_phase_light_b", REG_CALIB_PHASE_LIGHT_B),
- { },
+ { }
};
#define ISL29501_DISTANCE_SCAN_INDEX 0
@@ -990,7 +990,7 @@ static int isl29501_probe(struct i2c_client *client)
static const struct i2c_device_id isl29501_id[] = {
{ "isl29501" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, isl29501_id);
diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c
index cfc75d001f20..01783486bc7d 100644
--- a/drivers/iio/proximity/mb1232.c
+++ b/drivers/iio/proximity/mb1232.c
@@ -125,8 +125,8 @@ static irqreturn_t mb1232_trigger_handler(int irq, void *p)
if (data->scan.distance < 0)
goto err;
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@@ -239,7 +239,7 @@ static const struct of_device_id of_mb1232_match[] = {
{ .compatible = "maxbotix,mb1242", },
{ .compatible = "maxbotix,mb7040", },
{ .compatible = "maxbotix,mb7137", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, of_mb1232_match);
diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c
index 2ad69b150902..c5b4e1378b7d 100644
--- a/drivers/iio/proximity/ping.c
+++ b/drivers/iio/proximity/ping.c
@@ -268,7 +268,7 @@ static const struct iio_chan_spec ping_chan_spec[] = {
static const struct of_device_id of_ping_match[] = {
{ .compatible = "parallax,ping", .data = &pa_ping_cfg },
{ .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, of_ping_match);
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index f3d054b06b4c..1deaf70e92ce 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -208,7 +208,7 @@ static int lidar_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW: {
u16 reg;
- if (iio_device_claim_direct_mode(indio_dev))
+ if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
ret = lidar_get_measurement(data, &reg);
@@ -216,7 +216,7 @@ static int lidar_read_raw(struct iio_dev *indio_dev,
*val = reg;
ret = IIO_VAL_INT;
}
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
break;
}
case IIO_CHAN_INFO_SCALE:
@@ -238,8 +238,9 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
ret = lidar_get_measurement(data, &data->scan.chan);
if (!ret) {
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan,
+ sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
} else if (ret != -EINVAL) {
dev_err(&data->client->dev, "cannot read LIDAR measurement");
}
diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c
index 71ad29e441b2..b059bac1078b 100644
--- a/drivers/iio/proximity/srf04.c
+++ b/drivers/iio/proximity/srf04.c
@@ -240,7 +240,7 @@ static const struct of_device_id of_srf04_match[] = {
{ .compatible = "maxbotix,mb1020", .data = &mb_lv_cfg },
{ .compatible = "maxbotix,mb1030", .data = &mb_lv_cfg },
{ .compatible = "maxbotix,mb1040", .data = &mb_lv_cfg },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, of_srf04_match);
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
index 86cab113ef3d..6e32fdfd161b 100644
--- a/drivers/iio/proximity/srf08.c
+++ b/drivers/iio/proximity/srf08.c
@@ -191,8 +191,8 @@ static irqreturn_t srf08_trigger_handler(int irq, void *p)
mutex_lock(&data->lock);
data->scan.chan = sensor_data;
- iio_push_to_buffers_with_timestamp(indio_dev,
- &data->scan, pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ pf->timestamp);
mutex_unlock(&data->lock);
err:
@@ -531,7 +531,7 @@ static const struct of_device_id of_srf08_match[] = {
{ .compatible = "devantech,srf02", (void *)SRF02 },
{ .compatible = "devantech,srf08", (void *)SRF08 },
{ .compatible = "devantech,srf10", (void *)SRF10 },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, of_srf08_match);
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index b60707eba39d..fb02eac78ed4 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -995,21 +995,21 @@ static const struct sx931x_info sx9311_info = {
static const struct acpi_device_id sx9310_acpi_match[] = {
{ "STH9310", (kernel_ulong_t)&sx9310_info },
{ "STH9311", (kernel_ulong_t)&sx9311_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
static const struct of_device_id sx9310_of_match[] = {
{ .compatible = "semtech,sx9310", &sx9310_info },
{ .compatible = "semtech,sx9311", &sx9311_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, sx9310_of_match);
static const struct i2c_device_id sx9310_id[] = {
{ "sx9310", (kernel_ulong_t)&sx9310_info },
{ "sx9311", (kernel_ulong_t)&sx9311_info },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, sx9310_id);
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
index 73d972416c01..c7b2d03c23bc 100644
--- a/drivers/iio/proximity/sx9324.c
+++ b/drivers/iio/proximity/sx9324.c
@@ -202,7 +202,7 @@ static const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = {
.shared = IIO_SEPARATE,
.read = sx9324_phase_configuration_show,
},
- {}
+ { }
};
#define SX9324_CHANNEL(idx) \
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index c4e94d0fb163..8913da59dc73 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -387,11 +387,10 @@ static int sx9500_read_raw(struct iio_dev *indio_dev,
case IIO_PROXIMITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = sx9500_read_proximity(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9500_read_samp_freq(data, val, val2);
@@ -866,7 +865,7 @@ static const struct acpi_gpio_mapping acpi_sx9500_gpios[] = {
* GPIO to be output only. Ask the GPIO core to ignore this limit.
*/
{ "interrupt-gpios", &interrupt_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION },
- { },
+ { }
};
static void sx9500_gpio_probe(struct i2c_client *client,
@@ -1031,7 +1030,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sx9500_pm_ops, sx9500_suspend, sx9500_resume);
static const struct acpi_device_id sx9500_acpi_match[] = {
{"SSX9500", 0},
{"SASX9500", 0},
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c
index f70198a1f0d1..59b35e40739b 100644
--- a/drivers/iio/proximity/sx_common.c
+++ b/drivers/iio/proximity/sx_common.c
@@ -379,8 +379,8 @@ static irqreturn_t sx_common_trigger_handler(int irq, void *private)
data->buffer.channels[i++] = val;
}
- iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
- pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &data->buffer,
+ sizeof(data->buffer), pf->timestamp);
out:
mutex_unlock(&data->mutex);
diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c
index bb6c9cc88b35..31e77d9e0c90 100644
--- a/drivers/iio/proximity/vcnl3020.c
+++ b/drivers/iio/proximity/vcnl3020.c
@@ -653,7 +653,7 @@ static const struct of_device_id vcnl3020_of_match[] = {
{
.compatible = "vishay,vcnl3020",
},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, vcnl3020_of_match);
diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c
index 87d10faaff9b..ef4aa7b2835e 100644
--- a/drivers/iio/proximity/vl53l0x-i2c.c
+++ b/drivers/iio/proximity/vl53l0x-i2c.c
@@ -94,8 +94,8 @@ static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv)
return -EREMOTEIO;
data->scan.chan = get_unaligned_be16(&buffer[10]);
- iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
+ iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
vl53l0x_clear_irq(data);
diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c
index 9d95241bdf8f..0bc84f12cb34 100644
--- a/drivers/iio/resolver/ad2s1200.c
+++ b/drivers/iio/resolver/ad2s1200.c
@@ -186,7 +186,7 @@ MODULE_DEVICE_TABLE(of, ad2s1200_of_match);
static const struct spi_device_id ad2s1200_id[] = {
{ "ad2s1200" },
{ "ad2s1205" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad2s1200_id);
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index ab860cedecd1..9b028c8bb1db 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -1340,7 +1340,8 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
}
ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
- iio_push_to_buffers_with_timestamp(indio_dev, &st->scan, pf->timestamp);
+ iio_push_to_buffers_with_ts(indio_dev, &st->scan, sizeof(st->scan),
+ pf->timestamp);
error_ret:
iio_trigger_notify_done(indio_dev->trig);
@@ -1597,7 +1598,7 @@ MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
static const struct spi_device_id ad2s1210_id[] = {
{ "ad2s1210" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad2s1210_id);
diff --git a/drivers/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c
index be6836e55376..18f1c905eeac 100644
--- a/drivers/iio/resolver/ad2s90.c
+++ b/drivers/iio/resolver/ad2s90.c
@@ -105,13 +105,13 @@ static int ad2s90_probe(struct spi_device *spi)
static const struct of_device_id ad2s90_of_match[] = {
{ .compatible = "adi,ad2s90", },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad2s90_of_match);
static const struct spi_device_id ad2s90_id[] = {
{ "ad2s90" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad2s90_id);
diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c
index 692520e1c497..9f628a8e5cfb 100644
--- a/drivers/iio/temperature/hid-sensor-temperature.c
+++ b/drivers/iio/temperature/hid-sensor-temperature.c
@@ -131,8 +131,9 @@ static int temperature_proc_event(struct hid_sensor_hub_device *hsdev,
struct temperature_state *temp_st = iio_priv(indio_dev);
if (atomic_read(&temp_st->common_attributes.data_ready))
- iio_push_to_buffers_with_timestamp(indio_dev, &temp_st->scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &temp_st->scan,
+ sizeof(temp_st->scan),
+ iio_get_time_ns(indio_dev));
return 0;
}
@@ -272,7 +273,7 @@ static const struct platform_device_id hid_temperature_ids[] = {
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200033",
},
- { /* sentinel */ }
+ { }
};
MODULE_DEVICE_TABLE(platform, hid_temperature_ids);
diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c
index f8ea2219ab48..7dd40d69cce6 100644
--- a/drivers/iio/temperature/ltc2983.c
+++ b/drivers/iio/temperature/ltc2983.c
@@ -1664,7 +1664,7 @@ static const struct spi_device_id ltc2983_id_table[] = {
{ "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
{ "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
{ "ltm2985", (kernel_ulong_t)&ltm2985_chip_info_data },
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
@@ -1673,7 +1673,7 @@ static const struct of_device_id ltc2983_of_match[] = {
{ .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
{ .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
{ .compatible = "adi,ltm2985", .data = &ltm2985_chip_info_data },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, ltc2983_of_match);
diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c
index 555a61e2f3fd..cae8e84821d7 100644
--- a/drivers/iio/temperature/maxim_thermocouple.c
+++ b/drivers/iio/temperature/maxim_thermocouple.c
@@ -9,7 +9,6 @@
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
@@ -169,8 +168,9 @@ static irqreturn_t maxim_thermocouple_trigger_handler(int irq, void *private)
ret = spi_read(data->spi, data->buffer, data->chip->read_size);
if (!ret) {
- iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, data->buffer,
+ sizeof(data->buffer),
+ iio_get_time_ns(indio_dev));
}
iio_trigger_notify_done(indio_dev->trig);
@@ -183,40 +183,35 @@ static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct maxim_thermocouple_data *data = iio_priv(indio_dev);
- int ret = -EINVAL;
+ int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
ret = maxim_thermocouple_read(data, chan, val);
- iio_device_release_direct_mode(indio_dev);
-
- if (!ret)
- return IIO_VAL_INT;
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel2) {
case IIO_MOD_TEMP_AMBIENT:
*val = 62;
*val2 = 500000; /* 1000 * 0.0625 */
- ret = IIO_VAL_INT_PLUS_MICRO;
- break;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
*val = 250; /* 1000 * 0.25 */
- ret = IIO_VAL_INT;
+ return IIO_VAL_INT;
}
- break;
case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
*val = data->tc_type;
- ret = IIO_VAL_CHAR;
- break;
+ return IIO_VAL_CHAR;
+ default:
+ return -EINVAL;
}
-
- return ret;
}
static const struct iio_info maxim_thermocouple_info = {
@@ -271,7 +266,7 @@ static const struct spi_device_id maxim_thermocouple_id[] = {
{"max31855t", MAX31855T},
{"max31855e", MAX31855E},
{"max31855r", MAX31855R},
- {},
+ { }
};
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
index c2447860adfd..6e9108d5cf75 100644
--- a/drivers/iio/temperature/mcp9600.c
+++ b/drivers/iio/temperature/mcp9600.c
@@ -449,13 +449,13 @@ static int mcp9600_probe(struct i2c_client *client)
static const struct i2c_device_id mcp9600_id[] = {
{ "mcp9600" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, mcp9600_id);
static const struct of_device_id mcp9600_of_match[] = {
{ .compatible = "microchip,mcp9600" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, mcp9600_of_match);
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
index b5c94b7492f5..29bff9d8859d 100644
--- a/drivers/iio/temperature/tmp006.c
+++ b/drivers/iio/temperature/tmp006.c
@@ -269,8 +269,8 @@ static irqreturn_t tmp006_trigger_handler(int irq, void *p)
goto err;
scan.channels[1] = ret;
- iio_push_to_buffers_with_timestamp(indio_dev, &scan,
- iio_get_time_ns(indio_dev));
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
index fd4d389ce1df..043283b02c4d 100644
--- a/drivers/iio/temperature/tmp007.c
+++ b/drivers/iio/temperature/tmp007.c
@@ -558,7 +558,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
static const struct of_device_id tmp007_of_match[] = {
{ .compatible = "ti,tmp007", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, tmp007_of_match);
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
index cfaa16f46a3f..334bba6fdae6 100644
--- a/drivers/iio/temperature/tsys01.c
+++ b/drivers/iio/temperature/tsys01.c
@@ -207,13 +207,13 @@ static int tsys01_i2c_probe(struct i2c_client *client)
static const struct i2c_device_id tsys01_id[] = {
{ "tsys01" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tsys01_id);
static const struct of_device_id tsys01_of_match[] = {
{ .compatible = "meas,tsys01", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, tsys01_of_match);
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
index ef34b3c58f26..0cad27205667 100644
--- a/drivers/iio/temperature/tsys02d.c
+++ b/drivers/iio/temperature/tsys02d.c
@@ -169,7 +169,7 @@ static int tsys02d_probe(struct i2c_client *client)
static const struct i2c_device_id tsys02d_id[] = {
{ "tsys02d" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, tsys02d_id);
diff --git a/drivers/iio/test/iio-test-format.c b/drivers/iio/test/iio-test-format.c
index fc67e6b73df7..872dd8582003 100644
--- a/drivers/iio/test/iio-test-format.c
+++ b/drivers/iio/test/iio-test-format.c
@@ -257,7 +257,7 @@ static struct kunit_case iio_format_test_cases[] = {
KUNIT_CASE(iio_test_iio_format_value_fractional_log2),
KUNIT_CASE(iio_test_iio_format_value_multiple),
KUNIT_CASE(iio_test_iio_format_value_integer_64),
- {}
+ { }
};
static struct kunit_suite iio_format_test_suite = {
diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c
index 1eceec9d477f..11250bc905c9 100644
--- a/drivers/iio/test/iio-test-gts.c
+++ b/drivers/iio/test/iio-test-gts.c
@@ -499,7 +499,7 @@ static struct kunit_case iio_gts_test_cases[] = {
KUNIT_CASE(test_iio_find_closest_gain_low),
KUNIT_CASE(test_iio_gts_total_gain_to_scale),
KUNIT_CASE(test_iio_gts_avail_test),
- {}
+ { }
};
static struct kunit_suite iio_gts_test_suite = {
diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c
index bbc6a2e1c2c1..ac6942cf1e44 100644
--- a/drivers/iio/test/iio-test-rescale.c
+++ b/drivers/iio/test/iio-test-rescale.c
@@ -704,7 +704,7 @@ static void iio_rescale_test_offset(struct kunit *test)
static struct kunit_case iio_rescale_test_cases[] = {
KUNIT_CASE_PARAM(iio_rescale_test_scale, iio_rescale_scale_gen_params),
KUNIT_CASE_PARAM(iio_rescale_test_offset, iio_rescale_offset_gen_params),
- {}
+ { }
};
static struct kunit_suite iio_rescale_test_suite = {
diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c
index f1e18913236a..2505ace440b4 100644
--- a/drivers/iio/trigger/stm32-lptimer-trigger.c
+++ b/drivers/iio/trigger/stm32-lptimer-trigger.c
@@ -16,16 +16,43 @@
#include <linux/platform_device.h>
#include <linux/property.h>
-/* List Low-Power Timer triggers */
-static const char * const stm32_lptim_triggers[] = {
- LPTIM1_OUT,
- LPTIM2_OUT,
- LPTIM3_OUT,
+/* Maximum triggers + one trailing null entry to indicate the end of array */
+#define MAX_TRIGGERS 3
+
+struct stm32_lptim_cfg {
+ const char * const (*triggers)[MAX_TRIGGERS];
+ unsigned int nb_triggers;
+};
+
+/* List Low-Power Timer triggers for H7, MP13, MP15 */
+static const char * const stm32_lptim_triggers[][MAX_TRIGGERS] = {
+ { LPTIM1_OUT,},
+ { LPTIM2_OUT,},
+ { LPTIM3_OUT,},
+};
+
+/* List Low-Power Timer triggers for STM32MP25 */
+static const char * const stm32mp25_lptim_triggers[][MAX_TRIGGERS] = {
+ { LPTIM1_CH1, LPTIM1_CH2, },
+ { LPTIM2_CH1, LPTIM2_CH2, },
+ { LPTIM3_CH1,},
+ { LPTIM4_CH1,},
+ { LPTIM5_OUT,},
+};
+
+static const struct stm32_lptim_cfg stm32mp15_lptim_cfg = {
+ .triggers = stm32_lptim_triggers,
+ .nb_triggers = ARRAY_SIZE(stm32_lptim_triggers),
+};
+
+static const struct stm32_lptim_cfg stm32mp25_lptim_cfg = {
+ .triggers = stm32mp25_lptim_triggers,
+ .nb_triggers = ARRAY_SIZE(stm32mp25_lptim_triggers),
};
struct stm32_lptim_trigger {
struct device *dev;
- const char *trg;
+ const char * const *triggers;
};
static int stm32_lptim_validate_device(struct iio_trigger *trig,
@@ -56,22 +83,33 @@ EXPORT_SYMBOL(is_stm32_lptim_trigger);
static int stm32_lptim_setup_trig(struct stm32_lptim_trigger *priv)
{
- struct iio_trigger *trig;
+ const char * const *cur = priv->triggers;
+ int ret;
- trig = devm_iio_trigger_alloc(priv->dev, "%s", priv->trg);
- if (!trig)
- return -ENOMEM;
+ while (cur && *cur) {
+ struct iio_trigger *trig;
- trig->dev.parent = priv->dev->parent;
- trig->ops = &stm32_lptim_trigger_ops;
- iio_trigger_set_drvdata(trig, priv);
+ trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
+ if (!trig)
+ return -ENOMEM;
- return devm_iio_trigger_register(priv->dev, trig);
+ trig->dev.parent = priv->dev->parent;
+ trig->ops = &stm32_lptim_trigger_ops;
+ iio_trigger_set_drvdata(trig, priv);
+
+ ret = devm_iio_trigger_register(priv->dev, trig);
+ if (ret)
+ return ret;
+ cur++;
+ }
+
+ return 0;
}
static int stm32_lptim_trigger_probe(struct platform_device *pdev)
{
struct stm32_lptim_trigger *priv;
+ struct stm32_lptim_cfg const *lptim_cfg;
u32 index;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -81,18 +119,21 @@ static int stm32_lptim_trigger_probe(struct platform_device *pdev)
if (device_property_read_u32(&pdev->dev, "reg", &index))
return -EINVAL;
- if (index >= ARRAY_SIZE(stm32_lptim_triggers))
+ lptim_cfg = device_get_match_data(&pdev->dev);
+
+ if (index >= lptim_cfg->nb_triggers)
return -EINVAL;
priv->dev = &pdev->dev;
- priv->trg = stm32_lptim_triggers[index];
+ priv->triggers = lptim_cfg->triggers[index];
return stm32_lptim_setup_trig(priv);
}
static const struct of_device_id stm32_lptim_trig_of_match[] = {
- { .compatible = "st,stm32-lptimer-trigger", },
- {},
+ { .compatible = "st,stm32-lptimer-trigger", .data = &stm32mp15_lptim_cfg },
+ { .compatible = "st,stm32mp25-lptimer-trigger", .data = &stm32mp25_lptim_cfg},
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_lptim_trig_of_match);
diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index e41cb741253b..925b864facca 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -711,7 +711,7 @@ static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = {
IIO_ENUM_AVAILABLE("enable_mode", IIO_SHARED_BY_TYPE, &stm32_enable_mode_enum),
IIO_ENUM("trigger_mode", IIO_SEPARATE, &stm32_trigger_mode_enum),
IIO_ENUM_AVAILABLE("trigger_mode", IIO_SHARED_BY_TYPE, &stm32_trigger_mode_enum),
- {}
+ { }
};
static const struct iio_chan_spec stm32_trigger_channel = {
@@ -921,7 +921,7 @@ static const struct of_device_id stm32_trig_of_match[] = {
.compatible = "st,stm32mp25-timer-trigger",
.data = (void *)&stm32mp25_timer_trg_cfg,
},
- { /* end node */ },
+ { }
};
MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index 9d5404a07e8a..1a41e59c77f8 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -20,6 +20,8 @@
#include "internal.h"
+#define ICC_DYN_ID_START 10000
+
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -826,7 +828,12 @@ static struct icc_node *icc_node_create_nolock(int id)
if (!node)
return ERR_PTR(-ENOMEM);
- id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
+ /* dynamic id allocation */
+ if (id == ICC_ALLOC_DYN_ID)
+ id = idr_alloc(&icc_idr, node, ICC_DYN_ID_START, 0, GFP_KERNEL);
+ else
+ id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
+
if (id < 0) {
WARN(1, "%s: couldn't get idr\n", __func__);
kfree(node);
@@ -839,6 +846,25 @@ static struct icc_node *icc_node_create_nolock(int id)
}
/**
+ * icc_node_create_dyn() - create a node with dynamic id
+ *
+ * Return: icc_node pointer on success, or ERR_PTR() on error
+ */
+struct icc_node *icc_node_create_dyn(void)
+{
+ struct icc_node *node;
+
+ mutex_lock(&icc_lock);
+
+ node = icc_node_create_nolock(ICC_ALLOC_DYN_ID);
+
+ mutex_unlock(&icc_lock);
+
+ return node;
+}
+EXPORT_SYMBOL_GPL(icc_node_create_dyn);
+
+/**
* icc_node_create() - create a node
* @id: node id
*
@@ -885,6 +911,56 @@ void icc_node_destroy(int id)
EXPORT_SYMBOL_GPL(icc_node_destroy);
/**
+ * icc_link_nodes() - create link between two nodes
+ * @src_node: source node
+ * @dst_node: destination node
+ *
+ * Create a link between two nodes. The nodes might belong to different
+ * interconnect providers and the @dst_node might not exist (if the
+ * provider driver has not probed yet). So just create the @dst_node
+ * and when the actual provider driver is probed, the rest of the node
+ * data is filled.
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_link_nodes(struct icc_node *src_node, struct icc_node **dst_node)
+{
+ struct icc_node **new;
+ int ret = 0;
+
+ if (!src_node->provider)
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ if (!*dst_node) {
+ *dst_node = icc_node_create_nolock(ICC_ALLOC_DYN_ID);
+
+ if (IS_ERR(*dst_node)) {
+ ret = PTR_ERR(*dst_node);
+ goto out;
+ }
+ }
+
+ new = krealloc(src_node->links,
+ (src_node->num_links + 1) * sizeof(*src_node->links),
+ GFP_KERNEL);
+ if (!new) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ src_node->links = new;
+ src_node->links[src_node->num_links++] = *dst_node;
+
+out:
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_link_nodes);
+
+/**
* icc_link_create() - create a link between two nodes
* @node: source node id
* @dst_id: destination node id
@@ -962,6 +1038,10 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider)
node->avg_bw = node->init_avg;
node->peak_bw = node->init_peak;
+ if (node->id >= ICC_DYN_ID_START)
+ node->name = devm_kasprintf(provider->dev, GFP_KERNEL, "%s@%s",
+ node->name, dev_name(provider->dev));
+
if (node->avg_bw || node->peak_bw) {
if (provider->pre_aggregate)
provider->pre_aggregate(node);
diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c
index f2d63745be54..41bfc6e7ee1d 100644
--- a/drivers/interconnect/qcom/icc-rpmh.c
+++ b/drivers/interconnect/qcom/icc-rpmh.c
@@ -280,7 +280,14 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
if (!qn)
continue;
- node = icc_node_create(qn->id);
+ if (desc->alloc_dyn_id) {
+ if (!qn->node)
+ qn->node = icc_node_create_dyn();
+ node = qn->node;
+ } else {
+ node = icc_node_create(qn->id);
+ }
+
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err_remove_nodes;
@@ -290,8 +297,12 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
node->data = qn;
icc_node_add(node, provider);
- for (j = 0; j < qn->num_links; j++)
- icc_link_create(node, qn->links[j]);
+ for (j = 0; j < qn->num_links; j++) {
+ if (desc->alloc_dyn_id)
+ icc_link_nodes(node, &qn->link_nodes[j]->node);
+ else
+ icc_link_create(node, qn->links[j]);
+ }
data->nodes[i] = node;
}
diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h
index 82344c734091..bd8d730249b1 100644
--- a/drivers/interconnect/qcom/icc-rpmh.h
+++ b/drivers/interconnect/qcom/icc-rpmh.h
@@ -83,6 +83,8 @@ struct qcom_icc_qosbox {
* @name: the node name used in debugfs
* @links: an array of nodes where we can go next while traversing
* @id: a unique node identifier
+ * @link_nodes: links associated with this node
+ * @node: icc_node associated with this node
* @num_links: the total number of @links
* @channels: num of channels at this node
* @buswidth: width of the interconnect between a node and the bus
@@ -96,6 +98,8 @@ struct qcom_icc_node {
const char *name;
u16 links[MAX_LINKS];
u16 id;
+ struct qcom_icc_node **link_nodes;
+ struct icc_node *node;
u16 num_links;
u16 channels;
u16 buswidth;
@@ -154,6 +158,7 @@ struct qcom_icc_desc {
struct qcom_icc_bcm * const *bcms;
size_t num_bcms;
bool qos_requires_clocks;
+ bool alloc_dyn_id;
};
int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c
index 6a656ed44d49..baecbf2533f7 100644
--- a/drivers/interconnect/qcom/osm-l3.c
+++ b/drivers/interconnect/qcom/osm-l3.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/args.h>
@@ -32,8 +33,6 @@
#define EPSS_REG_FREQ_LUT 0x100
#define EPSS_REG_PERF_STATE 0x320
-#define OSM_L3_MAX_LINKS 1
-
#define to_osm_l3_provider(_provider) \
container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
@@ -48,16 +47,10 @@ struct qcom_osm_l3_icc_provider {
/**
* struct qcom_osm_l3_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
- * @links: an array of nodes where we can go next while traversing
- * @id: a unique node identifier
- * @num_links: the total number of @links
* @buswidth: width of the interconnect between a node and the bus
*/
struct qcom_osm_l3_node {
const char *name;
- u16 links[OSM_L3_MAX_LINKS];
- u16 id;
- u16 num_links;
u16 buswidth;
};
@@ -69,30 +62,22 @@ struct qcom_osm_l3_desc {
unsigned int reg_perf_state;
};
-enum {
- OSM_L3_MASTER_NODE = 10000,
- OSM_L3_SLAVE_NODE,
-};
-
-#define DEFINE_QNODE(_name, _id, _buswidth, ...) \
+#define DEFINE_QNODE(_name, _buswidth) \
static const struct qcom_osm_l3_node _name = { \
.name = #_name, \
- .id = _id, \
.buswidth = _buswidth, \
- .num_links = COUNT_ARGS(__VA_ARGS__), \
- .links = { __VA_ARGS__ }, \
}
-DEFINE_QNODE(osm_l3_master, OSM_L3_MASTER_NODE, 16, OSM_L3_SLAVE_NODE);
-DEFINE_QNODE(osm_l3_slave, OSM_L3_SLAVE_NODE, 16);
+DEFINE_QNODE(osm_l3_slave, 16);
+DEFINE_QNODE(osm_l3_master, 16);
static const struct qcom_osm_l3_node * const osm_l3_nodes[] = {
[MASTER_OSM_L3_APPS] = &osm_l3_master,
[SLAVE_OSM_L3] = &osm_l3_slave,
};
-DEFINE_QNODE(epss_l3_master, OSM_L3_MASTER_NODE, 32, OSM_L3_SLAVE_NODE);
-DEFINE_QNODE(epss_l3_slave, OSM_L3_SLAVE_NODE, 32);
+DEFINE_QNODE(epss_l3_slave, 32);
+DEFINE_QNODE(epss_l3_master, 32);
static const struct qcom_osm_l3_node * const epss_l3_nodes[] = {
[MASTER_EPSS_L3_APPS] = &epss_l3_master,
@@ -242,10 +227,10 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
icc_provider_init(provider);
+ /* Create nodes */
for (i = 0; i < num_nodes; i++) {
- size_t j;
+ node = icc_node_create_dyn();
- node = icc_node_create(qnodes[i]->id);
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err;
@@ -256,12 +241,12 @@ static int qcom_osm_l3_probe(struct platform_device *pdev)
node->data = (void *)qnodes[i];
icc_node_add(node, provider);
- for (j = 0; j < qnodes[i]->num_links; j++)
- icc_link_create(node, qnodes[i]->links[j]);
-
data->nodes[i] = node;
}
+ /* Create link */
+ icc_link_nodes(data->nodes[MASTER_OSM_L3_APPS], &data->nodes[SLAVE_OSM_L3]);
+
ret = icc_provider_register(provider);
if (ret)
goto err;
@@ -278,6 +263,7 @@ err:
static const struct of_device_id osm_l3_of_match[] = {
{ .compatible = "qcom,epss-l3", .data = &epss_l3_l3_vote },
{ .compatible = "qcom,osm-l3", .data = &osm_l3 },
+ { .compatible = "qcom,sa8775p-epss-l3", .data = &epss_l3_perf_state },
{ .compatible = "qcom,sc7180-osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sc7280-epss-l3", .data = &epss_l3_perf_state },
{ .compatible = "qcom,sdm845-osm-l3", .data = &osm_l3 },
diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c
index e2826af3ea2e..04b4abbf4487 100644
--- a/drivers/interconnect/qcom/sa8775p.c
+++ b/drivers/interconnect/qcom/sa8775p.c
@@ -15,1859 +15,1587 @@
#include "bcm-voter.h"
#include "icc-rpmh.h"
-#define SA8775P_MASTER_GPU_TCU 0
-#define SA8775P_MASTER_PCIE_TCU 1
-#define SA8775P_MASTER_SYS_TCU 2
-#define SA8775P_MASTER_APPSS_PROC 3
-#define SA8775P_MASTER_LLCC 4
-#define SA8775P_MASTER_CNOC_LPASS_AG_NOC 5
-#define SA8775P_MASTER_GIC_AHB 6
-#define SA8775P_MASTER_CDSP_NOC_CFG 7
-#define SA8775P_MASTER_CDSPB_NOC_CFG 8
-#define SA8775P_MASTER_QDSS_BAM 9
-#define SA8775P_MASTER_QUP_0 10
-#define SA8775P_MASTER_QUP_1 11
-#define SA8775P_MASTER_QUP_2 12
-#define SA8775P_MASTER_A1NOC_SNOC 13
-#define SA8775P_MASTER_A2NOC_SNOC 14
-#define SA8775P_MASTER_CAMNOC_HF 15
-#define SA8775P_MASTER_CAMNOC_ICP 16
-#define SA8775P_MASTER_CAMNOC_SF 17
-#define SA8775P_MASTER_COMPUTE_NOC 18
-#define SA8775P_MASTER_COMPUTE_NOC_1 19
-#define SA8775P_MASTER_CNOC_A2NOC 20
-#define SA8775P_MASTER_CNOC_DC_NOC 21
-#define SA8775P_MASTER_GEM_NOC_CFG 22
-#define SA8775P_MASTER_GEM_NOC_CNOC 23
-#define SA8775P_MASTER_GEM_NOC_PCIE_SNOC 24
-#define SA8775P_MASTER_GPDSP_SAIL 25
-#define SA8775P_MASTER_GFX3D 26
-#define SA8775P_MASTER_LPASS_ANOC 27
-#define SA8775P_MASTER_MDP0 28
-#define SA8775P_MASTER_MDP1 29
-#define SA8775P_MASTER_MDP_CORE1_0 30
-#define SA8775P_MASTER_MDP_CORE1_1 31
-#define SA8775P_MASTER_MNOC_HF_MEM_NOC 32
-#define SA8775P_MASTER_CNOC_MNOC_HF_CFG 33
-#define SA8775P_MASTER_MNOC_SF_MEM_NOC 34
-#define SA8775P_MASTER_CNOC_MNOC_SF_CFG 35
-#define SA8775P_MASTER_ANOC_PCIE_GEM_NOC 36
-#define SA8775P_MASTER_SNOC_CFG 37
-#define SA8775P_MASTER_SNOC_GC_MEM_NOC 38
-#define SA8775P_MASTER_SNOC_SF_MEM_NOC 39
-#define SA8775P_MASTER_VIDEO_P0 40
-#define SA8775P_MASTER_VIDEO_P1 41
-#define SA8775P_MASTER_VIDEO_PROC 42
-#define SA8775P_MASTER_VIDEO_V_PROC 43
-#define SA8775P_MASTER_QUP_CORE_0 44
-#define SA8775P_MASTER_QUP_CORE_1 45
-#define SA8775P_MASTER_QUP_CORE_2 46
-#define SA8775P_MASTER_QUP_CORE_3 47
-#define SA8775P_MASTER_CRYPTO_CORE0 48
-#define SA8775P_MASTER_CRYPTO_CORE1 49
-#define SA8775P_MASTER_DSP0 50
-#define SA8775P_MASTER_DSP1 51
-#define SA8775P_MASTER_IPA 52
-#define SA8775P_MASTER_LPASS_PROC 53
-#define SA8775P_MASTER_CDSP_PROC 54
-#define SA8775P_MASTER_CDSP_PROC_B 55
-#define SA8775P_MASTER_PIMEM 56
-#define SA8775P_MASTER_QUP_3 57
-#define SA8775P_MASTER_EMAC 58
-#define SA8775P_MASTER_EMAC_1 59
-#define SA8775P_MASTER_GIC 60
-#define SA8775P_MASTER_PCIE_0 61
-#define SA8775P_MASTER_PCIE_1 62
-#define SA8775P_MASTER_QDSS_ETR_0 63
-#define SA8775P_MASTER_QDSS_ETR_1 64
-#define SA8775P_MASTER_SDC 65
-#define SA8775P_MASTER_UFS_CARD 66
-#define SA8775P_MASTER_UFS_MEM 67
-#define SA8775P_MASTER_USB2 68
-#define SA8775P_MASTER_USB3_0 69
-#define SA8775P_MASTER_USB3_1 70
-#define SA8775P_SLAVE_EBI1 512
-#define SA8775P_SLAVE_AHB2PHY_0 513
-#define SA8775P_SLAVE_AHB2PHY_1 514
-#define SA8775P_SLAVE_AHB2PHY_2 515
-#define SA8775P_SLAVE_AHB2PHY_3 516
-#define SA8775P_SLAVE_ANOC_THROTTLE_CFG 517
-#define SA8775P_SLAVE_AOSS 518
-#define SA8775P_SLAVE_APPSS 519
-#define SA8775P_SLAVE_BOOT_ROM 520
-#define SA8775P_SLAVE_CAMERA_CFG 521
-#define SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG 522
-#define SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG 523
-#define SA8775P_SLAVE_CLK_CTL 524
-#define SA8775P_SLAVE_CDSP_CFG 525
-#define SA8775P_SLAVE_CDSP1_CFG 526
-#define SA8775P_SLAVE_RBCPR_CX_CFG 527
-#define SA8775P_SLAVE_RBCPR_MMCX_CFG 528
-#define SA8775P_SLAVE_RBCPR_MX_CFG 529
-#define SA8775P_SLAVE_CPR_NSPCX 530
-#define SA8775P_SLAVE_CRYPTO_0_CFG 531
-#define SA8775P_SLAVE_CX_RDPM 532
-#define SA8775P_SLAVE_DISPLAY_CFG 533
-#define SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG 534
-#define SA8775P_SLAVE_DISPLAY1_CFG 535
-#define SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG 536
-#define SA8775P_SLAVE_EMAC_CFG 537
-#define SA8775P_SLAVE_EMAC1_CFG 538
-#define SA8775P_SLAVE_GP_DSP0_CFG 539
-#define SA8775P_SLAVE_GP_DSP1_CFG 540
-#define SA8775P_SLAVE_GPDSP0_THROTTLE_CFG 541
-#define SA8775P_SLAVE_GPDSP1_THROTTLE_CFG 542
-#define SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG 543
-#define SA8775P_SLAVE_GFX3D_CFG 544
-#define SA8775P_SLAVE_HWKM 545
-#define SA8775P_SLAVE_IMEM_CFG 546
-#define SA8775P_SLAVE_IPA_CFG 547
-#define SA8775P_SLAVE_IPC_ROUTER_CFG 548
-#define SA8775P_SLAVE_LLCC_CFG 549
-#define SA8775P_SLAVE_LPASS 550
-#define SA8775P_SLAVE_LPASS_CORE_CFG 551
-#define SA8775P_SLAVE_LPASS_LPI_CFG 552
-#define SA8775P_SLAVE_LPASS_MPU_CFG 553
-#define SA8775P_SLAVE_LPASS_THROTTLE_CFG 554
-#define SA8775P_SLAVE_LPASS_TOP_CFG 555
-#define SA8775P_SLAVE_MX_RDPM 556
-#define SA8775P_SLAVE_MXC_RDPM 557
-#define SA8775P_SLAVE_PCIE_0_CFG 558
-#define SA8775P_SLAVE_PCIE_1_CFG 559
-#define SA8775P_SLAVE_PCIE_RSC_CFG 560
-#define SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG 561
-#define SA8775P_SLAVE_PCIE_THROTTLE_CFG 562
-#define SA8775P_SLAVE_PDM 563
-#define SA8775P_SLAVE_PIMEM_CFG 564
-#define SA8775P_SLAVE_PKA_WRAPPER_CFG 565
-#define SA8775P_SLAVE_QDSS_CFG 566
-#define SA8775P_SLAVE_QM_CFG 567
-#define SA8775P_SLAVE_QM_MPU_CFG 568
-#define SA8775P_SLAVE_QUP_0 569
-#define SA8775P_SLAVE_QUP_1 570
-#define SA8775P_SLAVE_QUP_2 571
-#define SA8775P_SLAVE_QUP_3 572
-#define SA8775P_SLAVE_SAIL_THROTTLE_CFG 573
-#define SA8775P_SLAVE_SDC1 574
-#define SA8775P_SLAVE_SECURITY 575
-#define SA8775P_SLAVE_SNOC_THROTTLE_CFG 576
-#define SA8775P_SLAVE_TCSR 577
-#define SA8775P_SLAVE_TLMM 578
-#define SA8775P_SLAVE_TSC_CFG 579
-#define SA8775P_SLAVE_UFS_CARD_CFG 580
-#define SA8775P_SLAVE_UFS_MEM_CFG 581
-#define SA8775P_SLAVE_USB2 582
-#define SA8775P_SLAVE_USB3_0 583
-#define SA8775P_SLAVE_USB3_1 584
-#define SA8775P_SLAVE_VENUS_CFG 585
-#define SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG 586
-#define SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG 587
-#define SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG 588
-#define SA8775P_SLAVE_A1NOC_SNOC 589
-#define SA8775P_SLAVE_A2NOC_SNOC 590
-#define SA8775P_SLAVE_DDRSS_CFG 591
-#define SA8775P_SLAVE_GEM_NOC_CNOC 592
-#define SA8775P_SLAVE_GEM_NOC_CFG 593
-#define SA8775P_SLAVE_SNOC_GEM_NOC_GC 594
-#define SA8775P_SLAVE_SNOC_GEM_NOC_SF 595
-#define SA8775P_SLAVE_GP_DSP_SAIL_NOC 596
-#define SA8775P_SLAVE_GPDSP_NOC_CFG 597
-#define SA8775P_SLAVE_HCP_A 598
-#define SA8775P_SLAVE_LLCC 599
-#define SA8775P_SLAVE_MNOC_HF_MEM_NOC 600
-#define SA8775P_SLAVE_MNOC_SF_MEM_NOC 601
-#define SA8775P_SLAVE_CNOC_MNOC_HF_CFG 602
-#define SA8775P_SLAVE_CNOC_MNOC_SF_CFG 603
-#define SA8775P_SLAVE_CDSP_MEM_NOC 604
-#define SA8775P_SLAVE_CDSPB_MEM_NOC 605
-#define SA8775P_SLAVE_HCP_B 606
-#define SA8775P_SLAVE_GEM_NOC_PCIE_CNOC 607
-#define SA8775P_SLAVE_PCIE_ANOC_CFG 608
-#define SA8775P_SLAVE_ANOC_PCIE_GEM_NOC 609
-#define SA8775P_SLAVE_SNOC_CFG 610
-#define SA8775P_SLAVE_LPASS_SNOC 611
-#define SA8775P_SLAVE_QUP_CORE_0 612
-#define SA8775P_SLAVE_QUP_CORE_1 613
-#define SA8775P_SLAVE_QUP_CORE_2 614
-#define SA8775P_SLAVE_QUP_CORE_3 615
-#define SA8775P_SLAVE_BOOT_IMEM 616
-#define SA8775P_SLAVE_IMEM 617
-#define SA8775P_SLAVE_PIMEM 618
-#define SA8775P_SLAVE_SERVICE_NSP_NOC 619
-#define SA8775P_SLAVE_SERVICE_NSPB_NOC 620
-#define SA8775P_SLAVE_SERVICE_GEM_NOC_1 621
-#define SA8775P_SLAVE_SERVICE_MNOC_HF 622
-#define SA8775P_SLAVE_SERVICE_MNOC_SF 623
-#define SA8775P_SLAVE_SERVICES_LPASS_AML_NOC 624
-#define SA8775P_SLAVE_SERVICE_LPASS_AG_NOC 625
-#define SA8775P_SLAVE_SERVICE_GEM_NOC_2 626
-#define SA8775P_SLAVE_SERVICE_SNOC 627
-#define SA8775P_SLAVE_SERVICE_GEM_NOC 628
-#define SA8775P_SLAVE_SERVICE_GEM_NOC2 629
-#define SA8775P_SLAVE_PCIE_0 630
-#define SA8775P_SLAVE_PCIE_1 631
-#define SA8775P_SLAVE_QDSS_STM 632
-#define SA8775P_SLAVE_TCU 633
+static struct qcom_icc_node qxm_qup3;
+static struct qcom_icc_node xm_emac_0;
+static struct qcom_icc_node xm_emac_1;
+static struct qcom_icc_node xm_sdc1;
+static struct qcom_icc_node xm_ufs_mem;
+static struct qcom_icc_node xm_usb2_2;
+static struct qcom_icc_node xm_usb3_0;
+static struct qcom_icc_node xm_usb3_1;
+static struct qcom_icc_node qns_a1noc_snoc;
+static struct qcom_icc_node qhm_qdss_bam;
+static struct qcom_icc_node qhm_qup0;
+static struct qcom_icc_node qhm_qup1;
+static struct qcom_icc_node qhm_qup2;
+static struct qcom_icc_node qnm_cnoc_datapath;
+static struct qcom_icc_node qxm_crypto_0;
+static struct qcom_icc_node qxm_crypto_1;
+static struct qcom_icc_node qxm_ipa;
+static struct qcom_icc_node xm_qdss_etr_0;
+static struct qcom_icc_node xm_qdss_etr_1;
+static struct qcom_icc_node xm_ufs_card;
+static struct qcom_icc_node qns_a2noc_snoc;
+static struct qcom_icc_node qup0_core_master;
+static struct qcom_icc_node qup1_core_master;
+static struct qcom_icc_node qup2_core_master;
+static struct qcom_icc_node qup3_core_master;
+static struct qcom_icc_node qup0_core_slave;
+static struct qcom_icc_node qup1_core_slave;
+static struct qcom_icc_node qup2_core_slave;
+static struct qcom_icc_node qup3_core_slave;
+static struct qcom_icc_node qnm_gemnoc_cnoc;
+static struct qcom_icc_node qnm_gemnoc_pcie;
+static struct qcom_icc_node qhs_ahb2phy0;
+static struct qcom_icc_node qhs_ahb2phy1;
+static struct qcom_icc_node qhs_ahb2phy2;
+static struct qcom_icc_node qhs_ahb2phy3;
+static struct qcom_icc_node qhs_anoc_throttle_cfg;
+static struct qcom_icc_node qhs_aoss;
+static struct qcom_icc_node qhs_apss;
+static struct qcom_icc_node qhs_boot_rom;
+static struct qcom_icc_node qhs_camera_cfg;
+static struct qcom_icc_node qhs_camera_nrt_throttle_cfg;
+static struct qcom_icc_node qhs_camera_rt_throttle_cfg;
+static struct qcom_icc_node qhs_clk_ctl;
+static struct qcom_icc_node qhs_compute0_cfg;
+static struct qcom_icc_node qhs_compute1_cfg;
+static struct qcom_icc_node qhs_cpr_cx;
+static struct qcom_icc_node qhs_cpr_mmcx;
+static struct qcom_icc_node qhs_cpr_mx;
+static struct qcom_icc_node qhs_cpr_nspcx;
+static struct qcom_icc_node qhs_crypto0_cfg;
+static struct qcom_icc_node qhs_cx_rdpm;
+static struct qcom_icc_node qhs_display0_cfg;
+static struct qcom_icc_node qhs_display0_rt_throttle_cfg;
+static struct qcom_icc_node qhs_display1_cfg;
+static struct qcom_icc_node qhs_display1_rt_throttle_cfg;
+static struct qcom_icc_node qhs_emac0_cfg;
+static struct qcom_icc_node qhs_emac1_cfg;
+static struct qcom_icc_node qhs_gp_dsp0_cfg;
+static struct qcom_icc_node qhs_gp_dsp1_cfg;
+static struct qcom_icc_node qhs_gpdsp0_throttle_cfg;
+static struct qcom_icc_node qhs_gpdsp1_throttle_cfg;
+static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg;
+static struct qcom_icc_node qhs_gpuss_cfg;
+static struct qcom_icc_node qhs_hwkm;
+static struct qcom_icc_node qhs_imem_cfg;
+static struct qcom_icc_node qhs_ipa;
+static struct qcom_icc_node qhs_ipc_router;
+static struct qcom_icc_node qhs_lpass_cfg;
+static struct qcom_icc_node qhs_lpass_throttle_cfg;
+static struct qcom_icc_node qhs_mx_rdpm;
+static struct qcom_icc_node qhs_mxc_rdpm;
+static struct qcom_icc_node qhs_pcie0_cfg;
+static struct qcom_icc_node qhs_pcie1_cfg;
+static struct qcom_icc_node qhs_pcie_rsc_cfg;
+static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg;
+static struct qcom_icc_node qhs_pcie_throttle_cfg;
+static struct qcom_icc_node qhs_pdm;
+static struct qcom_icc_node qhs_pimem_cfg;
+static struct qcom_icc_node qhs_pke_wrapper_cfg;
+static struct qcom_icc_node qhs_qdss_cfg;
+static struct qcom_icc_node qhs_qm_cfg;
+static struct qcom_icc_node qhs_qm_mpu_cfg;
+static struct qcom_icc_node qhs_qup0;
+static struct qcom_icc_node qhs_qup1;
+static struct qcom_icc_node qhs_qup2;
+static struct qcom_icc_node qhs_qup3;
+static struct qcom_icc_node qhs_sail_throttle_cfg;
+static struct qcom_icc_node qhs_sdc1;
+static struct qcom_icc_node qhs_security;
+static struct qcom_icc_node qhs_snoc_throttle_cfg;
+static struct qcom_icc_node qhs_tcsr;
+static struct qcom_icc_node qhs_tlmm;
+static struct qcom_icc_node qhs_tsc_cfg;
+static struct qcom_icc_node qhs_ufs_card_cfg;
+static struct qcom_icc_node qhs_ufs_mem_cfg;
+static struct qcom_icc_node qhs_usb2_0;
+static struct qcom_icc_node qhs_usb3_0;
+static struct qcom_icc_node qhs_usb3_1;
+static struct qcom_icc_node qhs_venus_cfg;
+static struct qcom_icc_node qhs_venus_cvp_throttle_cfg;
+static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg;
+static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg;
+static struct qcom_icc_node qns_ddrss_cfg;
+static struct qcom_icc_node qns_gpdsp_noc_cfg;
+static struct qcom_icc_node qns_mnoc_hf_cfg;
+static struct qcom_icc_node qns_mnoc_sf_cfg;
+static struct qcom_icc_node qns_pcie_anoc_cfg;
+static struct qcom_icc_node qns_snoc_cfg;
+static struct qcom_icc_node qxs_boot_imem;
+static struct qcom_icc_node qxs_imem;
+static struct qcom_icc_node qxs_pimem;
+static struct qcom_icc_node xs_pcie_0;
+static struct qcom_icc_node xs_pcie_1;
+static struct qcom_icc_node xs_qdss_stm;
+static struct qcom_icc_node xs_sys_tcu_cfg;
+static struct qcom_icc_node qnm_cnoc_dc_noc;
+static struct qcom_icc_node qhs_llcc;
+static struct qcom_icc_node qns_gemnoc;
+static struct qcom_icc_node alm_gpu_tcu;
+static struct qcom_icc_node alm_pcie_tcu;
+static struct qcom_icc_node alm_sys_tcu;
+static struct qcom_icc_node chm_apps;
+static struct qcom_icc_node qnm_cmpnoc0;
+static struct qcom_icc_node qnm_cmpnoc1;
+static struct qcom_icc_node qnm_gemnoc_cfg;
+static struct qcom_icc_node qnm_gpdsp_sail;
+static struct qcom_icc_node qnm_gpu;
+static struct qcom_icc_node qnm_mnoc_hf;
+static struct qcom_icc_node qnm_mnoc_sf;
+static struct qcom_icc_node qnm_pcie;
+static struct qcom_icc_node qnm_snoc_gc;
+static struct qcom_icc_node qnm_snoc_sf;
+static struct qcom_icc_node qns_gem_noc_cnoc;
+static struct qcom_icc_node qns_llcc;
+static struct qcom_icc_node qns_pcie;
+static struct qcom_icc_node srvc_even_gemnoc;
+static struct qcom_icc_node srvc_odd_gemnoc;
+static struct qcom_icc_node srvc_sys_gemnoc;
+static struct qcom_icc_node srvc_sys_gemnoc_2;
+static struct qcom_icc_node qxm_dsp0;
+static struct qcom_icc_node qxm_dsp1;
+static struct qcom_icc_node qns_gp_dsp_sail_noc;
+static struct qcom_icc_node qhm_config_noc;
+static struct qcom_icc_node qxm_lpass_dsp;
+static struct qcom_icc_node qhs_lpass_core;
+static struct qcom_icc_node qhs_lpass_lpi;
+static struct qcom_icc_node qhs_lpass_mpu;
+static struct qcom_icc_node qhs_lpass_top;
+static struct qcom_icc_node qns_sysnoc;
+static struct qcom_icc_node srvc_niu_aml_noc;
+static struct qcom_icc_node srvc_niu_lpass_agnoc;
+static struct qcom_icc_node llcc_mc;
+static struct qcom_icc_node ebi;
+static struct qcom_icc_node qnm_camnoc_hf;
+static struct qcom_icc_node qnm_camnoc_icp;
+static struct qcom_icc_node qnm_camnoc_sf;
+static struct qcom_icc_node qnm_mdp0_0;
+static struct qcom_icc_node qnm_mdp0_1;
+static struct qcom_icc_node qnm_mdp1_0;
+static struct qcom_icc_node qnm_mdp1_1;
+static struct qcom_icc_node qnm_mnoc_hf_cfg;
+static struct qcom_icc_node qnm_mnoc_sf_cfg;
+static struct qcom_icc_node qnm_video0;
+static struct qcom_icc_node qnm_video1;
+static struct qcom_icc_node qnm_video_cvp;
+static struct qcom_icc_node qnm_video_v_cpu;
+static struct qcom_icc_node qns_mem_noc_hf;
+static struct qcom_icc_node qns_mem_noc_sf;
+static struct qcom_icc_node srvc_mnoc_hf;
+static struct qcom_icc_node srvc_mnoc_sf;
+static struct qcom_icc_node qhm_nsp_noc_config;
+static struct qcom_icc_node qxm_nsp;
+static struct qcom_icc_node qns_hcp;
+static struct qcom_icc_node qns_nsp_gemnoc;
+static struct qcom_icc_node service_nsp_noc;
+static struct qcom_icc_node qhm_nspb_noc_config;
+static struct qcom_icc_node qxm_nspb;
+static struct qcom_icc_node qns_nspb_gemnoc;
+static struct qcom_icc_node qns_nspb_hcp;
+static struct qcom_icc_node service_nspb_noc;
+static struct qcom_icc_node xm_pcie3_0;
+static struct qcom_icc_node xm_pcie3_1;
+static struct qcom_icc_node qns_pcie_mem_noc;
+static struct qcom_icc_node qhm_gic;
+static struct qcom_icc_node qnm_aggre1_noc;
+static struct qcom_icc_node qnm_aggre2_noc;
+static struct qcom_icc_node qnm_lpass_noc;
+static struct qcom_icc_node qnm_snoc_cfg;
+static struct qcom_icc_node qxm_pimem;
+static struct qcom_icc_node xm_gic;
+static struct qcom_icc_node qns_gemnoc_gc;
+static struct qcom_icc_node qns_gemnoc_sf;
+static struct qcom_icc_node srvc_snoc;
static struct qcom_icc_node qxm_qup3 = {
.name = "qxm_qup3",
- .id = SA8775P_MASTER_QUP_3,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_emac_0 = {
.name = "xm_emac_0",
- .id = SA8775P_MASTER_EMAC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_emac_1 = {
.name = "xm_emac_1",
- .id = SA8775P_MASTER_EMAC_1,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_sdc1 = {
.name = "xm_sdc1",
- .id = SA8775P_MASTER_SDC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_ufs_mem = {
.name = "xm_ufs_mem",
- .id = SA8775P_MASTER_UFS_MEM,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_usb2_2 = {
.name = "xm_usb2_2",
- .id = SA8775P_MASTER_USB2,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_usb3_0 = {
.name = "xm_usb3_0",
- .id = SA8775P_MASTER_USB3_0,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node xm_usb3_1 = {
.name = "xm_usb3_1",
- .id = SA8775P_MASTER_USB3_1,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a1noc_snoc },
};
static struct qcom_icc_node qhm_qdss_bam = {
.name = "qhm_qdss_bam",
- .id = SA8775P_MASTER_QDSS_BAM,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qhm_qup0 = {
.name = "qhm_qup0",
- .id = SA8775P_MASTER_QUP_0,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qhm_qup1 = {
.name = "qhm_qup1",
- .id = SA8775P_MASTER_QUP_1,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qhm_qup2 = {
.name = "qhm_qup2",
- .id = SA8775P_MASTER_QUP_2,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qnm_cnoc_datapath = {
.name = "qnm_cnoc_datapath",
- .id = SA8775P_MASTER_CNOC_A2NOC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qxm_crypto_0 = {
.name = "qxm_crypto_0",
- .id = SA8775P_MASTER_CRYPTO_CORE0,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qxm_crypto_1 = {
.name = "qxm_crypto_1",
- .id = SA8775P_MASTER_CRYPTO_CORE1,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qxm_ipa = {
.name = "qxm_ipa",
- .id = SA8775P_MASTER_IPA,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node xm_qdss_etr_0 = {
.name = "xm_qdss_etr_0",
- .id = SA8775P_MASTER_QDSS_ETR_0,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node xm_qdss_etr_1 = {
.name = "xm_qdss_etr_1",
- .id = SA8775P_MASTER_QDSS_ETR_1,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node xm_ufs_card = {
.name = "xm_ufs_card",
- .id = SA8775P_MASTER_UFS_CARD,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_a2noc_snoc },
};
static struct qcom_icc_node qup0_core_master = {
.name = "qup0_core_master",
- .id = SA8775P_MASTER_QUP_CORE_0,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_QUP_CORE_0 },
+ .link_nodes = (struct qcom_icc_node *[]) { &qup0_core_slave },
};
static struct qcom_icc_node qup1_core_master = {
.name = "qup1_core_master",
- .id = SA8775P_MASTER_QUP_CORE_1,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_QUP_CORE_1 },
+ .link_nodes = (struct qcom_icc_node *[]) { &qup1_core_slave },
};
static struct qcom_icc_node qup2_core_master = {
.name = "qup2_core_master",
- .id = SA8775P_MASTER_QUP_CORE_2,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_QUP_CORE_2 },
+ .link_nodes = (struct qcom_icc_node *[]) { &qup2_core_slave },
};
static struct qcom_icc_node qup3_core_master = {
.name = "qup3_core_master",
- .id = SA8775P_MASTER_QUP_CORE_3,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_QUP_CORE_3 },
+ .link_nodes = (struct qcom_icc_node *[]) { &qup3_core_slave },
};
static struct qcom_icc_node qnm_gemnoc_cnoc = {
.name = "qnm_gemnoc_cnoc",
- .id = SA8775P_MASTER_GEM_NOC_CNOC,
.channels = 1,
.buswidth = 16,
.num_links = 82,
- .links = { SA8775P_SLAVE_AHB2PHY_0,
- SA8775P_SLAVE_AHB2PHY_1,
- SA8775P_SLAVE_AHB2PHY_2,
- SA8775P_SLAVE_AHB2PHY_3,
- SA8775P_SLAVE_ANOC_THROTTLE_CFG,
- SA8775P_SLAVE_AOSS,
- SA8775P_SLAVE_APPSS,
- SA8775P_SLAVE_BOOT_ROM,
- SA8775P_SLAVE_CAMERA_CFG,
- SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG,
- SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG,
- SA8775P_SLAVE_CLK_CTL,
- SA8775P_SLAVE_CDSP_CFG,
- SA8775P_SLAVE_CDSP1_CFG,
- SA8775P_SLAVE_RBCPR_CX_CFG,
- SA8775P_SLAVE_RBCPR_MMCX_CFG,
- SA8775P_SLAVE_RBCPR_MX_CFG,
- SA8775P_SLAVE_CPR_NSPCX,
- SA8775P_SLAVE_CRYPTO_0_CFG,
- SA8775P_SLAVE_CX_RDPM,
- SA8775P_SLAVE_DISPLAY_CFG,
- SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG,
- SA8775P_SLAVE_DISPLAY1_CFG,
- SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG,
- SA8775P_SLAVE_EMAC_CFG,
- SA8775P_SLAVE_EMAC1_CFG,
- SA8775P_SLAVE_GP_DSP0_CFG,
- SA8775P_SLAVE_GP_DSP1_CFG,
- SA8775P_SLAVE_GPDSP0_THROTTLE_CFG,
- SA8775P_SLAVE_GPDSP1_THROTTLE_CFG,
- SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG,
- SA8775P_SLAVE_GFX3D_CFG,
- SA8775P_SLAVE_HWKM,
- SA8775P_SLAVE_IMEM_CFG,
- SA8775P_SLAVE_IPA_CFG,
- SA8775P_SLAVE_IPC_ROUTER_CFG,
- SA8775P_SLAVE_LPASS,
- SA8775P_SLAVE_LPASS_THROTTLE_CFG,
- SA8775P_SLAVE_MX_RDPM,
- SA8775P_SLAVE_MXC_RDPM,
- SA8775P_SLAVE_PCIE_0_CFG,
- SA8775P_SLAVE_PCIE_1_CFG,
- SA8775P_SLAVE_PCIE_RSC_CFG,
- SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG,
- SA8775P_SLAVE_PCIE_THROTTLE_CFG,
- SA8775P_SLAVE_PDM,
- SA8775P_SLAVE_PIMEM_CFG,
- SA8775P_SLAVE_PKA_WRAPPER_CFG,
- SA8775P_SLAVE_QDSS_CFG,
- SA8775P_SLAVE_QM_CFG,
- SA8775P_SLAVE_QM_MPU_CFG,
- SA8775P_SLAVE_QUP_0,
- SA8775P_SLAVE_QUP_1,
- SA8775P_SLAVE_QUP_2,
- SA8775P_SLAVE_QUP_3,
- SA8775P_SLAVE_SAIL_THROTTLE_CFG,
- SA8775P_SLAVE_SDC1,
- SA8775P_SLAVE_SECURITY,
- SA8775P_SLAVE_SNOC_THROTTLE_CFG,
- SA8775P_SLAVE_TCSR,
- SA8775P_SLAVE_TLMM,
- SA8775P_SLAVE_TSC_CFG,
- SA8775P_SLAVE_UFS_CARD_CFG,
- SA8775P_SLAVE_UFS_MEM_CFG,
- SA8775P_SLAVE_USB2,
- SA8775P_SLAVE_USB3_0,
- SA8775P_SLAVE_USB3_1,
- SA8775P_SLAVE_VENUS_CFG,
- SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG,
- SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG,
- SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG,
- SA8775P_SLAVE_DDRSS_CFG,
- SA8775P_SLAVE_GPDSP_NOC_CFG,
- SA8775P_SLAVE_CNOC_MNOC_HF_CFG,
- SA8775P_SLAVE_CNOC_MNOC_SF_CFG,
- SA8775P_SLAVE_PCIE_ANOC_CFG,
- SA8775P_SLAVE_SNOC_CFG,
- SA8775P_SLAVE_BOOT_IMEM,
- SA8775P_SLAVE_IMEM,
- SA8775P_SLAVE_PIMEM,
- SA8775P_SLAVE_QDSS_STM,
- SA8775P_SLAVE_TCU
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhs_ahb2phy0, &qhs_ahb2phy1,
+ &qhs_ahb2phy2, &qhs_ahb2phy3,
+ &qhs_anoc_throttle_cfg, &qhs_aoss,
+ &qhs_apss, &qhs_boot_rom,
+ &qhs_camera_cfg, &qhs_camera_nrt_throttle_cfg,
+ &qhs_camera_rt_throttle_cfg, &qhs_clk_ctl,
+ &qhs_compute0_cfg, &qhs_compute1_cfg,
+ &qhs_cpr_cx, &qhs_cpr_mmcx,
+ &qhs_cpr_mx, &qhs_cpr_nspcx,
+ &qhs_crypto0_cfg, &qhs_cx_rdpm,
+ &qhs_display0_cfg, &qhs_display0_rt_throttle_cfg,
+ &qhs_display1_cfg, &qhs_display1_rt_throttle_cfg,
+ &qhs_emac0_cfg, &qhs_emac1_cfg,
+ &qhs_gp_dsp0_cfg, &qhs_gp_dsp1_cfg,
+ &qhs_gpdsp0_throttle_cfg, &qhs_gpdsp1_throttle_cfg,
+ &qhs_gpu_tcu_throttle_cfg, &qhs_gpuss_cfg,
+ &qhs_hwkm, &qhs_imem_cfg,
+ &qhs_ipa, &qhs_ipc_router,
+ &qhs_lpass_cfg, &qhs_lpass_throttle_cfg,
+ &qhs_mx_rdpm, &qhs_mxc_rdpm,
+ &qhs_pcie0_cfg, &qhs_pcie1_cfg,
+ &qhs_pcie_rsc_cfg, &qhs_pcie_tcu_throttle_cfg,
+ &qhs_pcie_throttle_cfg, &qhs_pdm,
+ &qhs_pimem_cfg, &qhs_pke_wrapper_cfg,
+ &qhs_qdss_cfg, &qhs_qm_cfg,
+ &qhs_qm_mpu_cfg, &qhs_qup0,
+ &qhs_qup1, &qhs_qup2,
+ &qhs_qup3, &qhs_sail_throttle_cfg,
+ &qhs_sdc1, &qhs_security,
+ &qhs_snoc_throttle_cfg, &qhs_tcsr,
+ &qhs_tlmm, &qhs_tsc_cfg,
+ &qhs_ufs_card_cfg, &qhs_ufs_mem_cfg,
+ &qhs_usb2_0, &qhs_usb3_0,
+ &qhs_usb3_1, &qhs_venus_cfg,
+ &qhs_venus_cvp_throttle_cfg, &qhs_venus_v_cpu_throttle_cfg,
+ &qhs_venus_vcodec_throttle_cfg, &qns_ddrss_cfg,
+ &qns_gpdsp_noc_cfg, &qns_mnoc_hf_cfg,
+ &qns_mnoc_sf_cfg, &qns_pcie_anoc_cfg,
+ &qns_snoc_cfg, &qxs_boot_imem,
+ &qxs_imem, &qxs_pimem,
+ &xs_qdss_stm, &xs_sys_tcu_cfg },
};
static struct qcom_icc_node qnm_gemnoc_pcie = {
.name = "qnm_gemnoc_pcie",
- .id = SA8775P_MASTER_GEM_NOC_PCIE_SNOC,
.channels = 1,
.buswidth = 16,
.num_links = 2,
- .links = { SA8775P_SLAVE_PCIE_0,
- SA8775P_SLAVE_PCIE_1
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &xs_pcie_0, &xs_pcie_1 },
};
static struct qcom_icc_node qnm_cnoc_dc_noc = {
.name = "qnm_cnoc_dc_noc",
- .id = SA8775P_MASTER_CNOC_DC_NOC,
.channels = 1,
.buswidth = 4,
.num_links = 2,
- .links = { SA8775P_SLAVE_LLCC_CFG,
- SA8775P_SLAVE_GEM_NOC_CFG
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhs_llcc, &qns_gemnoc },
};
static struct qcom_icc_node alm_gpu_tcu = {
.name = "alm_gpu_tcu",
- .id = SA8775P_MASTER_GPU_TCU,
.channels = 1,
.buswidth = 8,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node alm_pcie_tcu = {
.name = "alm_pcie_tcu",
- .id = SA8775P_MASTER_PCIE_TCU,
.channels = 1,
.buswidth = 8,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node alm_sys_tcu = {
.name = "alm_sys_tcu",
- .id = SA8775P_MASTER_SYS_TCU,
.channels = 1,
.buswidth = 8,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node chm_apps = {
.name = "chm_apps",
- .id = SA8775P_MASTER_APPSS_PROC,
.channels = 4,
.buswidth = 32,
.num_links = 3,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC,
- SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc,
+ &qns_pcie },
};
static struct qcom_icc_node qnm_cmpnoc0 = {
.name = "qnm_cmpnoc0",
- .id = SA8775P_MASTER_COMPUTE_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node qnm_cmpnoc1 = {
.name = "qnm_cmpnoc1",
- .id = SA8775P_MASTER_COMPUTE_NOC_1,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node qnm_gemnoc_cfg = {
.name = "qnm_gemnoc_cfg",
- .id = SA8775P_MASTER_GEM_NOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 4,
- .links = { SA8775P_SLAVE_SERVICE_GEM_NOC_1,
- SA8775P_SLAVE_SERVICE_GEM_NOC_2,
- SA8775P_SLAVE_SERVICE_GEM_NOC,
- SA8775P_SLAVE_SERVICE_GEM_NOC2
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &srvc_even_gemnoc, &srvc_odd_gemnoc,
+ &srvc_sys_gemnoc, &srvc_sys_gemnoc_2 },
};
static struct qcom_icc_node qnm_gpdsp_sail = {
.name = "qnm_gpdsp_sail",
- .id = SA8775P_MASTER_GPDSP_SAIL,
.channels = 1,
.buswidth = 16,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node qnm_gpu = {
.name = "qnm_gpu",
- .id = SA8775P_MASTER_GFX3D,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node qnm_mnoc_hf = {
.name = "qnm_mnoc_hf",
- .id = SA8775P_MASTER_MNOC_HF_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_LLCC,
- SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc, &qns_pcie },
};
static struct qcom_icc_node qnm_mnoc_sf = {
.name = "qnm_mnoc_sf",
- .id = SA8775P_MASTER_MNOC_SF_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 3,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC,
- SA8775P_SLAVE_GEM_NOC_PCIE_CNOC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc,
+ &qns_pcie },
};
static struct qcom_icc_node qnm_pcie = {
.name = "qnm_pcie",
- .id = SA8775P_MASTER_ANOC_PCIE_GEM_NOC,
.channels = 1,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc },
};
static struct qcom_icc_node qnm_snoc_gc = {
.name = "qnm_snoc_gc",
- .id = SA8775P_MASTER_SNOC_GC_MEM_NOC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_LLCC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_llcc },
};
static struct qcom_icc_node qnm_snoc_sf = {
.name = "qnm_snoc_sf",
- .id = SA8775P_MASTER_SNOC_SF_MEM_NOC,
.channels = 1,
.buswidth = 16,
.num_links = 3,
- .links = { SA8775P_SLAVE_GEM_NOC_CNOC,
- SA8775P_SLAVE_LLCC,
- SA8775P_SLAVE_GEM_NOC_PCIE_CNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gem_noc_cnoc, &qns_llcc,
+ &qns_pcie },
};
static struct qcom_icc_node qxm_dsp0 = {
.name = "qxm_dsp0",
- .id = SA8775P_MASTER_DSP0,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gp_dsp_sail_noc },
};
static struct qcom_icc_node qxm_dsp1 = {
.name = "qxm_dsp1",
- .id = SA8775P_MASTER_DSP1,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_SLAVE_GP_DSP_SAIL_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gp_dsp_sail_noc },
};
static struct qcom_icc_node qhm_config_noc = {
.name = "qhm_config_noc",
- .id = SA8775P_MASTER_CNOC_LPASS_AG_NOC,
.channels = 1,
.buswidth = 4,
.num_links = 6,
- .links = { SA8775P_SLAVE_LPASS_CORE_CFG,
- SA8775P_SLAVE_LPASS_LPI_CFG,
- SA8775P_SLAVE_LPASS_MPU_CFG,
- SA8775P_SLAVE_LPASS_TOP_CFG,
- SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
- SA8775P_SLAVE_SERVICE_LPASS_AG_NOC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhs_lpass_core, &qhs_lpass_lpi,
+ &qhs_lpass_mpu, &qhs_lpass_top,
+ &srvc_niu_aml_noc, &srvc_niu_lpass_agnoc },
};
static struct qcom_icc_node qxm_lpass_dsp = {
.name = "qxm_lpass_dsp",
- .id = SA8775P_MASTER_LPASS_PROC,
.channels = 1,
.buswidth = 8,
.num_links = 4,
- .links = { SA8775P_SLAVE_LPASS_TOP_CFG,
- SA8775P_SLAVE_LPASS_SNOC,
- SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
- SA8775P_SLAVE_SERVICE_LPASS_AG_NOC
- },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhs_lpass_top, &qns_sysnoc,
+ &srvc_niu_aml_noc, &srvc_niu_lpass_agnoc },
};
static struct qcom_icc_node llcc_mc = {
.name = "llcc_mc",
- .id = SA8775P_MASTER_LLCC,
.channels = 8,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_EBI1 },
+ .link_nodes = (struct qcom_icc_node *[]) { &ebi },
};
static struct qcom_icc_node qnm_camnoc_hf = {
.name = "qnm_camnoc_hf",
- .id = SA8775P_MASTER_CAMNOC_HF,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf },
};
static struct qcom_icc_node qnm_camnoc_icp = {
.name = "qnm_camnoc_icp",
- .id = SA8775P_MASTER_CAMNOC_ICP,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qnm_camnoc_sf = {
.name = "qnm_camnoc_sf",
- .id = SA8775P_MASTER_CAMNOC_SF,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qnm_mdp0_0 = {
.name = "qnm_mdp0_0",
- .id = SA8775P_MASTER_MDP0,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf },
};
static struct qcom_icc_node qnm_mdp0_1 = {
.name = "qnm_mdp0_1",
- .id = SA8775P_MASTER_MDP1,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf },
};
static struct qcom_icc_node qnm_mdp1_0 = {
.name = "qnm_mdp1_0",
- .id = SA8775P_MASTER_MDP_CORE1_0,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf },
};
static struct qcom_icc_node qnm_mdp1_1 = {
.name = "qnm_mdp1_1",
- .id = SA8775P_MASTER_MDP_CORE1_1,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_hf },
};
static struct qcom_icc_node qnm_mnoc_hf_cfg = {
.name = "qnm_mnoc_hf_cfg",
- .id = SA8775P_MASTER_CNOC_MNOC_HF_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SERVICE_MNOC_HF },
+ .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc_hf },
};
static struct qcom_icc_node qnm_mnoc_sf_cfg = {
.name = "qnm_mnoc_sf_cfg",
- .id = SA8775P_MASTER_CNOC_MNOC_SF_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SERVICE_MNOC_SF },
+ .link_nodes = (struct qcom_icc_node *[]) { &srvc_mnoc_sf },
};
static struct qcom_icc_node qnm_video0 = {
.name = "qnm_video0",
- .id = SA8775P_MASTER_VIDEO_P0,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qnm_video1 = {
.name = "qnm_video1",
- .id = SA8775P_MASTER_VIDEO_P1,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qnm_video_cvp = {
.name = "qnm_video_cvp",
- .id = SA8775P_MASTER_VIDEO_PROC,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qnm_video_v_cpu = {
.name = "qnm_video_v_cpu",
- .id = SA8775P_MASTER_VIDEO_V_PROC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_mem_noc_sf },
};
static struct qcom_icc_node qhm_nsp_noc_config = {
.name = "qhm_nsp_noc_config",
- .id = SA8775P_MASTER_CDSP_NOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SERVICE_NSP_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &service_nsp_noc },
};
static struct qcom_icc_node qxm_nsp = {
.name = "qxm_nsp",
- .id = SA8775P_MASTER_CDSP_PROC,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_HCP_A, SLAVE_CDSP_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_hcp, &qns_nsp_gemnoc },
};
static struct qcom_icc_node qhm_nspb_noc_config = {
.name = "qhm_nspb_noc_config",
- .id = SA8775P_MASTER_CDSPB_NOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SERVICE_NSPB_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &service_nspb_noc },
};
static struct qcom_icc_node qxm_nspb = {
.name = "qxm_nspb",
- .id = SA8775P_MASTER_CDSP_PROC_B,
.channels = 2,
.buswidth = 32,
.num_links = 2,
- .links = { SA8775P_SLAVE_HCP_B, SLAVE_CDSPB_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_nspb_hcp, &qns_nspb_gemnoc },
};
static struct qcom_icc_node xm_pcie3_0 = {
.name = "xm_pcie3_0",
- .id = SA8775P_MASTER_PCIE_0,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_mem_noc },
};
static struct qcom_icc_node xm_pcie3_1 = {
.name = "xm_pcie3_1",
- .id = SA8775P_MASTER_PCIE_1,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_ANOC_PCIE_GEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_pcie_mem_noc },
};
static struct qcom_icc_node qhm_gic = {
.name = "qhm_gic",
- .id = SA8775P_MASTER_GIC_AHB,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf },
};
static struct qcom_icc_node qnm_aggre1_noc = {
.name = "qnm_aggre1_noc",
- .id = SA8775P_MASTER_A1NOC_SNOC,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf },
};
static struct qcom_icc_node qnm_aggre2_noc = {
.name = "qnm_aggre2_noc",
- .id = SA8775P_MASTER_A2NOC_SNOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf },
};
static struct qcom_icc_node qnm_lpass_noc = {
.name = "qnm_lpass_noc",
- .id = SA8775P_MASTER_LPASS_ANOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_SF },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_sf },
};
static struct qcom_icc_node qnm_snoc_cfg = {
.name = "qnm_snoc_cfg",
- .id = SA8775P_MASTER_SNOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_SLAVE_SERVICE_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &srvc_snoc },
};
static struct qcom_icc_node qxm_pimem = {
.name = "qxm_pimem",
- .id = SA8775P_MASTER_PIMEM,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_gc },
};
static struct qcom_icc_node xm_gic = {
.name = "xm_gic",
- .id = SA8775P_MASTER_GIC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_SLAVE_SNOC_GEM_NOC_GC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qns_gemnoc_gc },
};
static struct qcom_icc_node qns_a1noc_snoc = {
.name = "qns_a1noc_snoc",
- .id = SA8775P_SLAVE_A1NOC_SNOC,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_A1NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre1_noc },
};
static struct qcom_icc_node qns_a2noc_snoc = {
.name = "qns_a2noc_snoc",
- .id = SA8775P_SLAVE_A2NOC_SNOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_A2NOC_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_aggre2_noc },
};
static struct qcom_icc_node qup0_core_slave = {
.name = "qup0_core_slave",
- .id = SA8775P_SLAVE_QUP_CORE_0,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qup1_core_slave = {
.name = "qup1_core_slave",
- .id = SA8775P_SLAVE_QUP_CORE_1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qup2_core_slave = {
.name = "qup2_core_slave",
- .id = SA8775P_SLAVE_QUP_CORE_2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qup3_core_slave = {
.name = "qup3_core_slave",
- .id = SA8775P_SLAVE_QUP_CORE_3,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ahb2phy0 = {
.name = "qhs_ahb2phy0",
- .id = SA8775P_SLAVE_AHB2PHY_0,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ahb2phy1 = {
.name = "qhs_ahb2phy1",
- .id = SA8775P_SLAVE_AHB2PHY_1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ahb2phy2 = {
.name = "qhs_ahb2phy2",
- .id = SA8775P_SLAVE_AHB2PHY_2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ahb2phy3 = {
.name = "qhs_ahb2phy3",
- .id = SA8775P_SLAVE_AHB2PHY_3,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_anoc_throttle_cfg = {
.name = "qhs_anoc_throttle_cfg",
- .id = SA8775P_SLAVE_ANOC_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_aoss = {
.name = "qhs_aoss",
- .id = SA8775P_SLAVE_AOSS,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_apss = {
.name = "qhs_apss",
- .id = SA8775P_SLAVE_APPSS,
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node qhs_boot_rom = {
.name = "qhs_boot_rom",
- .id = SA8775P_SLAVE_BOOT_ROM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_camera_cfg = {
.name = "qhs_camera_cfg",
- .id = SA8775P_SLAVE_CAMERA_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_camera_nrt_throttle_cfg = {
.name = "qhs_camera_nrt_throttle_cfg",
- .id = SA8775P_SLAVE_CAMERA_NRT_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_camera_rt_throttle_cfg = {
.name = "qhs_camera_rt_throttle_cfg",
- .id = SA8775P_SLAVE_CAMERA_RT_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_clk_ctl = {
.name = "qhs_clk_ctl",
- .id = SA8775P_SLAVE_CLK_CTL,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_compute0_cfg = {
.name = "qhs_compute0_cfg",
- .id = SA8775P_SLAVE_CDSP_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CDSP_NOC_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhm_nsp_noc_config },
};
static struct qcom_icc_node qhs_compute1_cfg = {
.name = "qhs_compute1_cfg",
- .id = SA8775P_SLAVE_CDSP1_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CDSPB_NOC_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhm_nspb_noc_config },
};
static struct qcom_icc_node qhs_cpr_cx = {
.name = "qhs_cpr_cx",
- .id = SA8775P_SLAVE_RBCPR_CX_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_cpr_mmcx = {
.name = "qhs_cpr_mmcx",
- .id = SA8775P_SLAVE_RBCPR_MMCX_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_cpr_mx = {
.name = "qhs_cpr_mx",
- .id = SA8775P_SLAVE_RBCPR_MX_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_cpr_nspcx = {
.name = "qhs_cpr_nspcx",
- .id = SA8775P_SLAVE_CPR_NSPCX,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_crypto0_cfg = {
.name = "qhs_crypto0_cfg",
- .id = SA8775P_SLAVE_CRYPTO_0_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_cx_rdpm = {
.name = "qhs_cx_rdpm",
- .id = SA8775P_SLAVE_CX_RDPM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_display0_cfg = {
.name = "qhs_display0_cfg",
- .id = SA8775P_SLAVE_DISPLAY_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_display0_rt_throttle_cfg = {
.name = "qhs_display0_rt_throttle_cfg",
- .id = SA8775P_SLAVE_DISPLAY_RT_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_display1_cfg = {
.name = "qhs_display1_cfg",
- .id = SA8775P_SLAVE_DISPLAY1_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_display1_rt_throttle_cfg = {
.name = "qhs_display1_rt_throttle_cfg",
- .id = SA8775P_SLAVE_DISPLAY1_RT_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_emac0_cfg = {
.name = "qhs_emac0_cfg",
- .id = SA8775P_SLAVE_EMAC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_emac1_cfg = {
.name = "qhs_emac1_cfg",
- .id = SA8775P_SLAVE_EMAC1_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gp_dsp0_cfg = {
.name = "qhs_gp_dsp0_cfg",
- .id = SA8775P_SLAVE_GP_DSP0_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gp_dsp1_cfg = {
.name = "qhs_gp_dsp1_cfg",
- .id = SA8775P_SLAVE_GP_DSP1_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gpdsp0_throttle_cfg = {
.name = "qhs_gpdsp0_throttle_cfg",
- .id = SA8775P_SLAVE_GPDSP0_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gpdsp1_throttle_cfg = {
.name = "qhs_gpdsp1_throttle_cfg",
- .id = SA8775P_SLAVE_GPDSP1_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg = {
.name = "qhs_gpu_tcu_throttle_cfg",
- .id = SA8775P_SLAVE_GPU_TCU_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_gpuss_cfg = {
.name = "qhs_gpuss_cfg",
- .id = SA8775P_SLAVE_GFX3D_CFG,
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node qhs_hwkm = {
.name = "qhs_hwkm",
- .id = SA8775P_SLAVE_HWKM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_imem_cfg = {
.name = "qhs_imem_cfg",
- .id = SA8775P_SLAVE_IMEM_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ipa = {
.name = "qhs_ipa",
- .id = SA8775P_SLAVE_IPA_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ipc_router = {
.name = "qhs_ipc_router",
- .id = SA8775P_SLAVE_IPC_ROUTER_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_lpass_cfg = {
.name = "qhs_lpass_cfg",
- .id = SA8775P_SLAVE_LPASS,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CNOC_LPASS_AG_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qhm_config_noc },
};
static struct qcom_icc_node qhs_lpass_throttle_cfg = {
.name = "qhs_lpass_throttle_cfg",
- .id = SA8775P_SLAVE_LPASS_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_mx_rdpm = {
.name = "qhs_mx_rdpm",
- .id = SA8775P_SLAVE_MX_RDPM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_mxc_rdpm = {
.name = "qhs_mxc_rdpm",
- .id = SA8775P_SLAVE_MXC_RDPM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie0_cfg = {
.name = "qhs_pcie0_cfg",
- .id = SA8775P_SLAVE_PCIE_0_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie1_cfg = {
.name = "qhs_pcie1_cfg",
- .id = SA8775P_SLAVE_PCIE_1_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie_rsc_cfg = {
.name = "qhs_pcie_rsc_cfg",
- .id = SA8775P_SLAVE_PCIE_RSC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg = {
.name = "qhs_pcie_tcu_throttle_cfg",
- .id = SA8775P_SLAVE_PCIE_TCU_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie_throttle_cfg = {
.name = "qhs_pcie_throttle_cfg",
- .id = SA8775P_SLAVE_PCIE_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pdm = {
.name = "qhs_pdm",
- .id = SA8775P_SLAVE_PDM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pimem_cfg = {
.name = "qhs_pimem_cfg",
- .id = SA8775P_SLAVE_PIMEM_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pke_wrapper_cfg = {
.name = "qhs_pke_wrapper_cfg",
- .id = SA8775P_SLAVE_PKA_WRAPPER_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qdss_cfg = {
.name = "qhs_qdss_cfg",
- .id = SA8775P_SLAVE_QDSS_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qm_cfg = {
.name = "qhs_qm_cfg",
- .id = SA8775P_SLAVE_QM_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qm_mpu_cfg = {
.name = "qhs_qm_mpu_cfg",
- .id = SA8775P_SLAVE_QM_MPU_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qup0 = {
.name = "qhs_qup0",
- .id = SA8775P_SLAVE_QUP_0,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qup1 = {
.name = "qhs_qup1",
- .id = SA8775P_SLAVE_QUP_1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qup2 = {
.name = "qhs_qup2",
- .id = SA8775P_SLAVE_QUP_2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qup3 = {
.name = "qhs_qup3",
- .id = SA8775P_SLAVE_QUP_3,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_sail_throttle_cfg = {
.name = "qhs_sail_throttle_cfg",
- .id = SA8775P_SLAVE_SAIL_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_sdc1 = {
.name = "qhs_sdc1",
- .id = SA8775P_SLAVE_SDC1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_security = {
.name = "qhs_security",
- .id = SA8775P_SLAVE_SECURITY,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_snoc_throttle_cfg = {
.name = "qhs_snoc_throttle_cfg",
- .id = SA8775P_SLAVE_SNOC_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tcsr = {
.name = "qhs_tcsr",
- .id = SA8775P_SLAVE_TCSR,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tlmm = {
.name = "qhs_tlmm",
- .id = SA8775P_SLAVE_TLMM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tsc_cfg = {
.name = "qhs_tsc_cfg",
- .id = SA8775P_SLAVE_TSC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ufs_card_cfg = {
.name = "qhs_ufs_card_cfg",
- .id = SA8775P_SLAVE_UFS_CARD_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ufs_mem_cfg = {
.name = "qhs_ufs_mem_cfg",
- .id = SA8775P_SLAVE_UFS_MEM_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb2_0 = {
.name = "qhs_usb2_0",
- .id = SA8775P_SLAVE_USB2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3_0 = {
.name = "qhs_usb3_0",
- .id = SA8775P_SLAVE_USB3_0,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3_1 = {
.name = "qhs_usb3_1",
- .id = SA8775P_SLAVE_USB3_1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_venus_cfg = {
.name = "qhs_venus_cfg",
- .id = SA8775P_SLAVE_VENUS_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = {
.name = "qhs_venus_cvp_throttle_cfg",
- .id = SA8775P_SLAVE_VENUS_CVP_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg = {
.name = "qhs_venus_v_cpu_throttle_cfg",
- .id = SA8775P_SLAVE_VENUS_V_CPU_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg = {
.name = "qhs_venus_vcodec_throttle_cfg",
- .id = SA8775P_SLAVE_VENUS_VCODEC_THROTTLE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_ddrss_cfg = {
.name = "qns_ddrss_cfg",
- .id = SA8775P_SLAVE_DDRSS_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CNOC_DC_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_cnoc_dc_noc },
};
static struct qcom_icc_node qns_gpdsp_noc_cfg = {
.name = "qns_gpdsp_noc_cfg",
- .id = SA8775P_SLAVE_GPDSP_NOC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_mnoc_hf_cfg = {
.name = "qns_mnoc_hf_cfg",
- .id = SA8775P_SLAVE_CNOC_MNOC_HF_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CNOC_MNOC_HF_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf_cfg },
};
static struct qcom_icc_node qns_mnoc_sf_cfg = {
.name = "qns_mnoc_sf_cfg",
- .id = SA8775P_SLAVE_CNOC_MNOC_SF_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_CNOC_MNOC_SF_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf_cfg },
};
static struct qcom_icc_node qns_pcie_anoc_cfg = {
.name = "qns_pcie_anoc_cfg",
- .id = SA8775P_SLAVE_PCIE_ANOC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_snoc_cfg = {
.name = "qns_snoc_cfg",
- .id = SA8775P_SLAVE_SNOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_SNOC_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_cfg },
};
static struct qcom_icc_node qxs_boot_imem = {
.name = "qxs_boot_imem",
- .id = SA8775P_SLAVE_BOOT_IMEM,
.channels = 1,
.buswidth = 16,
};
static struct qcom_icc_node qxs_imem = {
.name = "qxs_imem",
- .id = SA8775P_SLAVE_IMEM,
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node qxs_pimem = {
.name = "qxs_pimem",
- .id = SA8775P_SLAVE_PIMEM,
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node xs_pcie_0 = {
.name = "xs_pcie_0",
- .id = SA8775P_SLAVE_PCIE_0,
.channels = 1,
.buswidth = 16,
};
static struct qcom_icc_node xs_pcie_1 = {
.name = "xs_pcie_1",
- .id = SA8775P_SLAVE_PCIE_1,
.channels = 1,
.buswidth = 32,
};
static struct qcom_icc_node xs_qdss_stm = {
.name = "xs_qdss_stm",
- .id = SA8775P_SLAVE_QDSS_STM,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node xs_sys_tcu_cfg = {
.name = "xs_sys_tcu_cfg",
- .id = SA8775P_SLAVE_TCU,
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node qhs_llcc = {
.name = "qhs_llcc",
- .id = SA8775P_SLAVE_LLCC_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_gemnoc = {
.name = "qns_gemnoc",
- .id = SA8775P_SLAVE_GEM_NOC_CFG,
.channels = 1,
.buswidth = 4,
.num_links = 1,
- .links = { SA8775P_MASTER_GEM_NOC_CFG },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_cfg },
};
static struct qcom_icc_node qns_gem_noc_cnoc = {
.name = "qns_gem_noc_cnoc",
- .id = SA8775P_SLAVE_GEM_NOC_CNOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_GEM_NOC_CNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_cnoc },
};
static struct qcom_icc_node qns_llcc = {
.name = "qns_llcc",
- .id = SA8775P_SLAVE_LLCC,
.channels = 6,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_LLCC },
+ .link_nodes = (struct qcom_icc_node *[]) { &llcc_mc },
};
static struct qcom_icc_node qns_pcie = {
.name = "qns_pcie",
- .id = SA8775P_SLAVE_GEM_NOC_PCIE_CNOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_GEM_NOC_PCIE_SNOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_gemnoc_pcie },
};
static struct qcom_icc_node srvc_even_gemnoc = {
.name = "srvc_even_gemnoc",
- .id = SA8775P_SLAVE_SERVICE_GEM_NOC_1,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node srvc_odd_gemnoc = {
.name = "srvc_odd_gemnoc",
- .id = SA8775P_SLAVE_SERVICE_GEM_NOC_2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node srvc_sys_gemnoc = {
.name = "srvc_sys_gemnoc",
- .id = SA8775P_SLAVE_SERVICE_GEM_NOC,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node srvc_sys_gemnoc_2 = {
.name = "srvc_sys_gemnoc_2",
- .id = SA8775P_SLAVE_SERVICE_GEM_NOC2,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_gp_dsp_sail_noc = {
.name = "qns_gp_dsp_sail_noc",
- .id = SA8775P_SLAVE_GP_DSP_SAIL_NOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_GPDSP_SAIL },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_gpdsp_sail },
};
static struct qcom_icc_node qhs_lpass_core = {
.name = "qhs_lpass_core",
- .id = SA8775P_SLAVE_LPASS_CORE_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_lpass_lpi = {
.name = "qhs_lpass_lpi",
- .id = SA8775P_SLAVE_LPASS_LPI_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_lpass_mpu = {
.name = "qhs_lpass_mpu",
- .id = SA8775P_SLAVE_LPASS_MPU_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_lpass_top = {
.name = "qhs_lpass_top",
- .id = SA8775P_SLAVE_LPASS_TOP_CFG,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_sysnoc = {
.name = "qns_sysnoc",
- .id = SA8775P_SLAVE_LPASS_SNOC,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_LPASS_ANOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_lpass_noc },
};
static struct qcom_icc_node srvc_niu_aml_noc = {
.name = "srvc_niu_aml_noc",
- .id = SA8775P_SLAVE_SERVICES_LPASS_AML_NOC,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node srvc_niu_lpass_agnoc = {
.name = "srvc_niu_lpass_agnoc",
- .id = SA8775P_SLAVE_SERVICE_LPASS_AG_NOC,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node ebi = {
.name = "ebi",
- .id = SA8775P_SLAVE_EBI1,
.channels = 8,
.buswidth = 4,
};
static struct qcom_icc_node qns_mem_noc_hf = {
.name = "qns_mem_noc_hf",
- .id = SA8775P_SLAVE_MNOC_HF_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_MNOC_HF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_hf },
};
static struct qcom_icc_node qns_mem_noc_sf = {
.name = "qns_mem_noc_sf",
- .id = SA8775P_SLAVE_MNOC_SF_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_MNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_mnoc_sf },
};
static struct qcom_icc_node srvc_mnoc_hf = {
.name = "srvc_mnoc_hf",
- .id = SA8775P_SLAVE_SERVICE_MNOC_HF,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node srvc_mnoc_sf = {
.name = "srvc_mnoc_sf",
- .id = SA8775P_SLAVE_SERVICE_MNOC_SF,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_hcp = {
.name = "qns_hcp",
- .id = SA8775P_SLAVE_HCP_A,
.channels = 2,
.buswidth = 32,
};
static struct qcom_icc_node qns_nsp_gemnoc = {
.name = "qns_nsp_gemnoc",
- .id = SA8775P_SLAVE_CDSP_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_COMPUTE_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_cmpnoc0 },
};
static struct qcom_icc_node service_nsp_noc = {
.name = "service_nsp_noc",
- .id = SA8775P_SLAVE_SERVICE_NSP_NOC,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_nspb_gemnoc = {
.name = "qns_nspb_gemnoc",
- .id = SA8775P_SLAVE_CDSPB_MEM_NOC,
.channels = 2,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_COMPUTE_NOC_1 },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_cmpnoc1 },
};
static struct qcom_icc_node qns_nspb_hcp = {
.name = "qns_nspb_hcp",
- .id = SA8775P_SLAVE_HCP_B,
.channels = 2,
.buswidth = 32,
};
static struct qcom_icc_node service_nspb_noc = {
.name = "service_nspb_noc",
- .id = SA8775P_SLAVE_SERVICE_NSPB_NOC,
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_pcie_mem_noc = {
.name = "qns_pcie_mem_noc",
- .id = SA8775P_SLAVE_ANOC_PCIE_GEM_NOC,
.channels = 1,
.buswidth = 32,
.num_links = 1,
- .links = { SA8775P_MASTER_ANOC_PCIE_GEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_pcie },
};
static struct qcom_icc_node qns_gemnoc_gc = {
.name = "qns_gemnoc_gc",
- .id = SA8775P_SLAVE_SNOC_GEM_NOC_GC,
.channels = 1,
.buswidth = 8,
.num_links = 1,
- .links = { SA8775P_MASTER_SNOC_GC_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_gc },
};
static struct qcom_icc_node qns_gemnoc_sf = {
.name = "qns_gemnoc_sf",
- .id = SA8775P_SLAVE_SNOC_GEM_NOC_SF,
.channels = 1,
.buswidth = 16,
.num_links = 1,
- .links = { SA8775P_MASTER_SNOC_SF_MEM_NOC },
+ .link_nodes = (struct qcom_icc_node *[]) { &qnm_snoc_sf },
};
static struct qcom_icc_node srvc_snoc = {
.name = "srvc_snoc",
- .id = SA8775P_SLAVE_SERVICE_SNOC,
.channels = 1,
.buswidth = 4,
};
@@ -2113,6 +1841,7 @@ static const struct qcom_icc_desc sa8775p_aggre1_noc = {
.num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
.bcms = aggre1_noc_bcms,
.num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
@@ -2140,6 +1869,7 @@ static const struct qcom_icc_desc sa8775p_aggre2_noc = {
.num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
.bcms = aggre2_noc_bcms,
.num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const clk_virt_bcms[] = {
@@ -2164,6 +1894,7 @@ static const struct qcom_icc_desc sa8775p_clk_virt = {
.num_nodes = ARRAY_SIZE(clk_virt_nodes),
.bcms = clk_virt_bcms,
.num_bcms = ARRAY_SIZE(clk_virt_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const config_noc_bcms[] = {
@@ -2269,6 +2000,7 @@ static const struct qcom_icc_desc sa8775p_config_noc = {
.num_nodes = ARRAY_SIZE(config_noc_nodes),
.bcms = config_noc_bcms,
.num_bcms = ARRAY_SIZE(config_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const dc_noc_bcms[] = {
@@ -2285,6 +2017,7 @@ static const struct qcom_icc_desc sa8775p_dc_noc = {
.num_nodes = ARRAY_SIZE(dc_noc_nodes),
.bcms = dc_noc_bcms,
.num_bcms = ARRAY_SIZE(dc_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const gem_noc_bcms[] = {
@@ -2321,6 +2054,7 @@ static const struct qcom_icc_desc sa8775p_gem_noc = {
.num_nodes = ARRAY_SIZE(gem_noc_nodes),
.bcms = gem_noc_bcms,
.num_bcms = ARRAY_SIZE(gem_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const gpdsp_anoc_bcms[] = {
@@ -2339,6 +2073,7 @@ static const struct qcom_icc_desc sa8775p_gpdsp_anoc = {
.num_nodes = ARRAY_SIZE(gpdsp_anoc_nodes),
.bcms = gpdsp_anoc_bcms,
.num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = {
@@ -2362,6 +2097,7 @@ static const struct qcom_icc_desc sa8775p_lpass_ag_noc = {
.num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
.bcms = lpass_ag_noc_bcms,
.num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
@@ -2379,6 +2115,7 @@ static const struct qcom_icc_desc sa8775p_mc_virt = {
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
.bcms = mc_virt_bcms,
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
@@ -2411,6 +2148,7 @@ static const struct qcom_icc_desc sa8775p_mmss_noc = {
.num_nodes = ARRAY_SIZE(mmss_noc_nodes),
.bcms = mmss_noc_bcms,
.num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const nspa_noc_bcms[] = {
@@ -2431,6 +2169,7 @@ static const struct qcom_icc_desc sa8775p_nspa_noc = {
.num_nodes = ARRAY_SIZE(nspa_noc_nodes),
.bcms = nspa_noc_bcms,
.num_bcms = ARRAY_SIZE(nspa_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const nspb_noc_bcms[] = {
@@ -2451,6 +2190,7 @@ static const struct qcom_icc_desc sa8775p_nspb_noc = {
.num_nodes = ARRAY_SIZE(nspb_noc_nodes),
.bcms = nspb_noc_bcms,
.num_bcms = ARRAY_SIZE(nspb_noc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const pcie_anoc_bcms[] = {
@@ -2468,6 +2208,7 @@ static const struct qcom_icc_desc sa8775p_pcie_anoc = {
.num_nodes = ARRAY_SIZE(pcie_anoc_nodes),
.bcms = pcie_anoc_bcms,
.num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
+ .alloc_dyn_id = true,
};
static struct qcom_icc_bcm * const system_noc_bcms[] = {
@@ -2496,6 +2237,7 @@ static const struct qcom_icc_desc sa8775p_system_noc = {
.num_nodes = ARRAY_SIZE(system_noc_nodes),
.bcms = system_noc_bcms,
.num_bcms = ARRAY_SIZE(system_noc_bcms),
+ .alloc_dyn_id = true,
};
static const struct of_device_id qnoc_of_match[] = {
diff --git a/drivers/interconnect/qcom/sm8650.c b/drivers/interconnect/qcom/sm8650.c
index 20ac5bc5e1fb..b7c321f4e4b5 100644
--- a/drivers/interconnect/qcom/sm8650.c
+++ b/drivers/interconnect/qcom/sm8650.c
@@ -17,20 +17,45 @@
#include "icc-rpmh.h"
#include "sm8650.h"
+static const struct regmap_config icc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .fast_io = true,
+};
+
+static struct qcom_icc_qosbox qhm_qspi_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xc000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qhm_qspi = {
.name = "qhm_qspi",
.id = SM8650_MASTER_QSPI_0,
.channels = 1,
.buswidth = 4,
+ .qosbox = &qhm_qspi_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
+static struct qcom_icc_qosbox qhm_qup1_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xd000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qhm_qup1 = {
.name = "qhm_qup1",
.id = SM8650_MASTER_QUP_1,
.channels = 1,
.buswidth = 4,
+ .qosbox = &qhm_qup1_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
@@ -44,65 +69,128 @@ static struct qcom_icc_node qxm_qup02 = {
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_sdc4_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xe000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_sdc4 = {
.name = "xm_sdc4",
.id = SM8650_MASTER_SDCC_4,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_sdc4_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_ufs_mem_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xf000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_ufs_mem = {
.name = "xm_ufs_mem",
.id = SM8650_MASTER_UFS_MEM,
.channels = 1,
.buswidth = 16,
+ .qosbox = &xm_ufs_mem_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_usb3_0_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x10000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_usb3_0 = {
.name = "xm_usb3_0",
.id = SM8650_MASTER_USB3_0,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_usb3_0_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A1NOC_SNOC },
};
+static struct qcom_icc_qosbox qhm_qdss_bam_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x12000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qhm_qdss_bam = {
.name = "qhm_qdss_bam",
.id = SM8650_MASTER_QDSS_BAM,
.channels = 1,
.buswidth = 4,
+ .qosbox = &qhm_qdss_bam_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox qhm_qup2_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x13000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qhm_qup2 = {
.name = "qhm_qup2",
.id = SM8650_MASTER_QUP_2,
.channels = 1,
.buswidth = 4,
+ .qosbox = &qhm_qup2_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox qxm_crypto_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x15000 },
+ .prio = 2,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qxm_crypto = {
.name = "qxm_crypto",
.id = SM8650_MASTER_CRYPTO,
.channels = 1,
.buswidth = 8,
+ .qosbox = &qxm_crypto_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox qxm_ipa_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x16000 },
+ .prio = 2,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qxm_ipa = {
.name = "qxm_ipa",
.id = SM8650_MASTER_IPA,
.channels = 1,
.buswidth = 8,
+ .qosbox = &qxm_ipa_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
@@ -116,29 +204,56 @@ static struct qcom_icc_node qxm_sp = {
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_qdss_etr_0_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x17000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_qdss_etr_0 = {
.name = "xm_qdss_etr_0",
.id = SM8650_MASTER_QDSS_ETR,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_qdss_etr_0_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_qdss_etr_1_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x18000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_qdss_etr_1 = {
.name = "xm_qdss_etr_1",
.id = SM8650_MASTER_QDSS_ETR_1,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_qdss_etr_1_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
+static struct qcom_icc_qosbox xm_sdc2_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x19000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_sdc2 = {
.name = "xm_sdc2",
.id = SM8650_MASTER_SDCC_2,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_sdc2_qos,
.num_links = 1,
.links = { SM8650_SLAVE_A2NOC_SNOC },
};
@@ -223,29 +338,56 @@ static struct qcom_icc_node qnm_gemnoc_pcie = {
.links = { SM8650_SLAVE_PCIE_0, SM8650_SLAVE_PCIE_1 },
};
+static struct qcom_icc_qosbox alm_gpu_tcu_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xbf000 },
+ .prio = 1,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node alm_gpu_tcu = {
.name = "alm_gpu_tcu",
.id = SM8650_MASTER_GPU_TCU,
.channels = 1,
.buswidth = 8,
+ .qosbox = &alm_gpu_tcu_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox alm_sys_tcu_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xc1000 },
+ .prio = 6,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node alm_sys_tcu = {
.name = "alm_sys_tcu",
.id = SM8650_MASTER_SYS_TCU,
.channels = 1,
.buswidth = 8,
+ .qosbox = &alm_sys_tcu_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox alm_ubwc_p_tcu_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xc5000 },
+ .prio = 1,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node alm_ubwc_p_tcu = {
.name = "alm_ubwc_p_tcu",
.id = SM8650_MASTER_UBWC_P_TCU,
.channels = 1,
.buswidth = 8,
+ .qosbox = &alm_ubwc_p_tcu_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
@@ -260,20 +402,38 @@ static struct qcom_icc_node chm_apps = {
SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
};
+static struct qcom_icc_qosbox qnm_gpu_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x31000, 0x71000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node qnm_gpu = {
.name = "qnm_gpu",
.id = SM8650_MASTER_GFX3D,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_gpu_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox qnm_lpass_gemnoc_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xb5000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_lpass_gemnoc = {
.name = "qnm_lpass_gemnoc",
.id = SM8650_MASTER_LPASS_GEM_NOC,
.channels = 1,
.buswidth = 16,
+ .qosbox = &qnm_lpass_gemnoc_qos,
.num_links = 3,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
@@ -289,67 +449,130 @@ static struct qcom_icc_node qnm_mdsp = {
SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
};
+static struct qcom_icc_qosbox qnm_mnoc_hf_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x33000, 0x73000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_mnoc_hf = {
.name = "qnm_mnoc_hf",
.id = SM8650_MASTER_MNOC_HF_MEM_NOC,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_mnoc_hf_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox qnm_mnoc_sf_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x35000, 0x75000 },
+ .prio = 0,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_mnoc_sf = {
.name = "qnm_mnoc_sf",
.id = SM8650_MASTER_MNOC_SF_MEM_NOC,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_mnoc_sf_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox qnm_nsp_gemnoc_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x37000, 0x77000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node qnm_nsp_gemnoc = {
.name = "qnm_nsp_gemnoc",
.id = SM8650_MASTER_COMPUTE_NOC,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_nsp_gemnoc_qos,
.num_links = 3,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
};
+static struct qcom_icc_qosbox qnm_pcie_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xb7000 },
+ .prio = 2,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_pcie = {
.name = "qnm_pcie",
.id = SM8650_MASTER_ANOC_PCIE_GEM_NOC,
.channels = 1,
.buswidth = 16,
+ .qosbox = &qnm_pcie_qos,
.num_links = 2,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox qnm_snoc_sf_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xbb000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_snoc_sf = {
.name = "qnm_snoc_sf",
.id = SM8650_MASTER_SNOC_SF_MEM_NOC,
.channels = 1,
.buswidth = 16,
+ .qosbox = &qnm_snoc_sf_qos,
.num_links = 3,
.links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
};
+static struct qcom_icc_qosbox qnm_ubwc_p_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xc3000 },
+ .prio = 1,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node qnm_ubwc_p = {
.name = "qnm_ubwc_p",
.id = SM8650_MASTER_UBWC_P,
.channels = 1,
.buswidth = 32,
+ .qosbox = &qnm_ubwc_p_qos,
.num_links = 1,
.links = { SM8650_SLAVE_LLCC },
};
+static struct qcom_icc_qosbox xm_gic_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xb9000 },
+ .prio = 4,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 1,
+};
+
static struct qcom_icc_node xm_gic = {
.name = "xm_gic",
.id = SM8650_MASTER_GIC,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_gic_qos,
.num_links = 1,
.links = { SM8650_SLAVE_LLCC },
};
@@ -390,38 +613,74 @@ static struct qcom_icc_node llcc_mc = {
.links = { SM8650_SLAVE_EBI1 },
};
+static struct qcom_icc_qosbox qnm_camnoc_hf_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x28000, 0x29000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_camnoc_hf = {
.name = "qnm_camnoc_hf",
.id = SM8650_MASTER_CAMNOC_HF,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_camnoc_hf_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_HF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_camnoc_icp_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x2a000 },
+ .prio = 4,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_camnoc_icp = {
.name = "qnm_camnoc_icp",
.id = SM8650_MASTER_CAMNOC_ICP,
.channels = 1,
.buswidth = 8,
+ .qosbox = &qnm_camnoc_icp_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_camnoc_sf_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x2b000, 0x2c000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_camnoc_sf = {
.name = "qnm_camnoc_sf",
.id = SM8650_MASTER_CAMNOC_SF,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_camnoc_sf_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_mdp_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x2d000, 0x2e000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_mdp = {
.name = "qnm_mdp",
.id = SM8650_MASTER_MDP,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_mdp_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_HF_MEM_NOC },
};
@@ -435,38 +694,74 @@ static struct qcom_icc_node qnm_vapss_hcp = {
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_video_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x30000, 0x31000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_video = {
.name = "qnm_video",
.id = SM8650_MASTER_VIDEO,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_video_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_video_cv_cpu_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x32000 },
+ .prio = 4,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_video_cv_cpu = {
.name = "qnm_video_cv_cpu",
.id = SM8650_MASTER_VIDEO_CV_PROC,
.channels = 1,
.buswidth = 8,
+ .qosbox = &qnm_video_cv_cpu_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_video_cvp_qos = {
+ .num_ports = 2,
+ .port_offsets = { 0x33000, 0x34000 },
+ .prio = 0,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_video_cvp = {
.name = "qnm_video_cvp",
.id = SM8650_MASTER_VIDEO_PROC,
.channels = 2,
.buswidth = 32,
+ .qosbox = &qnm_video_cvp_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
+static struct qcom_icc_qosbox qnm_video_v_cpu_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x35000 },
+ .prio = 4,
+ .urg_fwd = 1,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node qnm_video_v_cpu = {
.name = "qnm_video_v_cpu",
.id = SM8650_MASTER_VIDEO_V_PROC,
.channels = 1,
.buswidth = 8,
+ .qosbox = &qnm_video_v_cpu_qos,
.num_links = 1,
.links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
};
@@ -498,20 +793,38 @@ static struct qcom_icc_node qsm_pcie_anoc_cfg = {
.links = { SM8650_SLAVE_SERVICE_PCIE_ANOC },
};
+static struct qcom_icc_qosbox xm_pcie3_0_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xb000 },
+ .prio = 3,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_pcie3_0 = {
.name = "xm_pcie3_0",
.id = SM8650_MASTER_PCIE_0,
.channels = 1,
.buswidth = 8,
+ .qosbox = &xm_pcie3_0_qos,
.num_links = 1,
.links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC },
};
+static struct qcom_icc_qosbox xm_pcie3_1_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0xc000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 0,
+};
+
static struct qcom_icc_node xm_pcie3_1 = {
.name = "xm_pcie3_1",
.id = SM8650_MASTER_PCIE_1,
.channels = 1,
.buswidth = 16,
+ .qosbox = &xm_pcie3_1_qos,
.num_links = 1,
.links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC },
};
@@ -534,6 +847,24 @@ static struct qcom_icc_node qnm_aggre2_noc = {
.links = { SM8650_SLAVE_SNOC_GEM_NOC_SF },
};
+static struct qcom_icc_qosbox qnm_apss_noc_qos = {
+ .num_ports = 1,
+ .port_offsets = { 0x1c000 },
+ .prio = 2,
+ .urg_fwd = 0,
+ .prio_fwd_disable = 1,
+};
+
+static struct qcom_icc_node qnm_apss_noc = {
+ .name = "qnm_apss_noc",
+ .id = SM8650_MASTER_APSS_NOC,
+ .channels = 1,
+ .buswidth = 4,
+ .qosbox = &qnm_apss_noc_qos,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_SNOC_GEM_NOC_SF },
+};
+
static struct qcom_icc_node qns_a1noc_snoc = {
.name = "qns_a1noc_snoc",
.id = SM8650_SLAVE_A1NOC_SNOC,
@@ -1325,6 +1656,7 @@ static struct qcom_icc_node * const aggre1_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_aggre1_noc = {
+ .config = &icc_regmap_config,
.nodes = aggre1_noc_nodes,
.num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
};
@@ -1346,6 +1678,7 @@ static struct qcom_icc_node * const aggre2_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_aggre2_noc = {
+ .config = &icc_regmap_config,
.nodes = aggre2_noc_nodes,
.num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
.bcms = aggre2_noc_bcms,
@@ -1429,6 +1762,7 @@ static struct qcom_icc_node * const config_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_config_noc = {
+ .config = &icc_regmap_config,
.nodes = config_noc_nodes,
.num_nodes = ARRAY_SIZE(config_noc_nodes),
.bcms = config_noc_bcms,
@@ -1456,6 +1790,7 @@ static struct qcom_icc_node * const cnoc_main_nodes[] = {
};
static const struct qcom_icc_desc sm8650_cnoc_main = {
+ .config = &icc_regmap_config,
.nodes = cnoc_main_nodes,
.num_nodes = ARRAY_SIZE(cnoc_main_nodes),
.bcms = cnoc_main_bcms,
@@ -1488,6 +1823,7 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_gem_noc = {
+ .config = &icc_regmap_config,
.nodes = gem_noc_nodes,
.num_nodes = ARRAY_SIZE(gem_noc_nodes),
.bcms = gem_noc_bcms,
@@ -1500,6 +1836,7 @@ static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_lpass_ag_noc = {
+ .config = &icc_regmap_config,
.nodes = lpass_ag_noc_nodes,
.num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
};
@@ -1514,6 +1851,7 @@ static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_lpass_lpiaon_noc = {
+ .config = &icc_regmap_config,
.nodes = lpass_lpiaon_noc_nodes,
.num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes),
.bcms = lpass_lpiaon_noc_bcms,
@@ -1526,6 +1864,7 @@ static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_lpass_lpicx_noc = {
+ .config = &icc_regmap_config,
.nodes = lpass_lpicx_noc_nodes,
.num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes),
};
@@ -1569,6 +1908,7 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_mmss_noc = {
+ .config = &icc_regmap_config,
.nodes = mmss_noc_nodes,
.num_nodes = ARRAY_SIZE(mmss_noc_nodes),
.bcms = mmss_noc_bcms,
@@ -1585,6 +1925,7 @@ static struct qcom_icc_node * const nsp_noc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_nsp_noc = {
+ .config = &icc_regmap_config,
.nodes = nsp_noc_nodes,
.num_nodes = ARRAY_SIZE(nsp_noc_nodes),
.bcms = nsp_noc_bcms,
@@ -1604,6 +1945,7 @@ static struct qcom_icc_node * const pcie_anoc_nodes[] = {
};
static const struct qcom_icc_desc sm8650_pcie_anoc = {
+ .config = &icc_regmap_config,
.nodes = pcie_anoc_nodes,
.num_nodes = ARRAY_SIZE(pcie_anoc_nodes),
.bcms = pcie_anoc_bcms,
@@ -1620,9 +1962,11 @@ static struct qcom_icc_node * const system_noc_nodes[] = {
[MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
[MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
[SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+ [MASTER_APSS_NOC] = &qnm_apss_noc,
};
static const struct qcom_icc_desc sm8650_system_noc = {
+ .config = &icc_regmap_config,
.nodes = system_noc_nodes,
.num_nodes = ARRAY_SIZE(system_noc_nodes),
.bcms = system_noc_bcms,
diff --git a/drivers/interconnect/qcom/sm8650.h b/drivers/interconnect/qcom/sm8650.h
index de35c956fe49..b6610225b38a 100644
--- a/drivers/interconnect/qcom/sm8650.h
+++ b/drivers/interconnect/qcom/sm8650.h
@@ -139,5 +139,6 @@
#define SM8650_SLAVE_USB3_0 127
#define SM8650_SLAVE_VENUS_CFG 128
#define SM8650_SLAVE_VSENSE_CTRL_CFG 129
+#define SM8650_MASTER_APSS_NOC 130
#endif
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 2cc2eb24dc8a..1d0100677357 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -89,8 +89,6 @@
* Test module load/unload
*/
-#define MAX_NEED_GC 64
-#define MAX_SAVE_PRIO 72
#define MAX_GC_TIMES 100
#define MIN_GC_NODES 100
#define GC_SLEEP_MS 100
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 1a2ce1a4b456..1efb768b2890 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1733,7 +1733,12 @@ static CLOSURE_CALLBACK(cache_set_flush)
mutex_unlock(&b->write_lock);
}
- if (ca->alloc_thread)
+ /*
+ * If the register_cache_set() call to bch_cache_set_alloc() failed,
+ * ca has not been assigned a value and return error.
+ * So we need check ca is not NULL during bch_cache_set_unregister().
+ */
+ if (ca && ca->alloc_thread)
kthread_stop(ca->alloc_thread);
if (c->journal.cur) {
@@ -2233,15 +2238,47 @@ static int cache_alloc(struct cache *ca)
bio_init(&ca->journal.bio, NULL, ca->journal.bio.bi_inline_vecs, 8, 0);
/*
- * when ca->sb.njournal_buckets is not zero, journal exists,
- * and in bch_journal_replay(), tree node may split,
- * so bucket of RESERVE_BTREE type is needed,
- * the worst situation is all journal buckets are valid journal,
- * and all the keys need to replay,
- * so the number of RESERVE_BTREE type buckets should be as much
- * as journal buckets
+ * When the cache disk is first registered, ca->sb.njournal_buckets
+ * is zero, and it is assigned in run_cache_set().
+ *
+ * When ca->sb.njournal_buckets is not zero, journal exists,
+ * and in bch_journal_replay(), tree node may split.
+ * The worst situation is all journal buckets are valid journal,
+ * and all the keys need to replay, so the number of RESERVE_BTREE
+ * type buckets should be as much as journal buckets.
+ *
+ * If the number of RESERVE_BTREE type buckets is too few, the
+ * bch_allocator_thread() may hang up and unable to allocate
+ * bucket. The situation is roughly as follows:
+ *
+ * 1. In bch_data_insert_keys(), if the operation is not op->replace,
+ * it will call the bch_journal(), which increments the journal_ref
+ * counter. This counter is only decremented after bch_btree_insert
+ * completes.
+ *
+ * 2. When calling bch_btree_insert, if the btree needs to split,
+ * it will call btree_split() and btree_check_reserve() to check
+ * whether there are enough reserved buckets in the RESERVE_BTREE
+ * slot. If not enough, bcache_btree_root() will repeatedly retry.
+ *
+ * 3. Normally, the bch_allocator_thread is responsible for filling
+ * the reservation slots from the free_inc bucket list. When the
+ * free_inc bucket list is exhausted, the bch_allocator_thread
+ * will call invalidate_buckets() until free_inc is refilled.
+ * Then bch_allocator_thread calls bch_prio_write() once. and
+ * bch_prio_write() will call bch_journal_meta() and waits for
+ * the journal write to complete.
+ *
+ * 4. During journal_write, journal_write_unlocked() is be called.
+ * If journal full occurs, journal_reclaim() and btree_flush_write()
+ * will be called sequentially, then retry journal_write.
+ *
+ * 5. When 2 and 4 occur together, IO will hung up and cannot recover.
+ *
+ * Therefore, reserve more RESERVE_BTREE type buckets.
*/
- btree_buckets = ca->sb.njournal_buckets ?: 8;
+ btree_buckets = clamp_t(size_t, ca->sb.nbuckets >> 7,
+ 32, SB_JOURNAL_BUCKETS);
free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
if (!free) {
ret = -EPERM;
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 127138c61be5..d296770478b2 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -1356,11 +1356,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
return -EINVAL;
}
- /*
- * In device-mapper, we specify things in sectors, but
- * MD records this value in kB
- */
- if (value < 0 || value / 2 > COUNTER_MAX) {
+ if (value < 0) {
rs->ti->error = "Max write-behind limit out of range";
return -EINVAL;
}
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 37b08f26c62f..bd694910b01b 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -105,9 +105,19 @@
*
*/
+typedef __u16 bitmap_counter_t;
+
#define PAGE_BITS (PAGE_SIZE << 3)
#define PAGE_BIT_SHIFT (PAGE_SHIFT + 3)
+#define COUNTER_BITS 16
+#define COUNTER_BIT_SHIFT 4
+#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3)
+
+#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1)))
+#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2)))
+#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1)
+
#define NEEDED(x) (((bitmap_counter_t) x) & NEEDED_MASK)
#define RESYNC(x) (((bitmap_counter_t) x) & RESYNC_MASK)
#define COUNTER(x) (((bitmap_counter_t) x) & COUNTER_MAX)
@@ -789,7 +799,7 @@ static int md_bitmap_new_disk_sb(struct bitmap *bitmap)
* is a good choice? We choose COUNTER_MAX / 2 arbitrarily.
*/
write_behind = bitmap->mddev->bitmap_info.max_write_behind;
- if (write_behind > COUNTER_MAX)
+ if (write_behind > COUNTER_MAX / 2)
write_behind = COUNTER_MAX / 2;
sb->write_behind = cpu_to_le32(write_behind);
bitmap->mddev->bitmap_info.max_write_behind = write_behind;
@@ -1672,13 +1682,13 @@ __acquires(bitmap->lock)
&(bitmap->bp[page].map[pageoff]);
}
-static int bitmap_startwrite(struct mddev *mddev, sector_t offset,
- unsigned long sectors)
+static void bitmap_start_write(struct mddev *mddev, sector_t offset,
+ unsigned long sectors)
{
struct bitmap *bitmap = mddev->bitmap;
if (!bitmap)
- return 0;
+ return;
while (sectors) {
sector_t blocks;
@@ -1688,7 +1698,7 @@ static int bitmap_startwrite(struct mddev *mddev, sector_t offset,
bmc = md_bitmap_get_counter(&bitmap->counts, offset, &blocks, 1);
if (!bmc) {
spin_unlock_irq(&bitmap->counts.lock);
- return 0;
+ return;
}
if (unlikely(COUNTER(*bmc) == COUNTER_MAX)) {
@@ -1724,11 +1734,10 @@ static int bitmap_startwrite(struct mddev *mddev, sector_t offset,
else
sectors = 0;
}
- return 0;
}
-static void bitmap_endwrite(struct mddev *mddev, sector_t offset,
- unsigned long sectors)
+static void bitmap_end_write(struct mddev *mddev, sector_t offset,
+ unsigned long sectors)
{
struct bitmap *bitmap = mddev->bitmap;
@@ -2205,9 +2214,9 @@ static struct bitmap *__bitmap_create(struct mddev *mddev, int slot)
return ERR_PTR(err);
}
-static int bitmap_create(struct mddev *mddev, int slot)
+static int bitmap_create(struct mddev *mddev)
{
- struct bitmap *bitmap = __bitmap_create(mddev, slot);
+ struct bitmap *bitmap = __bitmap_create(mddev, -1);
if (IS_ERR(bitmap))
return PTR_ERR(bitmap);
@@ -2670,7 +2679,7 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
}
mddev->bitmap_info.offset = offset;
- rv = bitmap_create(mddev, -1);
+ rv = bitmap_create(mddev);
if (rv)
goto out;
@@ -3003,8 +3012,8 @@ static struct bitmap_operations bitmap_ops = {
.end_behind_write = bitmap_end_behind_write,
.wait_behind_writes = bitmap_wait_behind_writes,
- .startwrite = bitmap_startwrite,
- .endwrite = bitmap_endwrite,
+ .start_write = bitmap_start_write,
+ .end_write = bitmap_end_write,
.start_sync = bitmap_start_sync,
.end_sync = bitmap_end_sync,
.cond_end_sync = bitmap_cond_end_sync,
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index 31c93019c76b..59e9dd45cfde 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -9,15 +9,6 @@
#define BITMAP_MAGIC 0x6d746962
-typedef __u16 bitmap_counter_t;
-#define COUNTER_BITS 16
-#define COUNTER_BIT_SHIFT 4
-#define COUNTER_BYTE_SHIFT (COUNTER_BIT_SHIFT - 3)
-
-#define NEEDED_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 1)))
-#define RESYNC_MASK ((bitmap_counter_t) (1 << (COUNTER_BITS - 2)))
-#define COUNTER_MAX ((bitmap_counter_t) RESYNC_MASK - 1)
-
/* use these for bitmap->flags and bitmap->sb->state bit-fields */
enum bitmap_state {
BITMAP_STALE = 1, /* the bitmap file is out of date or had -EIO */
@@ -72,7 +63,7 @@ struct md_bitmap_stats {
struct bitmap_operations {
bool (*enabled)(struct mddev *mddev);
- int (*create)(struct mddev *mddev, int slot);
+ int (*create)(struct mddev *mddev);
int (*resize)(struct mddev *mddev, sector_t blocks, int chunksize,
bool init);
@@ -89,10 +80,10 @@ struct bitmap_operations {
void (*end_behind_write)(struct mddev *mddev);
void (*wait_behind_writes)(struct mddev *mddev);
- int (*startwrite)(struct mddev *mddev, sector_t offset,
+ void (*start_write)(struct mddev *mddev, sector_t offset,
+ unsigned long sectors);
+ void (*end_write)(struct mddev *mddev, sector_t offset,
unsigned long sectors);
- void (*endwrite)(struct mddev *mddev, sector_t offset,
- unsigned long sectors);
bool (*start_sync)(struct mddev *mddev, sector_t offset,
sector_t *blocks, bool degraded);
void (*end_sync)(struct mddev *mddev, sector_t offset, sector_t *blocks);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0fde115e921f..09042b060086 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6225,7 +6225,7 @@ int md_run(struct mddev *mddev)
}
if (err == 0 && pers->sync_request &&
(mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
- err = mddev->bitmap_ops->create(mddev, -1);
+ err = mddev->bitmap_ops->create(mddev);
if (err)
pr_warn("%s: failed to create bitmap (%d)\n",
mdname(mddev), err);
@@ -7285,7 +7285,7 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
err = 0;
if (mddev->pers) {
if (fd >= 0) {
- err = mddev->bitmap_ops->create(mddev, -1);
+ err = mddev->bitmap_ops->create(mddev);
if (!err)
err = mddev->bitmap_ops->load(mddev);
@@ -7601,7 +7601,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->bitmap_info.default_offset;
mddev->bitmap_info.space =
mddev->bitmap_info.default_space;
- rv = mddev->bitmap_ops->create(mddev, -1);
+ rv = mddev->bitmap_ops->create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
@@ -8799,14 +8799,14 @@ static void md_bitmap_start(struct mddev *mddev,
mddev->pers->bitmap_sector(mddev, &md_io_clone->offset,
&md_io_clone->sectors);
- mddev->bitmap_ops->startwrite(mddev, md_io_clone->offset,
- md_io_clone->sectors);
+ mddev->bitmap_ops->start_write(mddev, md_io_clone->offset,
+ md_io_clone->sectors);
}
static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone)
{
- mddev->bitmap_ops->endwrite(mddev, md_io_clone->offset,
- md_io_clone->sectors);
+ mddev->bitmap_ops->end_write(mddev, md_io_clone->offset,
+ md_io_clone->sectors);
}
static void md_end_clone_io(struct bio *bio)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index c7efd8aab675..b8b3a9069701 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -293,3 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,
return false;
}
+
+/*
+ * bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is
+ * submitted to the underlying disks, hence don't record badblocks or retry
+ * in this case.
+ */
+static inline bool raid1_should_handle_error(struct bio *bio)
+{
+ return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT));
+}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 657d481525be..19c5a0ce5a40 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -373,14 +373,16 @@ static void raid1_end_read_request(struct bio *bio)
*/
update_head_pos(r1_bio->read_disk, r1_bio);
- if (uptodate)
+ if (uptodate) {
set_bit(R1BIO_Uptodate, &r1_bio->state);
- else if (test_bit(FailFast, &rdev->flags) &&
- test_bit(R1BIO_FailFast, &r1_bio->state))
+ } else if (test_bit(FailFast, &rdev->flags) &&
+ test_bit(R1BIO_FailFast, &r1_bio->state)) {
/* This was a fail-fast read so we definitely
* want to retry */
;
- else {
+ } else if (!raid1_should_handle_error(bio)) {
+ uptodate = 1;
+ } else {
/* If all other devices have failed, we want to return
* the error upwards rather than fail the last device.
* Here we redefine "uptodate" to mean "Don't want to retry"
@@ -451,16 +453,15 @@ static void raid1_end_write_request(struct bio *bio)
struct bio *to_put = NULL;
int mirror = find_bio_disk(r1_bio, bio);
struct md_rdev *rdev = conf->mirrors[mirror].rdev;
- bool discard_error;
sector_t lo = r1_bio->sector;
sector_t hi = r1_bio->sector + r1_bio->sectors;
-
- discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD;
+ bool ignore_error = !raid1_should_handle_error(bio) ||
+ (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
/*
* 'one mirror IO has finished' event handler:
*/
- if (bio->bi_status && !discard_error) {
+ if (bio->bi_status && !ignore_error) {
set_bit(WriteErrorSeen, &rdev->flags);
if (!test_and_set_bit(WantReplacement, &rdev->flags))
set_bit(MD_RECOVERY_NEEDED, &
@@ -511,7 +512,7 @@ static void raid1_end_write_request(struct bio *bio)
/* Maybe we can clear some bad blocks. */
if (rdev_has_badblock(rdev, r1_bio->sector, r1_bio->sectors) &&
- !discard_error) {
+ !ignore_error) {
r1_bio->bios[mirror] = IO_MADE_GOOD;
set_bit(R1BIO_MadeGood, &r1_bio->state);
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index dce06bf65016..b74780af4c22 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -399,6 +399,8 @@ static void raid10_end_read_request(struct bio *bio)
* wait for the 'master' bio.
*/
set_bit(R10BIO_Uptodate, &r10_bio->state);
+ } else if (!raid1_should_handle_error(bio)) {
+ uptodate = 1;
} else {
/* If all other devices that store this block have
* failed, we want to return the error upwards rather
@@ -456,9 +458,8 @@ static void raid10_end_write_request(struct bio *bio)
int slot, repl;
struct md_rdev *rdev = NULL;
struct bio *to_put = NULL;
- bool discard_error;
-
- discard_error = bio->bi_status && bio_op(bio) == REQ_OP_DISCARD;
+ bool ignore_error = !raid1_should_handle_error(bio) ||
+ (bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
@@ -472,7 +473,7 @@ static void raid10_end_write_request(struct bio *bio)
/*
* this branch is our 'one mirror IO has finished' event handler:
*/
- if (bio->bi_status && !discard_error) {
+ if (bio->bi_status && !ignore_error) {
if (repl)
/* Never record new bad blocks to replacement,
* just fail it.
@@ -527,7 +528,7 @@ static void raid10_end_write_request(struct bio *bio)
/* Maybe we can clear some bad blocks. */
if (rdev_has_badblock(rdev, r10_bio->devs[slot].addr,
r10_bio->sectors) &&
- !discard_error) {
+ !ignore_error) {
bio_put(bio);
if (repl)
r10_bio->devs[slot].repl_bio = IO_MADE_GOOD;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c161546d728f..b9ca56930003 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -652,7 +652,6 @@ source "drivers/misc/altera-stapl/Kconfig"
source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig"
source "drivers/misc/genwqe/Kconfig"
-source "drivers/misc/echo/Kconfig"
source "drivers/misc/ocxl/Kconfig"
source "drivers/misc/bcm-vk/Kconfig"
source "drivers/misc/cardreader/Kconfig"
@@ -660,4 +659,5 @@ source "drivers/misc/uacce/Kconfig"
source "drivers/misc/pvpanic/Kconfig"
source "drivers/misc/mchp_pci1xxxx/Kconfig"
source "drivers/misc/keba/Kconfig"
+source "drivers/misc/amd-sbi/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 054cee9b08a4..917b9a7183aa 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -50,7 +50,6 @@ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-$(CONFIG_SRAM_EXEC) += sram-exec.o
obj-$(CONFIG_GENWQE) += genwqe/
-obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_DW_XDATA_PCIE) += dw-xdata-pcie.o
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
obj-$(CONFIG_OCXL) += ocxl/
@@ -75,3 +74,4 @@ lan966x-pci-objs := lan966x_pci.o
lan966x-pci-objs += lan966x_pci.dtbo.o
obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
obj-y += keba/
+obj-y += amd-sbi/
diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
new file mode 100644
index 000000000000..4840831c84ca
--- /dev/null
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config AMD_SBRMI_I2C
+ tristate "AMD side band RMI support"
+ depends on I2C
+ help
+ Side band RMI over I2C support for AMD out of band management.
+
+ This driver can also be built as a module. If so, the module will
+ be called sbrmi-i2c.
+
+config AMD_SBRMI_HWMON
+ bool "SBRMI hardware monitoring"
+ depends on AMD_SBRMI_I2C && HWMON
+ depends on !(AMD_SBRMI_I2C=y && HWMON=m)
+ help
+ This provides support for RMI device hardware monitoring. If enabled,
+ a hardware monitoring device will be created for each socket in
+ the system.
diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile
new file mode 100644
index 000000000000..38eaaa651fd9
--- /dev/null
+++ b/drivers/misc/amd-sbi/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+sbrmi-i2c-objs += rmi-i2c.o rmi-core.o
+sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON) += rmi-hwmon.o
+obj-$(CONFIG_AMD_SBRMI_I2C) += sbrmi-i2c.o
diff --git a/drivers/misc/amd-sbi/rmi-core.c b/drivers/misc/amd-sbi/rmi-core.c
new file mode 100644
index 000000000000..b653a21a909e
--- /dev/null
+++ b/drivers/misc/amd-sbi/rmi-core.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * sbrmi-core.c - file defining SB-RMI protocols compliant
+ * AMD SoC device.
+ *
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include "rmi-core.h"
+
+/* Mask for Status Register bit[1] */
+#define SW_ALERT_MASK 0x2
+/* Mask to check H/W Alert status bit */
+#define HW_ALERT_MASK 0x80
+
+/* Software Interrupt for triggering */
+#define START_CMD 0x80
+#define TRIGGER_MAILBOX 0x01
+
+/* Default message lengths as per APML command protocol */
+/* CPUID */
+#define CPUID_RD_DATA_LEN 0x8
+#define CPUID_WR_DATA_LEN 0x8
+#define CPUID_RD_REG_LEN 0xa
+#define CPUID_WR_REG_LEN 0x9
+/* MSR */
+#define MSR_RD_REG_LEN 0xa
+#define MSR_WR_REG_LEN 0x8
+#define MSR_RD_DATA_LEN 0x8
+#define MSR_WR_DATA_LEN 0x7
+
+/* CPUID MSR Command Ids */
+#define CPUID_MCA_CMD 0x73
+#define RD_CPUID_CMD 0x91
+#define RD_MCA_CMD 0x86
+
+/* CPUID MCAMSR mask & index */
+#define CPUID_MCA_THRD_MASK GENMASK(15, 0)
+#define CPUID_MCA_THRD_INDEX 32
+#define CPUID_MCA_FUNC_MASK GENMASK(31, 0)
+#define CPUID_EXT_FUNC_INDEX 56
+
+/* input for bulk write to CPUID protocol */
+struct cpu_msr_indata {
+ u8 wr_len; /* const value */
+ u8 rd_len; /* const value */
+ u8 proto_cmd; /* const value */
+ u8 thread; /* thread number */
+ union {
+ u8 reg_offset[4]; /* input value */
+ u32 value;
+ } __packed;
+ u8 ext; /* extended function */
+};
+
+/* output for bulk read from CPUID protocol */
+struct cpu_msr_outdata {
+ u8 num_bytes; /* number of bytes return */
+ u8 status; /* Protocol status code */
+ union {
+ u64 value;
+ u8 reg_data[8];
+ } __packed;
+};
+
+static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input,
+ u8 thread_id, u32 func,
+ u8 ext_func)
+{
+ input->rd_len = CPUID_RD_DATA_LEN;
+ input->wr_len = CPUID_WR_DATA_LEN;
+ input->proto_cmd = RD_CPUID_CMD;
+ input->thread = thread_id << 1;
+ input->value = func;
+ input->ext = ext_func;
+}
+
+static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input,
+ u8 thread_id, u32 data_in)
+{
+ input->rd_len = MSR_RD_DATA_LEN;
+ input->wr_len = MSR_WR_DATA_LEN;
+ input->proto_cmd = RD_MCA_CMD;
+ input->thread = thread_id << 1;
+ input->value = data_in;
+}
+
+static int sbrmi_get_rev(struct sbrmi_data *data)
+{
+ unsigned int rev;
+ u16 offset = SBRMI_REV;
+ int ret;
+
+ ret = regmap_read(data->regmap, offset, &rev);
+ if (ret < 0)
+ return ret;
+
+ data->rev = rev;
+ return 0;
+}
+
+/* Read CPUID function protocol */
+static int rmi_cpuid_read(struct sbrmi_data *data,
+ struct apml_cpuid_msg *msg)
+{
+ struct cpu_msr_indata input = {0};
+ struct cpu_msr_outdata output = {0};
+ int val = 0;
+ int ret, hw_status;
+ u16 thread;
+
+ mutex_lock(&data->lock);
+ /* cache the rev value to identify if protocol is supported or not */
+ if (!data->rev) {
+ ret = sbrmi_get_rev(data);
+ if (ret < 0)
+ goto exit_unlock;
+ }
+ /* CPUID protocol for REV 0x10 is not supported*/
+ if (data->rev == 0x10) {
+ ret = -EOPNOTSUPP;
+ goto exit_unlock;
+ }
+
+ thread = msg->cpu_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK;
+
+ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
+ if (thread > 127) {
+ thread -= 128;
+ val = 1;
+ }
+ ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
+ if (ret < 0)
+ goto exit_unlock;
+
+ prepare_cpuid_input_message(&input, thread,
+ msg->cpu_in_out & CPUID_MCA_FUNC_MASK,
+ msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX);
+
+ ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
+ &input, CPUID_WR_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * For RMI Rev 0x20, new h/w status bit is introduced. which is used
+ * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
+ * wait for the status bit to be set by the hardware before
+ * reading the data out.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
+ hw_status & HW_ALERT_MASK, 500, 2000000);
+ if (ret)
+ goto exit_unlock;
+
+ ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
+ &output, CPUID_RD_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ ret = regmap_write(data->regmap, SBRMI_STATUS,
+ HW_ALERT_MASK);
+ if (ret < 0)
+ goto exit_unlock;
+
+ if (output.num_bytes != CPUID_RD_REG_LEN - 1) {
+ ret = -EMSGSIZE;
+ goto exit_unlock;
+ }
+ if (output.status) {
+ ret = -EPROTOTYPE;
+ msg->fw_ret_code = output.status;
+ goto exit_unlock;
+ }
+ msg->cpu_in_out = output.value;
+exit_unlock:
+ if (ret < 0)
+ msg->cpu_in_out = 0;
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/* MCA MSR protocol */
+static int rmi_mca_msr_read(struct sbrmi_data *data,
+ struct apml_mcamsr_msg *msg)
+{
+ struct cpu_msr_outdata output = {0};
+ struct cpu_msr_indata input = {0};
+ int ret, val = 0;
+ int hw_status;
+ u16 thread;
+
+ mutex_lock(&data->lock);
+ /* cache the rev value to identify if protocol is supported or not */
+ if (!data->rev) {
+ ret = sbrmi_get_rev(data);
+ if (ret < 0)
+ goto exit_unlock;
+ }
+ /* MCA MSR protocol for REV 0x10 is not supported*/
+ if (data->rev == 0x10) {
+ ret = -EOPNOTSUPP;
+ goto exit_unlock;
+ }
+
+ thread = msg->mcamsr_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK;
+
+ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
+ if (thread > 127) {
+ thread -= 128;
+ val = 1;
+ }
+ ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
+ if (ret < 0)
+ goto exit_unlock;
+
+ prepare_mca_msr_input_message(&input, thread,
+ msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK);
+
+ ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
+ &input, MSR_WR_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * For RMI Rev 0x20, new h/w status bit is introduced. which is used
+ * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
+ * wait for the status bit to be set by the hardware before
+ * reading the data out.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
+ hw_status & HW_ALERT_MASK, 500, 2000000);
+ if (ret)
+ goto exit_unlock;
+
+ ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
+ &output, MSR_RD_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ ret = regmap_write(data->regmap, SBRMI_STATUS,
+ HW_ALERT_MASK);
+ if (ret < 0)
+ goto exit_unlock;
+
+ if (output.num_bytes != MSR_RD_REG_LEN - 1) {
+ ret = -EMSGSIZE;
+ goto exit_unlock;
+ }
+ if (output.status) {
+ ret = -EPROTOTYPE;
+ msg->fw_ret_code = output.status;
+ goto exit_unlock;
+ }
+ msg->mcamsr_in_out = output.value;
+
+exit_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+int rmi_mailbox_xfer(struct sbrmi_data *data,
+ struct apml_mbox_msg *msg)
+{
+ unsigned int bytes, ec;
+ int i, ret;
+ int sw_status;
+ u8 byte;
+
+ mutex_lock(&data->lock);
+
+ msg->fw_ret_code = 0;
+
+ /* Indicate firmware a command is to be serviced */
+ ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /* Write the command to SBRMI::InBndMsg_inst0 */
+ ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * For both read and write the initiator (BMC) writes
+ * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1]
+ * SBRMI_x3C(MSB):SBRMI_x39(LSB)
+ */
+ for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) {
+ byte = (msg->mb_in_out >> i * 8) & 0xff;
+ ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte);
+ if (ret < 0)
+ goto exit_unlock;
+ }
+
+ /*
+ * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to
+ * perform the requested read or write command
+ */
+ ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate
+ * an ALERT (if enabled) to initiator (BMC) to indicate completion
+ * of the requested command
+ */
+ ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, sw_status,
+ sw_status & SW_ALERT_MASK, 500, 2000000);
+ if (ret)
+ goto exit_unlock;
+
+ ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG7, &ec);
+ if (ret || ec)
+ goto exit_clear_alert;
+ /*
+ * For a read operation, the initiator (BMC) reads the firmware
+ * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1]
+ * {SBRMI_x34(MSB):SBRMI_x31(LSB)}.
+ */
+ for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) {
+ ret = regmap_read(data->regmap,
+ SBRMI_OUTBNDMSG1 + i, &bytes);
+ if (ret < 0)
+ break;
+ msg->mb_in_out |= bytes << i * 8;
+ }
+
+exit_clear_alert:
+ /*
+ * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the
+ * ALERT to initiator
+ */
+ ret = regmap_write(data->regmap, SBRMI_STATUS,
+ sw_status | SW_ALERT_MASK);
+ if (ec) {
+ ret = -EPROTOTYPE;
+ msg->fw_ret_code = ec;
+ }
+exit_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int apml_rmi_reg_xfer(struct sbrmi_data *data,
+ struct apml_reg_xfer_msg __user *arg)
+{
+ struct apml_reg_xfer_msg msg = { 0 };
+ unsigned int data_read;
+ int ret;
+
+ /* Copy the structure from user */
+ if (copy_from_user(&msg, arg, sizeof(struct apml_reg_xfer_msg)))
+ return -EFAULT;
+
+ mutex_lock(&data->lock);
+ if (msg.rflag) {
+ ret = regmap_read(data->regmap, msg.reg_addr, &data_read);
+ if (!ret)
+ msg.data_in_out = data_read;
+ } else {
+ ret = regmap_write(data->regmap, msg.reg_addr, msg.data_in_out);
+ }
+
+ mutex_unlock(&data->lock);
+
+ if (msg.rflag && !ret)
+ return copy_to_user(arg, &msg, sizeof(struct apml_reg_xfer_msg));
+ return ret;
+}
+
+static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __user *arg)
+{
+ struct apml_mbox_msg msg = { 0 };
+ int ret;
+
+ /* Copy the structure from user */
+ if (copy_from_user(&msg, arg, sizeof(struct apml_mbox_msg)))
+ return -EFAULT;
+
+ /* Mailbox protocol */
+ ret = rmi_mailbox_xfer(data, &msg);
+ if (ret && ret != -EPROTOTYPE)
+ return ret;
+
+ return copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg));
+}
+
+static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg)
+{
+ struct apml_cpuid_msg msg = { 0 };
+ int ret;
+
+ /* Copy the structure from user */
+ if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg)))
+ return -EFAULT;
+
+ /* CPUID Protocol */
+ ret = rmi_cpuid_read(data, &msg);
+ if (ret && ret != -EPROTOTYPE)
+ return ret;
+
+ return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg));
+}
+
+static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg)
+{
+ struct apml_mcamsr_msg msg = { 0 };
+ int ret;
+
+ /* Copy the structure from user */
+ if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg)))
+ return -EFAULT;
+
+ /* MCAMSR Protocol */
+ ret = rmi_mca_msr_read(data, &msg);
+ if (ret && ret != -EPROTOTYPE)
+ return ret;
+
+ return copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg));
+}
+
+static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct sbrmi_data *data;
+
+ data = container_of(fp->private_data, struct sbrmi_data, sbrmi_misc_dev);
+ switch (cmd) {
+ case SBRMI_IOCTL_MBOX_CMD:
+ return apml_mailbox_xfer(data, argp);
+ case SBRMI_IOCTL_CPUID_CMD:
+ return apml_cpuid_xfer(data, argp);
+ case SBRMI_IOCTL_MCAMSR_CMD:
+ return apml_mcamsr_xfer(data, argp);
+ case SBRMI_IOCTL_REG_XFER_CMD:
+ return apml_rmi_reg_xfer(data, argp);
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations sbrmi_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = sbrmi_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+};
+
+int create_misc_rmi_device(struct sbrmi_data *data,
+ struct device *dev)
+{
+ data->sbrmi_misc_dev.name = devm_kasprintf(dev,
+ GFP_KERNEL,
+ "sbrmi-%x",
+ data->dev_static_addr);
+ data->sbrmi_misc_dev.minor = MISC_DYNAMIC_MINOR;
+ data->sbrmi_misc_dev.fops = &sbrmi_fops;
+ data->sbrmi_misc_dev.parent = dev;
+ data->sbrmi_misc_dev.nodename = devm_kasprintf(dev,
+ GFP_KERNEL,
+ "sbrmi-%x",
+ data->dev_static_addr);
+ data->sbrmi_misc_dev.mode = 0600;
+
+ return misc_register(&data->sbrmi_misc_dev);
+}
diff --git a/drivers/misc/amd-sbi/rmi-core.h b/drivers/misc/amd-sbi/rmi-core.h
new file mode 100644
index 000000000000..975ae858e9fd
--- /dev/null
+++ b/drivers/misc/amd-sbi/rmi-core.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _SBRMI_CORE_H_
+#define _SBRMI_CORE_H_
+
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <uapi/misc/amd-apml.h>
+
+/* SB-RMI registers */
+enum sbrmi_reg {
+ SBRMI_REV,
+ SBRMI_CTRL,
+ SBRMI_STATUS,
+ SBRMI_OUTBNDMSG0 = 0x30,
+ SBRMI_OUTBNDMSG1,
+ SBRMI_OUTBNDMSG2,
+ SBRMI_OUTBNDMSG3,
+ SBRMI_OUTBNDMSG4,
+ SBRMI_OUTBNDMSG5,
+ SBRMI_OUTBNDMSG6,
+ SBRMI_OUTBNDMSG7,
+ SBRMI_INBNDMSG0,
+ SBRMI_INBNDMSG1,
+ SBRMI_INBNDMSG2,
+ SBRMI_INBNDMSG3,
+ SBRMI_INBNDMSG4,
+ SBRMI_INBNDMSG5,
+ SBRMI_INBNDMSG6,
+ SBRMI_INBNDMSG7,
+ SBRMI_SW_INTERRUPT,
+ SBRMI_THREAD128CS = 0x4b,
+};
+
+/*
+ * SB-RMI supports soft mailbox service request to MP1 (power management
+ * firmware) through SBRMI inbound/outbound message registers.
+ * SB-RMI message IDs
+ */
+enum sbrmi_msg_id {
+ SBRMI_READ_PKG_PWR_CONSUMPTION = 0x1,
+ SBRMI_WRITE_PKG_PWR_LIMIT,
+ SBRMI_READ_PKG_PWR_LIMIT,
+ SBRMI_READ_PKG_MAX_PWR_LIMIT,
+};
+
+/* Each client has this additional data */
+struct sbrmi_data {
+ struct miscdevice sbrmi_misc_dev;
+ struct regmap *regmap;
+ /* Mutex locking */
+ struct mutex lock;
+ u32 pwr_limit_max;
+ u8 dev_static_addr;
+ u8 rev;
+};
+
+int rmi_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg *msg);
+#ifdef CONFIG_AMD_SBRMI_HWMON
+int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data);
+#else
+static inline int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data)
+{
+ return 0;
+}
+#endif
+int create_misc_rmi_device(struct sbrmi_data *data, struct device *dev);
+#endif /*_SBRMI_CORE_H_*/
diff --git a/drivers/misc/amd-sbi/rmi-hwmon.c b/drivers/misc/amd-sbi/rmi-hwmon.c
new file mode 100644
index 000000000000..f4f015605daa
--- /dev/null
+++ b/drivers/misc/amd-sbi/rmi-hwmon.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rmi-hwmon.c - hwmon sensor support for side band RMI
+ *
+ * Copyright (C) 2025 Advanced Micro Devices, Inc.
+ */
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <uapi/misc/amd-apml.h>
+#include "rmi-core.h"
+
+/* Do not allow setting negative power limit */
+#define SBRMI_PWR_MIN 0
+
+static int sbrmi_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct sbrmi_data *data = dev_get_drvdata(dev);
+ struct apml_mbox_msg msg = { 0 };
+ int ret;
+
+ if (!data)
+ return -ENODEV;
+
+ if (type != hwmon_power)
+ return -EINVAL;
+
+ switch (attr) {
+ case hwmon_power_input:
+ msg.cmd = SBRMI_READ_PKG_PWR_CONSUMPTION;
+ ret = rmi_mailbox_xfer(data, &msg);
+ break;
+ case hwmon_power_cap:
+ msg.cmd = SBRMI_READ_PKG_PWR_LIMIT;
+ ret = rmi_mailbox_xfer(data, &msg);
+ break;
+ case hwmon_power_cap_max:
+ msg.mb_in_out = data->pwr_limit_max;
+ ret = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return ret;
+ /* hwmon power attributes are in microWatt */
+ *val = (long)msg.mb_in_out * 1000;
+ return ret;
+}
+
+static int sbrmi_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
+ struct sbrmi_data *data = dev_get_drvdata(dev);
+ struct apml_mbox_msg msg = { 0 };
+
+ if (!data)
+ return -ENODEV;
+
+ if (type != hwmon_power && attr != hwmon_power_cap)
+ return -EINVAL;
+ /*
+ * hwmon power attributes are in microWatt
+ * mailbox read/write is in mWatt
+ */
+ val /= 1000;
+
+ val = clamp_val(val, SBRMI_PWR_MIN, data->pwr_limit_max);
+
+ msg.cmd = SBRMI_WRITE_PKG_PWR_LIMIT;
+ msg.mb_in_out = val;
+
+ return rmi_mailbox_xfer(data, &msg);
+}
+
+static umode_t sbrmi_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ switch (type) {
+ case hwmon_power:
+ switch (attr) {
+ case hwmon_power_input:
+ case hwmon_power_cap_max:
+ return 0444;
+ case hwmon_power_cap:
+ return 0644;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static const struct hwmon_channel_info * const sbrmi_info[] = {
+ HWMON_CHANNEL_INFO(power,
+ HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
+ NULL
+};
+
+static const struct hwmon_ops sbrmi_hwmon_ops = {
+ .is_visible = sbrmi_is_visible,
+ .read = sbrmi_read,
+ .write = sbrmi_write,
+};
+
+static const struct hwmon_chip_info sbrmi_chip_info = {
+ .ops = &sbrmi_hwmon_ops,
+ .info = sbrmi_info,
+};
+
+int create_hwmon_sensor_device(struct device *dev, struct sbrmi_data *data)
+{
+ struct device *hwmon_dev;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi", data,
+ &sbrmi_chip_info, NULL);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
diff --git a/drivers/misc/amd-sbi/rmi-i2c.c b/drivers/misc/amd-sbi/rmi-i2c.c
new file mode 100644
index 000000000000..f891f5af4bc6
--- /dev/null
+++ b/drivers/misc/amd-sbi/rmi-i2c.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * rmi-i2c.c - Side band RMI over I2C support for AMD out
+ * of band management
+ *
+ * Copyright (C) 2024 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include "rmi-core.h"
+
+static int sbrmi_enable_alert(struct sbrmi_data *data)
+{
+ int ctrl, ret;
+
+ /*
+ * Enable the SB-RMI Software alert status
+ * by writing 0 to bit 4 of Control register(0x1)
+ */
+ ret = regmap_read(data->regmap, SBRMI_CTRL, &ctrl);
+ if (ret < 0)
+ return ret;
+
+ if (ctrl & 0x10) {
+ ctrl &= ~0x10;
+ return regmap_write(data->regmap, SBRMI_CTRL, ctrl);
+ }
+
+ return 0;
+}
+
+static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data)
+{
+ struct apml_mbox_msg msg = { 0 };
+ int ret;
+
+ msg.cmd = SBRMI_READ_PKG_MAX_PWR_LIMIT;
+ ret = rmi_mailbox_xfer(data, &msg);
+ if (ret < 0)
+ return ret;
+ data->pwr_limit_max = msg.mb_in_out;
+
+ return ret;
+}
+
+static int sbrmi_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct sbrmi_data *data;
+ struct regmap_config sbrmi_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(struct sbrmi_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ mutex_init(&data->lock);
+
+ data->regmap = devm_regmap_init_i2c(client, &sbrmi_i2c_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ /* Enable alert for SB-RMI sequence */
+ ret = sbrmi_enable_alert(data);
+ if (ret < 0)
+ return ret;
+
+ /* Cache maximum power limit */
+ ret = sbrmi_get_max_pwr_limit(data);
+ if (ret < 0)
+ return ret;
+
+ data->dev_static_addr = client->addr;
+ dev_set_drvdata(dev, data);
+
+ ret = create_hwmon_sensor_device(dev, data);
+ if (ret < 0)
+ return ret;
+ return create_misc_rmi_device(data, dev);
+}
+
+static void sbrmi_i2c_remove(struct i2c_client *client)
+{
+ struct sbrmi_data *data = dev_get_drvdata(&client->dev);
+
+ misc_deregister(&data->sbrmi_misc_dev);
+ /* Assign fops and parent of misc dev to NULL */
+ data->sbrmi_misc_dev.fops = NULL;
+ data->sbrmi_misc_dev.parent = NULL;
+ dev_info(&client->dev, "Removed sbrmi-i2c driver\n");
+ return;
+}
+
+static const struct i2c_device_id sbrmi_id[] = {
+ {"sbrmi-i2c"},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, sbrmi_id);
+
+static const struct of_device_id __maybe_unused sbrmi_of_match[] = {
+ {
+ .compatible = "amd,sbrmi",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sbrmi_of_match);
+
+static struct i2c_driver sbrmi_driver = {
+ .driver = {
+ .name = "sbrmi-i2c",
+ .of_match_table = of_match_ptr(sbrmi_of_match),
+ },
+ .probe = sbrmi_i2c_probe,
+ .remove = sbrmi_i2c_remove,
+ .id_table = sbrmi_id,
+};
+
+module_i2c_driver(sbrmi_driver);
+
+MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
+MODULE_AUTHOR("Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>");
+MODULE_DESCRIPTION("Hwmon driver for AMD SB-RMI emulated sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bcm-vk/bcm_vk.h b/drivers/misc/bcm-vk/bcm_vk.h
index 386884c2a263..9344c2366a4b 100644
--- a/drivers/misc/bcm-vk/bcm_vk.h
+++ b/drivers/misc/bcm-vk/bcm_vk.h
@@ -311,7 +311,6 @@ struct bcm_vk_peer_log {
u32 wr_idx;
u32 buf_size;
u32 mask;
- char data[];
};
/* max buf size allowed */
diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c
index a5549eaf52d0..8e7ea2c9142d 100644
--- a/drivers/misc/cardreader/alcor_pci.c
+++ b/drivers/misc/cardreader/alcor_pci.c
@@ -121,23 +121,23 @@ static int alcor_pci_probe(struct pci_dev *pdev,
priv->cfg = cfg;
priv->irq = pdev->irq;
- ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI);
+ ret = pcim_request_all_regions(pdev, DRV_NAME_ALCOR_PCI);
if (ret) {
dev_err(&pdev->dev, "Cannot request region\n");
- ret = -ENOMEM;
+ ret = -EBUSY;
goto error_free_ida;
}
if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
ret = -ENODEV;
- goto error_release_regions;
+ goto error_free_ida;
}
priv->iobase = pcim_iomap(pdev, bar, 0);
if (!priv->iobase) {
ret = -ENOMEM;
- goto error_release_regions;
+ goto error_free_ida;
}
/* make sure irqs are disabled */
@@ -147,7 +147,7 @@ static int alcor_pci_probe(struct pci_dev *pdev,
ret = dma_set_mask_and_coherent(priv->dev, AU6601_SDMA_MASK);
if (ret) {
dev_err(priv->dev, "Failed to set DMA mask\n");
- goto error_release_regions;
+ goto error_free_ida;
}
pci_set_master(pdev);
@@ -169,8 +169,6 @@ static int alcor_pci_probe(struct pci_dev *pdev,
error_clear_drvdata:
pci_clear_master(pdev);
pci_set_drvdata(pdev, NULL);
-error_release_regions:
- pci_release_regions(pdev);
error_free_ida:
ida_free(&alcor_pci_idr, priv->id);
return ret;
@@ -186,7 +184,6 @@ static void alcor_pci_remove(struct pci_dev *pdev)
ida_free(&alcor_pci_idr, priv->id);
- pci_release_regions(pdev);
pci_clear_master(pdev);
pci_set_drvdata(pdev, NULL);
}
diff --git a/drivers/misc/cardreader/rts5264.c b/drivers/misc/cardreader/rts5264.c
index 8be4ed7d9d47..06d7a8a95fd6 100644
--- a/drivers/misc/cardreader/rts5264.c
+++ b/drivers/misc/cardreader/rts5264.c
@@ -605,6 +605,22 @@ static int rts5264_extra_init_hw(struct rtsx_pcr *pcr)
return 0;
}
+static int rts5264_optimize_phy(struct rtsx_pcr *pcr)
+{
+ u16 subvendor, subdevice, val;
+
+ subvendor = pcr->pci->subsystem_vendor;
+ subdevice = pcr->pci->subsystem_device;
+
+ if ((subvendor == 0x1028) && (subdevice == 0x0CE1)) {
+ rtsx_pci_read_phy_register(pcr, _PHY_REV0, &val);
+ if ((val & 0xFE00) > 0x3800)
+ rtsx_pci_update_phy(pcr, _PHY_REV0, 0x1FF, 0x3800);
+ }
+
+ return 0;
+}
+
static void rts5264_enable_aspm(struct rtsx_pcr *pcr, bool enable)
{
u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
@@ -682,6 +698,7 @@ static const struct pcr_ops rts5264_pcr_ops = {
.turn_on_led = rts5264_turn_on_led,
.turn_off_led = rts5264_turn_off_led,
.extra_init_hw = rts5264_extra_init_hw,
+ .optimize_phy = rts5264_optimize_phy,
.enable_auto_blink = rts5264_enable_auto_blink,
.disable_auto_blink = rts5264_disable_auto_blink,
.card_power_on = rts5264_card_power_on,
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index be3d4e0e50cc..a7b066c48740 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -420,25 +420,6 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
pcr->sgi++;
}
-int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
- int num_sg, bool read, int timeout)
-{
- int err = 0, count;
-
- pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg);
- count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
- if (count < 1)
- return -EINVAL;
- pcr_dbg(pcr, "DMA mapping count: %d\n", count);
-
- err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout);
-
- rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
-
int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read)
{
@@ -1197,33 +1178,6 @@ void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr)
}
-int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr)
-{
- rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
- MS_CLK_EN | SD40_CLK_EN, 0);
- rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
- rtsx_pci_card_power_off(pcr, RTSX_SD_CARD);
-
- msleep(50);
-
- rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD);
-
- return 0;
-}
-
-int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr)
-{
- rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
- MS_CLK_EN | SD40_CLK_EN, 0);
-
- rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD);
-
- rtsx_pci_write_register(pcr, CARD_OE, MS_OUTPUT_EN, 0);
- rtsx_pci_card_power_off(pcr, RTSX_MS_CARD);
-
- return 0;
-}
-
static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index 9215d66de00c..8e5951b61143 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -127,7 +127,5 @@ int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val);
void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr);
void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr);
void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr);
-int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr);
-int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr);
#endif
diff --git a/drivers/misc/echo/Kconfig b/drivers/misc/echo/Kconfig
deleted file mode 100644
index ce0a37a47fc1..000000000000
--- a/drivers/misc/echo/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config ECHO
- tristate "Line Echo Canceller support"
- help
- This driver provides line echo cancelling support for mISDN and
- Zaptel drivers.
-
- To compile this driver as a module, choose M here. The module
- will be called echo.
diff --git a/drivers/misc/echo/Makefile b/drivers/misc/echo/Makefile
deleted file mode 100644
index 5b97467ffb7d..000000000000
--- a/drivers/misc/echo/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ECHO) += echo.o
diff --git a/drivers/misc/echo/echo.c b/drivers/misc/echo/echo.c
deleted file mode 100644
index 3c4eaba86576..000000000000
--- a/drivers/misc/echo/echo.c
+++ /dev/null
@@ -1,589 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * echo.c - A line echo canceller. This code is being developed
- * against and partially complies with G168.
- *
- * Written by Steve Underwood <steveu@coppice.org>
- * and David Rowe <david_at_rowetel_dot_com>
- *
- * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
- *
- * Based on a bit from here, a bit from there, eye of toad, ear of
- * bat, 15 years of failed attempts by David and a few fried brain
- * cells.
- *
- * All rights reserved.
- */
-
-/*! \file */
-
-/* Implementation Notes
- David Rowe
- April 2007
-
- This code started life as Steve's NLMS algorithm with a tap
- rotation algorithm to handle divergence during double talk. I
- added a Geigel Double Talk Detector (DTD) [2] and performed some
- G168 tests. However I had trouble meeting the G168 requirements,
- especially for double talk - there were always cases where my DTD
- failed, for example where near end speech was under the 6dB
- threshold required for declaring double talk.
-
- So I tried a two path algorithm [1], which has so far given better
- results. The original tap rotation/Geigel algorithm is available
- in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit.
- It's probably possible to make it work if some one wants to put some
- serious work into it.
-
- At present no special treatment is provided for tones, which
- generally cause NLMS algorithms to diverge. Initial runs of a
- subset of the G168 tests for tones (e.g ./echo_test 6) show the
- current algorithm is passing OK, which is kind of surprising. The
- full set of tests needs to be performed to confirm this result.
-
- One other interesting change is that I have managed to get the NLMS
- code to work with 16 bit coefficients, rather than the original 32
- bit coefficents. This reduces the MIPs and storage required.
- I evaulated the 16 bit port using g168_tests.sh and listening tests
- on 4 real-world samples.
-
- I also attempted the implementation of a block based NLMS update
- [2] but although this passes g168_tests.sh it didn't converge well
- on the real-world samples. I have no idea why, perhaps a scaling
- problem. The block based code is also available in SVN
- http://svn.rowetel.com/software/oslec/tags/before_16bit. If this
- code can be debugged, it will lead to further reduction in MIPS, as
- the block update code maps nicely onto DSP instruction sets (it's a
- dot product) compared to the current sample-by-sample update.
-
- Steve also has some nice notes on echo cancellers in echo.h
-
- References:
-
- [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
- Path Models", IEEE Transactions on communications, COM-25,
- No. 6, June
- 1977.
- https://www.rowetel.com/images/echo/dual_path_paper.pdf
-
- [2] The classic, very useful paper that tells you how to
- actually build a real world echo canceller:
- Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
- Echo Canceller with a TMS320020,
- https://www.rowetel.com/images/echo/spra129.pdf
-
- [3] I have written a series of blog posts on this work, here is
- Part 1: http://www.rowetel.com/blog/?p=18
-
- [4] The source code http://svn.rowetel.com/software/oslec/
-
- [5] A nice reference on LMS filters:
- https://en.wikipedia.org/wiki/Least_mean_squares_filter
-
- Credits:
-
- Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
- Muthukrishnan for their suggestions and email discussions. Thanks
- also to those people who collected echo samples for me such as
- Mark, Pawel, and Pavel.
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "echo.h"
-
-#define MIN_TX_POWER_FOR_ADAPTION 64
-#define MIN_RX_POWER_FOR_ADAPTION 64
-#define DTD_HANGOVER 600 /* 600 samples, or 75ms */
-#define DC_LOG2BETA 3 /* log2() of DC filter Beta */
-
-/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
-
-static inline void lms_adapt_bg(struct oslec_state *ec, int clean, int shift)
-{
- int i;
-
- int offset1;
- int offset2;
- int factor;
- int exp;
-
- if (shift > 0)
- factor = clean << shift;
- else
- factor = clean >> -shift;
-
- /* Update the FIR taps */
-
- offset2 = ec->curr_pos;
- offset1 = ec->taps - offset2;
-
- for (i = ec->taps - 1; i >= offset1; i--) {
- exp = (ec->fir_state_bg.history[i - offset1] * factor);
- ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
- }
- for (; i >= 0; i--) {
- exp = (ec->fir_state_bg.history[i + offset2] * factor);
- ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
- }
-}
-
-static inline int top_bit(unsigned int bits)
-{
- if (bits == 0)
- return -1;
- else
- return (int)fls((int32_t) bits) - 1;
-}
-
-struct oslec_state *oslec_create(int len, int adaption_mode)
-{
- struct oslec_state *ec;
- int i;
- const int16_t *history;
-
- ec = kzalloc(sizeof(*ec), GFP_KERNEL);
- if (!ec)
- return NULL;
-
- ec->taps = len;
- ec->log2taps = top_bit(len);
- ec->curr_pos = ec->taps - 1;
-
- ec->fir_taps16[0] =
- kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
- if (!ec->fir_taps16[0])
- goto error_oom_0;
-
- ec->fir_taps16[1] =
- kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
- if (!ec->fir_taps16[1])
- goto error_oom_1;
-
- history = fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
- if (!history)
- goto error_state;
- history = fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps);
- if (!history)
- goto error_state_bg;
-
- for (i = 0; i < 5; i++)
- ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
-
- ec->cng_level = 1000;
- oslec_adaption_mode(ec, adaption_mode);
-
- ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
- if (!ec->snapshot)
- goto error_snap;
-
- ec->cond_met = 0;
- ec->pstates = 0;
- ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0;
- ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0;
- ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
- ec->lbgn = ec->lbgn_acc = 0;
- ec->lbgn_upper = 200;
- ec->lbgn_upper_acc = ec->lbgn_upper << 13;
-
- return ec;
-
-error_snap:
- fir16_free(&ec->fir_state_bg);
-error_state_bg:
- fir16_free(&ec->fir_state);
-error_state:
- kfree(ec->fir_taps16[1]);
-error_oom_1:
- kfree(ec->fir_taps16[0]);
-error_oom_0:
- kfree(ec);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(oslec_create);
-
-void oslec_free(struct oslec_state *ec)
-{
- int i;
-
- fir16_free(&ec->fir_state);
- fir16_free(&ec->fir_state_bg);
- for (i = 0; i < 2; i++)
- kfree(ec->fir_taps16[i]);
- kfree(ec->snapshot);
- kfree(ec);
-}
-EXPORT_SYMBOL_GPL(oslec_free);
-
-void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode)
-{
- ec->adaption_mode = adaption_mode;
-}
-EXPORT_SYMBOL_GPL(oslec_adaption_mode);
-
-void oslec_flush(struct oslec_state *ec)
-{
- int i;
-
- ec->ltxacc = ec->lrxacc = ec->lcleanacc = ec->lclean_bgacc = 0;
- ec->ltx = ec->lrx = ec->lclean = ec->lclean_bg = 0;
- ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
-
- ec->lbgn = ec->lbgn_acc = 0;
- ec->lbgn_upper = 200;
- ec->lbgn_upper_acc = ec->lbgn_upper << 13;
-
- ec->nonupdate_dwell = 0;
-
- fir16_flush(&ec->fir_state);
- fir16_flush(&ec->fir_state_bg);
- ec->fir_state.curr_pos = ec->taps - 1;
- ec->fir_state_bg.curr_pos = ec->taps - 1;
- for (i = 0; i < 2; i++)
- memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
-
- ec->curr_pos = ec->taps - 1;
- ec->pstates = 0;
-}
-EXPORT_SYMBOL_GPL(oslec_flush);
-
-void oslec_snapshot(struct oslec_state *ec)
-{
- memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t));
-}
-EXPORT_SYMBOL_GPL(oslec_snapshot);
-
-/* Dual Path Echo Canceller */
-
-int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx)
-{
- int32_t echo_value;
- int clean_bg;
- int tmp;
- int tmp1;
-
- /*
- * Input scaling was found be required to prevent problems when tx
- * starts clipping. Another possible way to handle this would be the
- * filter coefficent scaling.
- */
-
- ec->tx = tx;
- ec->rx = rx;
- tx >>= 1;
- rx >>= 1;
-
- /*
- * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision
- * required otherwise values do not track down to 0. Zero at DC, Pole
- * at (1-Beta) on real axis. Some chip sets (like Si labs) don't
- * need this, but something like a $10 X100P card does. Any DC really
- * slows down convergence.
- *
- * Note: removes some low frequency from the signal, this reduces the
- * speech quality when listening to samples through headphones but may
- * not be obvious through a telephone handset.
- *
- * Note that the 3dB frequency in radians is approx Beta, e.g. for Beta
- * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
- */
-
- if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
- tmp = rx << 15;
-
- /*
- * Make sure the gain of the HPF is 1.0. This can still
- * saturate a little under impulse conditions, and it might
- * roll to 32768 and need clipping on sustained peak level
- * signals. However, the scale of such clipping is small, and
- * the error due to any saturation should not markedly affect
- * the downstream processing.
- */
- tmp -= (tmp >> 4);
-
- ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2;
-
- /*
- * hard limit filter to prevent clipping. Note that at this
- * stage rx should be limited to +/- 16383 due to right shift
- * above
- */
- tmp1 = ec->rx_1 >> 15;
- if (tmp1 > 16383)
- tmp1 = 16383;
- if (tmp1 < -16383)
- tmp1 = -16383;
- rx = tmp1;
- ec->rx_2 = tmp;
- }
-
- /* Block average of power in the filter states. Used for
- adaption power calculation. */
-
- {
- int new, old;
-
- /* efficient "out with the old and in with the new" algorithm so
- we don't have to recalculate over the whole block of
- samples. */
- new = (int)tx * (int)tx;
- old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
- (int)ec->fir_state.history[ec->fir_state.curr_pos];
- ec->pstates +=
- ((new - old) + (1 << (ec->log2taps - 1))) >> ec->log2taps;
- if (ec->pstates < 0)
- ec->pstates = 0;
- }
-
- /* Calculate short term average levels using simple single pole IIRs */
-
- ec->ltxacc += abs(tx) - ec->ltx;
- ec->ltx = (ec->ltxacc + (1 << 4)) >> 5;
- ec->lrxacc += abs(rx) - ec->lrx;
- ec->lrx = (ec->lrxacc + (1 << 4)) >> 5;
-
- /* Foreground filter */
-
- ec->fir_state.coeffs = ec->fir_taps16[0];
- echo_value = fir16(&ec->fir_state, tx);
- ec->clean = rx - echo_value;
- ec->lcleanacc += abs(ec->clean) - ec->lclean;
- ec->lclean = (ec->lcleanacc + (1 << 4)) >> 5;
-
- /* Background filter */
-
- echo_value = fir16(&ec->fir_state_bg, tx);
- clean_bg = rx - echo_value;
- ec->lclean_bgacc += abs(clean_bg) - ec->lclean_bg;
- ec->lclean_bg = (ec->lclean_bgacc + (1 << 4)) >> 5;
-
- /* Background Filter adaption */
-
- /* Almost always adap bg filter, just simple DT and energy
- detection to minimise adaption in cases of strong double talk.
- However this is not critical for the dual path algorithm.
- */
- ec->factor = 0;
- ec->shift = 0;
- if (!ec->nonupdate_dwell) {
- int p, logp, shift;
-
- /* Determine:
-
- f = Beta * clean_bg_rx/P ------ (1)
-
- where P is the total power in the filter states.
-
- The Boffins have shown that if we obey (1) we converge
- quickly and avoid instability.
-
- The correct factor f must be in Q30, as this is the fixed
- point format required by the lms_adapt_bg() function,
- therefore the scaled version of (1) is:
-
- (2^30) * f = (2^30) * Beta * clean_bg_rx/P
- factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
-
- We have chosen Beta = 0.25 by experiment, so:
-
- factor = (2^30) * (2^-2) * clean_bg_rx/P
-
- (30 - 2 - log2(P))
- factor = clean_bg_rx 2 ----- (3)
-
- To avoid a divide we approximate log2(P) as top_bit(P),
- which returns the position of the highest non-zero bit in
- P. This approximation introduces an error as large as a
- factor of 2, but the algorithm seems to handle it OK.
-
- Come to think of it a divide may not be a big deal on a
- modern DSP, so its probably worth checking out the cycles
- for a divide versus a top_bit() implementation.
- */
-
- p = MIN_TX_POWER_FOR_ADAPTION + ec->pstates;
- logp = top_bit(p) + ec->log2taps;
- shift = 30 - 2 - logp;
- ec->shift = shift;
-
- lms_adapt_bg(ec, clean_bg, shift);
- }
-
- /* very simple DTD to make sure we dont try and adapt with strong
- near end speech */
-
- ec->adapt = 0;
- if ((ec->lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->lrx > ec->ltx))
- ec->nonupdate_dwell = DTD_HANGOVER;
- if (ec->nonupdate_dwell)
- ec->nonupdate_dwell--;
-
- /* Transfer logic */
-
- /* These conditions are from the dual path paper [1], I messed with
- them a bit to improve performance. */
-
- if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
- (ec->nonupdate_dwell == 0) &&
- /* (ec->Lclean_bg < 0.875*ec->Lclean) */
- (8 * ec->lclean_bg < 7 * ec->lclean) &&
- /* (ec->Lclean_bg < 0.125*ec->Ltx) */
- (8 * ec->lclean_bg < ec->ltx)) {
- if (ec->cond_met == 6) {
- /*
- * BG filter has had better results for 6 consecutive
- * samples
- */
- ec->adapt = 1;
- memcpy(ec->fir_taps16[0], ec->fir_taps16[1],
- ec->taps * sizeof(int16_t));
- } else
- ec->cond_met++;
- } else
- ec->cond_met = 0;
-
- /* Non-Linear Processing */
-
- ec->clean_nlp = ec->clean;
- if (ec->adaption_mode & ECHO_CAN_USE_NLP) {
- /*
- * Non-linear processor - a fancy way to say "zap small
- * signals, to avoid residual echo due to (uLaw/ALaw)
- * non-linearity in the channel.".
- */
-
- if ((16 * ec->lclean < ec->ltx)) {
- /*
- * Our e/c has improved echo by at least 24 dB (each
- * factor of 2 is 6dB, so 2*2*2*2=16 is the same as
- * 6+6+6+6=24dB)
- */
- if (ec->adaption_mode & ECHO_CAN_USE_CNG) {
- ec->cng_level = ec->lbgn;
-
- /*
- * Very elementary comfort noise generation.
- * Just random numbers rolled off very vaguely
- * Hoth-like. DR: This noise doesn't sound
- * quite right to me - I suspect there are some
- * overflow issues in the filtering as it's too
- * "crackly".
- * TODO: debug this, maybe just play noise at
- * high level or look at spectrum.
- */
-
- ec->cng_rndnum =
- 1664525U * ec->cng_rndnum + 1013904223U;
- ec->cng_filter =
- ((ec->cng_rndnum & 0xFFFF) - 32768 +
- 5 * ec->cng_filter) >> 3;
- ec->clean_nlp =
- (ec->cng_filter * ec->cng_level * 8) >> 14;
-
- } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) {
- /* This sounds much better than CNG */
- if (ec->clean_nlp > ec->lbgn)
- ec->clean_nlp = ec->lbgn;
- if (ec->clean_nlp < -ec->lbgn)
- ec->clean_nlp = -ec->lbgn;
- } else {
- /*
- * just mute the residual, doesn't sound very
- * good, used mainly in G168 tests
- */
- ec->clean_nlp = 0;
- }
- } else {
- /*
- * Background noise estimator. I tried a few
- * algorithms here without much luck. This very simple
- * one seems to work best, we just average the level
- * using a slow (1 sec time const) filter if the
- * current level is less than a (experimentally
- * derived) constant. This means we dont include high
- * level signals like near end speech. When combined
- * with CNG or especially CLIP seems to work OK.
- */
- if (ec->lclean < 40) {
- ec->lbgn_acc += abs(ec->clean) - ec->lbgn;
- ec->lbgn = (ec->lbgn_acc + (1 << 11)) >> 12;
- }
- }
- }
-
- /* Roll around the taps buffer */
- if (ec->curr_pos <= 0)
- ec->curr_pos = ec->taps;
- ec->curr_pos--;
-
- if (ec->adaption_mode & ECHO_CAN_DISABLE)
- ec->clean_nlp = rx;
-
- /* Output scaled back up again to match input scaling */
-
- return (int16_t) ec->clean_nlp << 1;
-}
-EXPORT_SYMBOL_GPL(oslec_update);
-
-/* This function is separated from the echo canceller is it is usually called
- as part of the tx process. See rx HP (DC blocking) filter above, it's
- the same design.
-
- Some soft phones send speech signals with a lot of low frequency
- energy, e.g. down to 20Hz. This can make the hybrid non-linear
- which causes the echo canceller to fall over. This filter can help
- by removing any low frequency before it gets to the tx port of the
- hybrid.
-
- It can also help by removing and DC in the tx signal. DC is bad
- for LMS algorithms.
-
- This is one of the classic DC removal filters, adjusted to provide
- sufficient bass rolloff to meet the above requirement to protect hybrids
- from things that upset them. The difference between successive samples
- produces a lousy HPF, and then a suitably placed pole flattens things out.
- The final result is a nicely rolled off bass end. The filtering is
- implemented with extended fractional precision, which noise shapes things,
- giving very clean DC removal.
-*/
-
-int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx)
-{
- int tmp;
- int tmp1;
-
- if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
- tmp = tx << 15;
-
- /*
- * Make sure the gain of the HPF is 1.0. The first can still
- * saturate a little under impulse conditions, and it might
- * roll to 32768 and need clipping on sustained peak level
- * signals. However, the scale of such clipping is small, and
- * the error due to any saturation should not markedly affect
- * the downstream processing.
- */
- tmp -= (tmp >> 4);
-
- ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2;
- tmp1 = ec->tx_1 >> 15;
- if (tmp1 > 32767)
- tmp1 = 32767;
- if (tmp1 < -32767)
- tmp1 = -32767;
- tx = tmp1;
- ec->tx_2 = tmp;
- }
-
- return tx;
-}
-EXPORT_SYMBOL_GPL(oslec_hpf_tx);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Rowe");
-MODULE_DESCRIPTION("Open Source Line Echo Canceller");
-MODULE_VERSION("0.3.0");
diff --git a/drivers/misc/echo/echo.h b/drivers/misc/echo/echo.h
deleted file mode 100644
index 56b4b95fd020..000000000000
--- a/drivers/misc/echo/echo.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * echo.c - A line echo canceller. This code is being developed
- * against and partially complies with G168.
- *
- * Written by Steve Underwood <steveu@coppice.org>
- * and David Rowe <david_at_rowetel_dot_com>
- *
- * Copyright (C) 2001 Steve Underwood and 2007 David Rowe
- *
- * All rights reserved.
- */
-
-#ifndef __ECHO_H
-#define __ECHO_H
-
-/*
-Line echo cancellation for voice
-
-What does it do?
-
-This module aims to provide G.168-2002 compliant echo cancellation, to remove
-electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
-
-How does it work?
-
-The heart of the echo cancellor is FIR filter. This is adapted to match the
-echo impulse response of the telephone line. It must be long enough to
-adequately cover the duration of that impulse response. The signal transmitted
-to the telephone line is passed through the FIR filter. Once the FIR is
-properly adapted, the resulting output is an estimate of the echo signal
-received from the line. This is subtracted from the received signal. The result
-is an estimate of the signal which originated at the far end of the line, free
-from echos of our own transmitted signal.
-
-The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and
-was introduced in 1960. It is the commonest form of filter adaption used in
-things like modem line equalisers and line echo cancellers. There it works very
-well. However, it only works well for signals of constant amplitude. It works
-very poorly for things like speech echo cancellation, where the signal level
-varies widely. This is quite easy to fix. If the signal level is normalised -
-similar to applying AGC - LMS can work as well for a signal of varying
-amplitude as it does for a modem signal. This normalised least mean squares
-(NLMS) algorithm is the commonest one used for speech echo cancellation. Many
-other algorithms exist - e.g. RLS (essentially the same as Kalman filtering),
-FAP, etc. Some perform significantly better than NLMS. However, factors such
-as computational complexity and patents favour the use of NLMS.
-
-A simple refinement to NLMS can improve its performance with speech. NLMS tends
-to adapt best to the strongest parts of a signal. If the signal is white noise,
-the NLMS algorithm works very well. However, speech has more low frequency than
-high frequency content. Pre-whitening (i.e. filtering the signal to flatten its
-spectrum) the echo signal improves the adapt rate for speech, and ensures the
-final residual signal is not heavily biased towards high frequencies. A very
-low complexity filter is adequate for this, so pre-whitening adds little to the
-compute requirements of the echo canceller.
-
-An FIR filter adapted using pre-whitened NLMS performs well, provided certain
-conditions are met:
-
- - The transmitted signal has poor self-correlation.
- - There is no signal being generated within the environment being
- cancelled.
-
-The difficulty is that neither of these can be guaranteed.
-
-If the adaption is performed while transmitting noise (or something fairly
-noise like, such as voice) the adaption works very well. If the adaption is
-performed while transmitting something highly correlative (typically narrow
-band energy such as signalling tones or DTMF), the adaption can go seriously
-wrong. The reason is there is only one solution for the adaption on a near
-random signal - the impulse response of the line. For a repetitive signal,
-there are any number of solutions which converge the adaption, and nothing
-guides the adaption to choose the generalised one. Allowing an untrained
-canceller to converge on this kind of narrowband energy probably a good thing,
-since at least it cancels the tones. Allowing a well converged canceller to
-continue converging on such energy is just a way to ruin its generalised
-adaption. A narrowband detector is needed, so adapation can be suspended at
-appropriate times.
-
-The adaption process is based on trying to eliminate the received signal. When
-there is any signal from within the environment being cancelled it may upset
-the adaption process. Similarly, if the signal we are transmitting is small,
-noise may dominate and disturb the adaption process. If we can ensure that the
-adaption is only performed when we are transmitting a significant signal level,
-and the environment is not, things will be OK. Clearly, it is easy to tell when
-we are sending a significant signal. Telling, if the environment is generating
-a significant signal, and doing it with sufficient speed that the adaption will
-not have diverged too much more we stop it, is a little harder.
-
-The key problem in detecting when the environment is sourcing significant
-energy is that we must do this very quickly. Given a reasonably long sample of
-the received signal, there are a number of strategies which may be used to
-assess whether that signal contains a strong far end component. However, by the
-time that assessment is complete the far end signal will have already caused
-major mis-convergence in the adaption process. An assessment algorithm is
-needed which produces a fairly accurate result from a very short burst of far
-end energy.
-
-How do I use it?
-
-The echo cancellor processes both the transmit and receive streams sample by
-sample. The processing function is not declared inline. Unfortunately,
-cancellation requires many operations per sample, so the call overhead is only
-a minor burden.
-*/
-
-#include "fir.h"
-#include "oslec.h"
-
-/*
- G.168 echo canceller descriptor. This defines the working state for a line
- echo canceller.
-*/
-struct oslec_state {
- int16_t tx;
- int16_t rx;
- int16_t clean;
- int16_t clean_nlp;
-
- int nonupdate_dwell;
- int curr_pos;
- int taps;
- int log2taps;
- int adaption_mode;
-
- int cond_met;
- int32_t pstates;
- int16_t adapt;
- int32_t factor;
- int16_t shift;
-
- /* Average levels and averaging filter states */
- int ltxacc;
- int lrxacc;
- int lcleanacc;
- int lclean_bgacc;
- int ltx;
- int lrx;
- int lclean;
- int lclean_bg;
- int lbgn;
- int lbgn_acc;
- int lbgn_upper;
- int lbgn_upper_acc;
-
- /* foreground and background filter states */
- struct fir16_state_t fir_state;
- struct fir16_state_t fir_state_bg;
- int16_t *fir_taps16[2];
-
- /* DC blocking filter states */
- int tx_1;
- int tx_2;
- int rx_1;
- int rx_2;
-
- /* optional High Pass Filter states */
- int32_t xvtx[5];
- int32_t yvtx[5];
- int32_t xvrx[5];
- int32_t yvrx[5];
-
- /* Parameters for the optional Hoth noise generator */
- int cng_level;
- int cng_rndnum;
- int cng_filter;
-
- /* snapshot sample of coeffs used for development */
- int16_t *snapshot;
-};
-
-#endif /* __ECHO_H */
diff --git a/drivers/misc/echo/fir.h b/drivers/misc/echo/fir.h
deleted file mode 100644
index 4d0821025223..000000000000
--- a/drivers/misc/echo/fir.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * fir.h - General telephony FIR routines
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2002 Steve Underwood
- *
- * All rights reserved.
- */
-
-#if !defined(_FIR_H_)
-#define _FIR_H_
-
-/*
- Ideas for improvement:
-
- 1/ Rewrite filter for dual MAC inner loop. The issue here is handling
- history sample offsets that are 16 bit aligned - the dual MAC needs
- 32 bit aligmnent. There are some good examples in libbfdsp.
-
- 2/ Use the hardware circular buffer facility tohalve memory usage.
-
- 3/ Consider using internal memory.
-
- Using less memory might also improve speed as cache misses will be
- reduced. A drop in MIPs and memory approaching 50% should be
- possible.
-
- The foreground and background filters currenlty use a total of
- about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
- can.
-*/
-
-/*
- * 16 bit integer FIR descriptor. This defines the working state for a single
- * instance of an FIR filter using 16 bit integer coefficients.
- */
-struct fir16_state_t {
- int taps;
- int curr_pos;
- const int16_t *coeffs;
- int16_t *history;
-};
-
-/*
- * 32 bit integer FIR descriptor. This defines the working state for a single
- * instance of an FIR filter using 32 bit integer coefficients, and filtering
- * 16 bit integer data.
- */
-struct fir32_state_t {
- int taps;
- int curr_pos;
- const int32_t *coeffs;
- int16_t *history;
-};
-
-/*
- * Floating point FIR descriptor. This defines the working state for a single
- * instance of an FIR filter using floating point coefficients and data.
- */
-struct fir_float_state_t {
- int taps;
- int curr_pos;
- const float *coeffs;
- float *history;
-};
-
-static inline const int16_t *fir16_create(struct fir16_state_t *fir,
- const int16_t *coeffs, int taps)
-{
- fir->taps = taps;
- fir->curr_pos = taps - 1;
- fir->coeffs = coeffs;
- fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
- return fir->history;
-}
-
-static inline void fir16_flush(struct fir16_state_t *fir)
-{
- memset(fir->history, 0, fir->taps * sizeof(int16_t));
-}
-
-static inline void fir16_free(struct fir16_state_t *fir)
-{
- kfree(fir->history);
-}
-
-static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample)
-{
- int32_t y;
- int i;
- int offset1;
- int offset2;
-
- fir->history[fir->curr_pos] = sample;
-
- offset2 = fir->curr_pos;
- offset1 = fir->taps - offset2;
- y = 0;
- for (i = fir->taps - 1; i >= offset1; i--)
- y += fir->coeffs[i] * fir->history[i - offset1];
- for (; i >= 0; i--)
- y += fir->coeffs[i] * fir->history[i + offset2];
- if (fir->curr_pos <= 0)
- fir->curr_pos = fir->taps;
- fir->curr_pos--;
- return (int16_t) (y >> 15);
-}
-
-static inline const int16_t *fir32_create(struct fir32_state_t *fir,
- const int32_t *coeffs, int taps)
-{
- fir->taps = taps;
- fir->curr_pos = taps - 1;
- fir->coeffs = coeffs;
- fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
- return fir->history;
-}
-
-static inline void fir32_flush(struct fir32_state_t *fir)
-{
- memset(fir->history, 0, fir->taps * sizeof(int16_t));
-}
-
-static inline void fir32_free(struct fir32_state_t *fir)
-{
- kfree(fir->history);
-}
-
-static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample)
-{
- int i;
- int32_t y;
- int offset1;
- int offset2;
-
- fir->history[fir->curr_pos] = sample;
- offset2 = fir->curr_pos;
- offset1 = fir->taps - offset2;
- y = 0;
- for (i = fir->taps - 1; i >= offset1; i--)
- y += fir->coeffs[i] * fir->history[i - offset1];
- for (; i >= 0; i--)
- y += fir->coeffs[i] * fir->history[i + offset2];
- if (fir->curr_pos <= 0)
- fir->curr_pos = fir->taps;
- fir->curr_pos--;
- return (int16_t) (y >> 15);
-}
-
-#endif
diff --git a/drivers/misc/echo/oslec.h b/drivers/misc/echo/oslec.h
deleted file mode 100644
index f1adac143b90..000000000000
--- a/drivers/misc/echo/oslec.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * OSLEC - A line echo canceller. This code is being developed
- * against and partially complies with G168. Using code from SpanDSP
- *
- * Written by Steve Underwood <steveu@coppice.org>
- * and David Rowe <david_at_rowetel_dot_com>
- *
- * Copyright (C) 2001 Steve Underwood and 2007-2008 David Rowe
- *
- * All rights reserved.
- */
-
-#ifndef __OSLEC_H
-#define __OSLEC_H
-
-/* Mask bits for the adaption mode */
-#define ECHO_CAN_USE_ADAPTION 0x01
-#define ECHO_CAN_USE_NLP 0x02
-#define ECHO_CAN_USE_CNG 0x04
-#define ECHO_CAN_USE_CLIP 0x08
-#define ECHO_CAN_USE_TX_HPF 0x10
-#define ECHO_CAN_USE_RX_HPF 0x20
-#define ECHO_CAN_DISABLE 0x40
-
-/**
- * oslec_state: G.168 echo canceller descriptor.
- *
- * This defines the working state for a line echo canceller.
- */
-struct oslec_state;
-
-/**
- * oslec_create - Create a voice echo canceller context.
- * @len: The length of the canceller, in samples.
- * @return: The new canceller context, or NULL if the canceller could not be
- * created.
- */
-struct oslec_state *oslec_create(int len, int adaption_mode);
-
-/**
- * oslec_free - Free a voice echo canceller context.
- * @ec: The echo canceller context.
- */
-void oslec_free(struct oslec_state *ec);
-
-/**
- * oslec_flush - Flush (reinitialise) a voice echo canceller context.
- * @ec: The echo canceller context.
- */
-void oslec_flush(struct oslec_state *ec);
-
-/**
- * oslec_adaption_mode - set the adaption mode of a voice echo canceller context.
- * @ec The echo canceller context.
- * @adaption_mode: The mode.
- */
-void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode);
-
-void oslec_snapshot(struct oslec_state *ec);
-
-/**
- * oslec_update: Process a sample through a voice echo canceller.
- * @ec: The echo canceller context.
- * @tx: The transmitted audio sample.
- * @rx: The received audio sample.
- *
- * The return value is the clean (echo cancelled) received sample.
- */
-int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx);
-
-/**
- * oslec_hpf_tx: Process to high pass filter the tx signal.
- * @ec: The echo canceller context.
- * @tx: The transmitted auio sample.
- *
- * The return value is the HP filtered transmit sample, send this to your D/A.
- */
-int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx);
-
-#endif /* __OSLEC_H */
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 1fc632ebf22f..60c42170d147 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -61,11 +61,6 @@ MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("T-platforms");
/*
- * csr_dbgdir - CSR read/write operations Debugfs directory
- */
-static struct dentry *csr_dbgdir;
-
-/*
* struct idt_89hpesx_dev - IDT 89HPESx device data structure
* @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible")
* @eero: EEPROM Read-only flag
@@ -1325,35 +1320,6 @@ static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev)
}
/*
- * idt_create_dbgfs_files() - create debugfs files
- * @pdev: Pointer to the driver data
- */
-#define CSRNAME_LEN ((size_t)32)
-static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev)
-{
- struct i2c_client *cli = pdev->client;
- char fname[CSRNAME_LEN];
-
- /* Create Debugfs directory for CSR file */
- snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr);
- pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir);
-
- /* Create Debugfs file for CSR read/write operations */
- debugfs_create_file(cli->name, 0600, pdev->csr_dir, pdev,
- &csr_dbgfs_ops);
-}
-
-/*
- * idt_remove_dbgfs_files() - remove debugfs files
- * @pdev: Pointer to the driver data
- */
-static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev)
-{
- /* Remove CSR directory and it sysfs-node */
- debugfs_remove_recursive(pdev->csr_dir);
-}
-
-/*
* idt_probe() - IDT 89HPESx driver probe() callback method
*/
static int idt_probe(struct i2c_client *client)
@@ -1382,7 +1348,7 @@ static int idt_probe(struct i2c_client *client)
goto err_free_pdev;
/* Create debugfs files */
- idt_create_dbgfs_files(pdev);
+ debugfs_create_file(pdev->client->name, 0600, client->debugfs, pdev, &csr_dbgfs_ops);
return 0;
@@ -1399,9 +1365,6 @@ static void idt_remove(struct i2c_client *client)
{
struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client);
- /* Remove debugfs files first */
- idt_remove_dbgfs_files(pdev);
-
/* Remove sysfs files */
idt_remove_sysfs_files(pdev);
@@ -1550,38 +1513,4 @@ static struct i2c_driver idt_driver = {
.remove = idt_remove,
.id_table = idt_ids,
};
-
-/*
- * idt_init() - IDT 89HPESx driver init() callback method
- */
-static int __init idt_init(void)
-{
- int ret;
-
- /* Create Debugfs directory first */
- if (debugfs_initialized())
- csr_dbgdir = debugfs_create_dir("idt_csr", NULL);
-
- /* Add new i2c-device driver */
- ret = i2c_add_driver(&idt_driver);
- if (ret) {
- debugfs_remove_recursive(csr_dbgdir);
- return ret;
- }
-
- return 0;
-}
-module_init(idt_init);
-
-/*
- * idt_exit() - IDT 89HPESx driver exit() callback method
- */
-static void __exit idt_exit(void)
-{
- /* Discard debugfs directory and all files if any */
- debugfs_remove_recursive(csr_dbgdir);
-
- /* Unregister i2c-device driver */
- i2c_del_driver(&idt_driver);
-}
-module_exit(idt_exit);
+module_i2c_driver(idt_driver);
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 7b7a22c91fe4..378923594f02 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -2313,7 +2313,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
rmem = of_reserved_mem_lookup(rmem_node);
if (!rmem) {
err = -EINVAL;
- goto fdev_error;
+ goto err_free_data;
}
src_perms = BIT(QCOM_SCM_VMID_HLOS);
@@ -2334,7 +2334,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
data->unsigned_support = false;
err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]);
if (err)
- goto fdev_error;
+ goto err_free_data;
break;
case CDSP_DOMAIN_ID:
case CDSP1_DOMAIN_ID:
@@ -2342,15 +2342,15 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
/* Create both device nodes so that we can allow both Signed and Unsigned PD */
err = fastrpc_device_register(rdev, data, true, domains[domain_id]);
if (err)
- goto fdev_error;
+ goto err_free_data;
err = fastrpc_device_register(rdev, data, false, domains[domain_id]);
if (err)
- goto populate_error;
+ goto err_deregister_fdev;
break;
default:
err = -EINVAL;
- goto fdev_error;
+ goto err_free_data;
}
kref_init(&data->refcount);
@@ -2367,17 +2367,17 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
err = of_platform_populate(rdev->of_node, NULL, NULL, rdev);
if (err)
- goto populate_error;
+ goto err_deregister_fdev;
return 0;
-populate_error:
+err_deregister_fdev:
if (data->fdevice)
misc_deregister(&data->fdevice->miscdev);
if (data->secure_fdevice)
misc_deregister(&data->secure_fdevice->miscdev);
-fdev_error:
+err_free_data:
kfree(data);
return err;
}
diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig
index bb2fec4b5880..56005243a230 100644
--- a/drivers/misc/lis3lv02d/Kconfig
+++ b/drivers/misc/lis3lv02d/Kconfig
@@ -10,7 +10,7 @@ config SENSORS_LIS3_SPI
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via SPI. The accelerometer data is readable via
- /sys/devices/platform/lis3lv02d.
+ /sys/devices/faux/lis3lv02d.
This driver also provides an absolute input class device, allowing
the laptop to act as a pinball machine-esque joystick.
@@ -26,7 +26,7 @@ config SENSORS_LIS3_I2C
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via I2C. The accelerometer data is readable via
- /sys/devices/platform/lis3lv02d.
+ /sys/devices/faux/lis3lv02d.
This driver also provides an absolute input class device, allowing
the device to act as a pinball machine-esque joystick.
diff --git a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
index 98d3d123004c..ff8f4404d10f 100644
--- a/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
+++ b/drivers/misc/mchp_pci1xxxx/mchp_pci1xxxx_gpio.c
@@ -7,12 +7,14 @@
#include <linux/gpio/driver.h>
#include <linux/bio.h>
#include <linux/mutex.h>
+#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include "mchp_pci1xxxx_gp.h"
#define PCI1XXXX_NR_PINS 93
+#define PCI_DEV_REV_OFFSET 0x08
#define PERI_GEN_RESET 0
#define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400)
#define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10)
@@ -40,9 +42,27 @@ struct pci1xxxx_gpio {
raw_spinlock_t wa_lock;
struct gpio_chip gpio;
spinlock_t lock;
+ u32 gpio_wake_mask[3];
int irq_base;
+ u8 dev_rev;
};
+static int pci1xxxx_gpio_get_device_revision(struct pci1xxxx_gpio *priv)
+{
+ struct device *parent = priv->aux_dev->dev.parent;
+ struct pci_dev *pcidev = to_pci_dev(parent);
+ int ret;
+ u32 val;
+
+ ret = pci_read_config_dword(pcidev, PCI_DEV_REV_OFFSET, &val);
+ if (ret)
+ return ret;
+
+ priv->dev_rev = val;
+
+ return 0;
+}
+
static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr)
{
struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
@@ -115,8 +135,7 @@ static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio,
return 0;
}
-static void pci1xxxx_gpio_set(struct gpio_chip *gpio,
- unsigned int nr, int val)
+static int pci1xxxx_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
{
struct pci1xxxx_gpio *priv = gpiochip_get_data(gpio);
unsigned long flags;
@@ -124,6 +143,8 @@ static void pci1xxxx_gpio_set(struct gpio_chip *gpio,
spin_lock_irqsave(&priv->lock, flags);
pci1xxx_assign_bit(priv->reg_base, OUT_OFFSET(nr), (nr % 32), val);
spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
}
static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset,
@@ -253,6 +274,22 @@ static int pci1xxxx_gpio_set_type(struct irq_data *data, unsigned int trigger_ty
return true;
}
+static int pci1xxxx_gpio_set_wake(struct irq_data *data, unsigned int enable)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct pci1xxxx_gpio *priv = gpiochip_get_data(chip);
+ unsigned int gpio = irqd_to_hwirq(data);
+ unsigned int bitpos = gpio % 32;
+ unsigned int bank = gpio / 32;
+
+ if (enable)
+ priv->gpio_wake_mask[bank] |= (1 << bitpos);
+ else
+ priv->gpio_wake_mask[bank] &= ~(1 << bitpos);
+
+ return 0;
+}
+
static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id)
{
struct pci1xxxx_gpio *priv = dev_id;
@@ -300,6 +337,7 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = {
.irq_mask = pci1xxxx_gpio_irq_mask,
.irq_unmask = pci1xxxx_gpio_irq_unmask,
.irq_set_type = pci1xxxx_gpio_set_type,
+ .irq_set_wake = pci1xxxx_gpio_set_wake,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
@@ -307,32 +345,83 @@ static const struct irq_chip pci1xxxx_gpio_irqchip = {
static int pci1xxxx_gpio_suspend(struct device *dev)
{
struct pci1xxxx_gpio *priv = dev_get_drvdata(dev);
+ struct device *parent = priv->aux_dev->dev.parent;
+ struct pci_dev *pcidev = to_pci_dev(parent);
+ unsigned int gpio_bank_base;
+ unsigned int wake_mask;
+ unsigned int gpiobank;
unsigned long flags;
+ for (gpiobank = 0; gpiobank < 3; gpiobank++) {
+ wake_mask = priv->gpio_wake_mask[gpiobank];
+
+ if (wake_mask) {
+ gpio_bank_base = gpiobank * 32;
+
+ pci1xxx_assign_bit(priv->reg_base,
+ PIO_PCI_CTRL_REG_OFFSET, 0, true);
+ writel(~wake_mask, priv->reg_base +
+ WAKEMASK_OFFSET(gpio_bank_base));
+ }
+ }
+
spin_lock_irqsave(&priv->lock, flags);
pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
16, true);
pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
17, false);
pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, true);
+
+ if (priv->dev_rev >= 0xC0)
+ pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, true);
+
spin_unlock_irqrestore(&priv->lock, flags);
+ device_set_wakeup_enable(&pcidev->dev, true);
+ pci_wake_from_d3(pcidev, true);
+
return 0;
}
static int pci1xxxx_gpio_resume(struct device *dev)
{
struct pci1xxxx_gpio *priv = dev_get_drvdata(dev);
+ struct device *parent = priv->aux_dev->dev.parent;
+ struct pci_dev *pcidev = to_pci_dev(parent);
+ unsigned int gpio_bank_base;
+ unsigned int wake_mask;
+ unsigned int gpiobank;
unsigned long flags;
+ for (gpiobank = 0; gpiobank < 3; gpiobank++) {
+ wake_mask = priv->gpio_wake_mask[gpiobank];
+
+ if (wake_mask) {
+ gpio_bank_base = gpiobank * 32;
+
+ writel(wake_mask, priv->reg_base +
+ INTR_STAT_OFFSET(gpio_bank_base));
+ pci1xxx_assign_bit(priv->reg_base,
+ PIO_PCI_CTRL_REG_OFFSET, 0, false);
+ writel(0xffffffff, priv->reg_base +
+ WAKEMASK_OFFSET(gpio_bank_base));
+ }
+ }
+
spin_lock_irqsave(&priv->lock, flags);
pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
17, true);
pci1xxx_assign_bit(priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET,
16, false);
pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 16, false);
+
+ if (priv->dev_rev >= 0xC0)
+ pci1xxx_assign_bit(priv->reg_base, PERI_GEN_RESET, 17, false);
+
spin_unlock_irqrestore(&priv->lock, flags);
+ pci_wake_from_d3(pcidev, false);
+
return 0;
}
@@ -349,7 +438,7 @@ static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq)
gchip->direction_output = pci1xxxx_gpio_direction_output;
gchip->get_direction = pci1xxxx_gpio_get_direction;
gchip->get = pci1xxxx_gpio_get;
- gchip->set = pci1xxxx_gpio_set;
+ gchip->set_rv = pci1xxxx_gpio_set;
gchip->set_config = pci1xxxx_gpio_set_config;
gchip->dbg_show = NULL;
gchip->base = -1;
@@ -412,6 +501,10 @@ static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev,
if (retval < 0)
return retval;
+ retval = pci1xxxx_gpio_get_device_revision(priv);
+ if (retval)
+ return retval;
+
dev_set_drvdata(&aux_dev->dev, priv);
return devm_gpiochip_add_data(&aux_dev->dev, &priv->gpio, priv);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index b09b79fedaba..c484f416fae4 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -133,7 +133,7 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl,
break;
case MEI_EXT_HDR_GSC:
gsc_f2h = (struct mei_ext_hdr_gsc_f2h *)ext;
- cb->ext_hdr = kzalloc(sizeof(*gsc_f2h), GFP_KERNEL);
+ cb->ext_hdr = (struct mei_ext_hdr *)kzalloc(sizeof(*gsc_f2h), GFP_KERNEL);
if (!cb->ext_hdr) {
cb->status = -ENOMEM;
goto discard;
diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c
index da26a080916c..267d0de5fade 100644
--- a/drivers/misc/mei/vsc-tp.c
+++ b/drivers/misc/mei/vsc-tp.c
@@ -324,7 +324,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)
guard(mutex)(&tp->mutex);
/* rom xfer is big endian */
- cpu_to_be32_array((u32 *)tp->tx_buf, obuf, words);
+ cpu_to_be32_array((__be32 *)tp->tx_buf, obuf, words);
ret = read_poll_timeout(gpiod_get_value_cansleep, ret,
!ret, VSC_TP_ROM_XFER_POLL_DELAY_US,
@@ -340,7 +340,7 @@ int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)
return ret;
if (ibuf)
- be32_to_cpu_array(ibuf, (u32 *)tp->rx_buf, words);
+ be32_to_cpu_array(ibuf, (__be32 *)tp->rx_buf, words);
return ret;
}
diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c
index 0a24ce44cc37..6db1c9d48f8f 100644
--- a/drivers/misc/tps6594-pfsm.c
+++ b/drivers/misc/tps6594-pfsm.c
@@ -281,6 +281,9 @@ static int tps6594_pfsm_probe(struct platform_device *pdev)
pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
tps->chip_id, tps->reg);
+ if (!pfsm->miscdev.name)
+ return -ENOMEM;
+
pfsm->miscdev.fops = &tps6594_pfsm_fops;
pfsm->miscdev.parent = dev->parent;
pfsm->chip_id = tps->chip_id;
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
index abe79f6fd2a7..b64944367ac5 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -227,6 +227,7 @@ static int drv_cp_harray_to_user(void __user *user_buf_uva,
static int vmci_host_setup_notify(struct vmci_ctx *context,
unsigned long uva)
{
+ struct page *page;
int retval;
if (context->notify_page) {
@@ -243,13 +244,11 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
/*
* Lock physical page backing a given user VA.
*/
- retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &context->notify_page);
- if (retval != 1) {
- context->notify_page = NULL;
+ retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &page);
+ if (retval != 1)
return VMCI_ERROR_GENERIC;
- }
- if (context->notify_page == NULL)
- return VMCI_ERROR_UNAVAILABLE;
+
+ context->notify_page = page;
/*
* Map the locked page and set up notify pointer.
diff --git a/drivers/mux/adg792a.c b/drivers/mux/adg792a.c
index 4da5aecb9fc6..a5afe29e3cf1 100644
--- a/drivers/mux/adg792a.c
+++ b/drivers/mux/adg792a.c
@@ -141,7 +141,7 @@ MODULE_DEVICE_TABLE(of, adg792a_of_match);
static struct i2c_driver adg792a_driver = {
.driver = {
.name = "adg792a",
- .of_match_table = of_match_ptr(adg792a_of_match),
+ .of_match_table = adg792a_of_match,
},
.probe = adg792a_probe,
.id_table = adg792a_id,
diff --git a/drivers/mux/adgs1408.c b/drivers/mux/adgs1408.c
index 22ed051eb1a4..5eaf07d09ac9 100644
--- a/drivers/mux/adgs1408.c
+++ b/drivers/mux/adgs1408.c
@@ -59,9 +59,7 @@ static int adgs1408_probe(struct spi_device *spi)
s32 idle_state;
int ret;
- chip_id = (enum adgs1408_chip_id)device_get_match_data(dev);
- if (!chip_id)
- chip_id = spi_get_device_id(spi)->driver_data;
+ chip_id = (kernel_ulong_t)spi_get_device_match_data(spi);
mux_chip = devm_mux_chip_alloc(dev, 1, 0);
if (IS_ERR(mux_chip))
diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c
index 5710879cd47f..4cc3202c58f3 100644
--- a/drivers/mux/gpio.c
+++ b/drivers/mux/gpio.c
@@ -15,6 +15,7 @@
#include <linux/mux/driver.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/regulator/consumer.h>
struct mux_gpio {
struct gpio_descs *gpios;
@@ -80,6 +81,10 @@ static int mux_gpio_probe(struct platform_device *pdev)
mux_chip->mux->idle_state = idle_state;
}
+ ret = devm_regulator_get_enable_optional(dev, "mux");
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to get/enable mux supply\n");
+
ret = devm_mux_chip_register(dev, mux_chip);
if (ret < 0)
return ret;
diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c
index 30a952c34365..9993ce38a818 100644
--- a/drivers/mux/mmio.c
+++ b/drivers/mux/mmio.c
@@ -33,6 +33,12 @@ static const struct of_device_id mux_mmio_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mux_mmio_dt_ids);
+static const struct regmap_config mux_mmio_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
static int mux_mmio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -40,6 +46,7 @@ static int mux_mmio_probe(struct platform_device *pdev)
struct regmap_field **fields;
struct mux_chip *mux_chip;
struct regmap *regmap;
+ void __iomem *base;
int num_fields;
int ret;
int i;
@@ -47,7 +54,11 @@ static int mux_mmio_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "mmio-mux")) {
regmap = syscon_node_to_regmap(np->parent);
} else {
- regmap = device_node_to_regmap(np);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ regmap = ERR_PTR(-ENODEV);
+ else
+ regmap = regmap_init_mmio(dev, base, &mux_mmio_regmap_cfg);
/* Fallback to checking the parent node on "real" errors. */
if (IS_ERR(regmap) && regmap != ERR_PTR(-EPROBE_DEFER)) {
regmap = dev_get_regmap(dev->parent, NULL);
@@ -107,7 +118,7 @@ static int mux_mmio_probe(struct platform_device *pdev)
fields[i] = devm_regmap_field_alloc(dev, regmap, field);
if (IS_ERR(fields[i])) {
ret = PTR_ERR(fields[i]);
- dev_err(dev, "bitfield %d: failed allocate: %d\n",
+ dev_err(dev, "bitfield %d: failed to allocate: %d\n",
i, ret);
return ret;
}
diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c
index 7d3066691d5d..52301511ed1b 100644
--- a/drivers/net/can/kvaser_pciefd.c
+++ b/drivers/net/can/kvaser_pciefd.c
@@ -966,7 +966,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
u32 status, tx_nr_packets_max;
netdev = alloc_candev(sizeof(struct kvaser_pciefd_can),
- KVASER_PCIEFD_CAN_TX_MAX_COUNT);
+ roundup_pow_of_two(KVASER_PCIEFD_CAN_TX_MAX_COUNT));
if (!netdev)
return -ENOMEM;
@@ -995,7 +995,6 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
can->tx_max_count = min(KVASER_PCIEFD_CAN_TX_MAX_COUNT, tx_nr_packets_max - 1);
can->can.clock.freq = pcie->freq;
- can->can.echo_skb_max = roundup_pow_of_two(can->tx_max_count);
spin_lock_init(&can->lock);
can->can.bittiming_const = &kvaser_pciefd_bittiming_const;
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 132683ed3abe..862bdccb7439 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -22,6 +22,7 @@
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/math.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/platform_data/b53.h>
#include <linux/phy.h>
@@ -1322,41 +1323,17 @@ static void b53_adjust_63xx_rgmii(struct dsa_switch *ds, int port,
phy_interface_t interface)
{
struct b53_device *dev = ds->priv;
- u8 rgmii_ctrl = 0, off;
-
- if (port == dev->imp_port)
- off = B53_RGMII_CTRL_IMP;
- else
- off = B53_RGMII_CTRL_P(port);
+ u8 rgmii_ctrl = 0;
- b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
-
- switch (interface) {
- case PHY_INTERFACE_MODE_RGMII_ID:
- rgmii_ctrl |= (RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
- break;
- case PHY_INTERFACE_MODE_RGMII_RXID:
- rgmii_ctrl &= ~(RGMII_CTRL_DLL_TXC);
- rgmii_ctrl |= RGMII_CTRL_DLL_RXC;
- break;
- case PHY_INTERFACE_MODE_RGMII_TXID:
- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC);
- rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
- break;
- case PHY_INTERFACE_MODE_RGMII:
- default:
- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
- break;
- }
+ b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), &rgmii_ctrl);
+ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
- if (port != dev->imp_port) {
- if (is63268(dev))
- rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
+ if (is63268(dev))
+ rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE;
- rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
- }
+ rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII;
- b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
+ b53_write8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_P(port), rgmii_ctrl);
dev_dbg(ds->dev, "Configured port %d for %s\n", port,
phy_modes(interface));
@@ -1377,8 +1354,7 @@ static void b53_adjust_531x5_rgmii(struct dsa_switch *ds, int port,
* tx_clk aligned timing (restoring to reset defaults)
*/
b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl);
- rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC |
- RGMII_CTRL_TIMING_SEL);
+ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC);
/* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make
* sure that we enable the port TX clock internal delay to
@@ -1398,7 +1374,10 @@ static void b53_adjust_531x5_rgmii(struct dsa_switch *ds, int port,
rgmii_ctrl |= RGMII_CTRL_DLL_TXC;
if (interface == PHY_INTERFACE_MODE_RGMII)
rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC;
- rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
+
+ if (dev->chip_id != BCM53115_DEVICE_ID)
+ rgmii_ctrl |= RGMII_CTRL_TIMING_SEL;
+
b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl);
dev_info(ds->dev, "Configured port %d for %s\n", port,
@@ -1462,6 +1441,10 @@ static void b53_phylink_get_caps(struct dsa_switch *ds, int port,
__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
+ /* BCM63xx RGMII ports support RGMII */
+ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
+ phy_interface_set_rgmii(config->supported_interfaces);
+
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
MAC_10 | MAC_100;
@@ -1501,7 +1484,7 @@ static void b53_phylink_mac_config(struct phylink_config *config,
struct b53_device *dev = ds->priv;
int port = dp->index;
- if (is63xx(dev) && port >= B53_63XX_RGMII0)
+ if (is63xx(dev) && in_range(port, B53_63XX_RGMII0, 4))
b53_adjust_63xx_rgmii(ds, port, interface);
if (mode == MLO_AN_FIXED) {
@@ -2353,6 +2336,9 @@ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy)
{
int ret;
+ if (!b53_support_eee(ds, port))
+ return 0;
+
ret = phy_init_eee(phy, false);
if (ret)
return 0;
@@ -2367,7 +2353,7 @@ bool b53_support_eee(struct dsa_switch *ds, int port)
{
struct b53_device *dev = ds->priv;
- return !is5325(dev) && !is5365(dev);
+ return !is5325(dev) && !is5365(dev) && !is63xx(dev);
}
EXPORT_SYMBOL(b53_support_eee);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index d1d3b854361e..a7ec609d64de 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -84,6 +84,8 @@ static void airoha_set_macaddr(struct airoha_gdm_port *port, const u8 *addr)
val = (addr[3] << 16) | (addr[4] << 8) | addr[5];
airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val);
airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val);
+
+ airoha_ppe_init_upd_mem(port);
}
static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr,
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index b815697302bf..a970b789cf23 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -614,6 +614,7 @@ void airoha_ppe_check_skb(struct airoha_ppe *ppe, struct sk_buff *skb,
int airoha_ppe_setup_tc_block_cb(struct net_device *dev, void *type_data);
int airoha_ppe_init(struct airoha_eth *eth);
void airoha_ppe_deinit(struct airoha_eth *eth);
+void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port);
struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
u32 hash);
void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash,
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 12d32c92717a..9067d2fc7706 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -223,6 +223,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
int dsa_port = airoha_get_dsa_port(&dev);
struct airoha_foe_mac_info_common *l2;
u32 qdata, ports_pad, val;
+ u8 smac_id = 0xf;
memset(hwe, 0, sizeof(*hwe));
@@ -257,6 +258,8 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
*/
if (airhoa_is_lan_gdm_port(port))
val |= AIROHA_FOE_IB2_FAST_PATH;
+
+ smac_id = port->id;
}
if (is_multicast_ether_addr(data->eth.h_dest))
@@ -291,7 +294,7 @@ static int airoha_ppe_foe_entry_prepare(struct airoha_eth *eth,
hwe->ipv4.l2.src_mac_lo =
get_unaligned_be16(data->eth.h_source + 4);
} else {
- l2->src_mac_hi = FIELD_PREP(AIROHA_FOE_MAC_SMAC_ID, 0xf);
+ l2->src_mac_hi = FIELD_PREP(AIROHA_FOE_MAC_SMAC_ID, smac_id);
}
if (data->vlan.num) {
@@ -636,7 +639,6 @@ airoha_ppe_foe_commit_subflow_entry(struct airoha_ppe *ppe,
u32 mask = AIROHA_FOE_IB1_BIND_PACKET_TYPE | AIROHA_FOE_IB1_BIND_UDP;
struct airoha_foe_entry *hwe_p, hwe;
struct airoha_flow_table_entry *f;
- struct airoha_foe_mac_info *l2;
int type;
hwe_p = airoha_ppe_foe_get_entry(ppe, hash);
@@ -653,18 +655,25 @@ airoha_ppe_foe_commit_subflow_entry(struct airoha_ppe *ppe,
memcpy(&hwe, hwe_p, sizeof(*hwe_p));
hwe.ib1 = (hwe.ib1 & mask) | (e->data.ib1 & ~mask);
- l2 = &hwe.bridge.l2;
- memcpy(l2, &e->data.bridge.l2, sizeof(*l2));
type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe.ib1);
- if (type == PPE_PKT_TYPE_IPV4_HNAPT)
- memcpy(&hwe.ipv4.new_tuple, &hwe.ipv4.orig_tuple,
- sizeof(hwe.ipv4.new_tuple));
- else if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T &&
- l2->common.etype == ETH_P_IP)
- l2->common.etype = ETH_P_IPV6;
-
- hwe.bridge.ib2 = e->data.bridge.ib2;
+ if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T) {
+ memcpy(&hwe.ipv6.l2, &e->data.bridge.l2, sizeof(hwe.ipv6.l2));
+ hwe.ipv6.ib2 = e->data.bridge.ib2;
+ /* setting smac_id to 0xf instruct the hw to keep original
+ * source mac address
+ */
+ hwe.ipv6.l2.src_mac_hi = FIELD_PREP(AIROHA_FOE_MAC_SMAC_ID,
+ 0xf);
+ } else {
+ memcpy(&hwe.bridge.l2, &e->data.bridge.l2,
+ sizeof(hwe.bridge.l2));
+ hwe.bridge.ib2 = e->data.bridge.ib2;
+ if (type == PPE_PKT_TYPE_IPV4_HNAPT)
+ memcpy(&hwe.ipv4.new_tuple, &hwe.ipv4.orig_tuple,
+ sizeof(hwe.ipv4.new_tuple));
+ }
+
hwe.bridge.data = e->data.bridge.data;
airoha_ppe_foe_commit_entry(ppe, &hwe, hash);
@@ -1238,6 +1247,27 @@ void airoha_ppe_check_skb(struct airoha_ppe *ppe, struct sk_buff *skb,
airoha_ppe_foe_insert_entry(ppe, skb, hash);
}
+void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port)
+{
+ struct airoha_eth *eth = port->qdma->eth;
+ struct net_device *dev = port->dev;
+ const u8 *addr = dev->dev_addr;
+ u32 val;
+
+ val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+ airoha_fe_wr(eth, REG_UPDMEM_DATA(0), val);
+ airoha_fe_wr(eth, REG_UPDMEM_CTRL(0),
+ FIELD_PREP(PPE_UPDMEM_ADDR_MASK, port->id) |
+ PPE_UPDMEM_WR_MASK | PPE_UPDMEM_REQ_MASK);
+
+ val = (addr[0] << 8) | addr[1];
+ airoha_fe_wr(eth, REG_UPDMEM_DATA(0), val);
+ airoha_fe_wr(eth, REG_UPDMEM_CTRL(0),
+ FIELD_PREP(PPE_UPDMEM_ADDR_MASK, port->id) |
+ FIELD_PREP(PPE_UPDMEM_OFFSET_MASK, 1) |
+ PPE_UPDMEM_WR_MASK | PPE_UPDMEM_REQ_MASK);
+}
+
int airoha_ppe_init(struct airoha_eth *eth)
{
struct airoha_ppe *ppe;
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index d931530fc96f..04187eb40ec6 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -313,6 +313,16 @@
#define REG_PPE_RAM_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x320)
#define REG_PPE_RAM_ENTRY(_m, _n) (REG_PPE_RAM_BASE(_m) + ((_n) << 2))
+#define REG_UPDMEM_CTRL(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x370)
+#define PPE_UPDMEM_ACK_MASK BIT(31)
+#define PPE_UPDMEM_ADDR_MASK GENMASK(11, 8)
+#define PPE_UPDMEM_OFFSET_MASK GENMASK(7, 4)
+#define PPE_UPDMEM_SEL_MASK GENMASK(3, 2)
+#define PPE_UPDMEM_WR_MASK BIT(1)
+#define PPE_UPDMEM_REQ_MASK BIT(0)
+
+#define REG_UPDMEM_DATA(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x374)
+
#define REG_FE_GDM_TX_OK_PKT_CNT_H(_n) (GDM_BASE(_n) + 0x280)
#define REG_FE_GDM_TX_OK_BYTE_CNT_H(_n) (GDM_BASE(_n) + 0x284)
#define REG_FE_GDM_TX_ETH_PKT_CNT_H(_n) (GDM_BASE(_n) + 0x288)
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index e1ffbd561fac..7cd1eda0b449 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -2153,7 +2153,7 @@ void gve_handle_report_stats(struct gve_priv *priv)
};
stats[stats_idx++] = (struct stats) {
.stat_name = cpu_to_be32(RX_BUFFERS_POSTED),
- .value = cpu_to_be64(priv->rx[0].fill_cnt),
+ .value = cpu_to_be64(priv->rx[idx].fill_cnt),
.queue_id = cpu_to_be32(idx),
};
}
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
index a27f1574a733..9d705d94b065 100644
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -764,6 +764,9 @@ static int gve_tx_add_skb_dqo(struct gve_tx_ring *tx,
s16 completion_tag;
pkt = gve_alloc_pending_packet(tx);
+ if (!pkt)
+ return -ENOMEM;
+
pkt->skb = skb;
completion_tag = pkt - tx->dqo.pending_packets;
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
index 093aa6d775ff..497f2a36f35d 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
@@ -324,8 +324,6 @@ static __init int hinic3_nic_lld_init(void)
{
int err;
- pr_info("%s: %s\n", HINIC3_NIC_DRV_NAME, HINIC3_NIC_DRV_DESC);
-
err = hinic3_lld_init();
if (err)
return err;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 9de3e0ba3731..f7a98ff43a57 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -268,7 +268,6 @@ struct iavf_adapter {
struct list_head vlan_filter_list;
int num_vlan_filters;
struct list_head mac_filter_list;
- struct mutex crit_lock;
/* Lock to protect accesses to MAC and VLAN lists */
spinlock_t mac_vlan_list_lock;
char misc_vector_name[IFNAMSIZ + 9];
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index 288bb5b2e72e..2b2b315205b5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -4,6 +4,8 @@
#include <linux/bitfield.h>
#include <linux/uaccess.h>
+#include <net/netdev_lock.h>
+
/* ethtool support for iavf */
#include "iavf.h"
@@ -1256,9 +1258,10 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
{
struct ethtool_rx_flow_spec *fsp = &cmd->fs;
struct iavf_fdir_fltr *fltr;
- int count = 50;
int err;
+ netdev_assert_locked(adapter->netdev);
+
if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP;
@@ -1277,14 +1280,6 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
if (!fltr)
return -ENOMEM;
- while (!mutex_trylock(&adapter->crit_lock)) {
- if (--count == 0) {
- kfree(fltr);
- return -EINVAL;
- }
- udelay(1);
- }
-
err = iavf_add_fdir_fltr_info(adapter, fsp, fltr);
if (!err)
err = iavf_fdir_add_fltr(adapter, fltr);
@@ -1292,7 +1287,6 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
if (err)
kfree(fltr);
- mutex_unlock(&adapter->crit_lock);
return err;
}
@@ -1435,11 +1429,13 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
{
struct iavf_adv_rss *rss_old, *rss_new;
bool rss_new_add = false;
- int count = 50, err = 0;
bool symm = false;
u64 hash_flds;
+ int err = 0;
u32 hdrs;
+ netdev_assert_locked(adapter->netdev);
+
if (!ADV_RSS_SUPPORT(adapter))
return -EOPNOTSUPP;
@@ -1463,15 +1459,6 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
return -EINVAL;
}
- while (!mutex_trylock(&adapter->crit_lock)) {
- if (--count == 0) {
- kfree(rss_new);
- return -EINVAL;
- }
-
- udelay(1);
- }
-
spin_lock_bh(&adapter->adv_rss_lock);
rss_old = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);
if (rss_old) {
@@ -1500,8 +1487,6 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
if (!err)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_ADV_RSS_CFG);
- mutex_unlock(&adapter->crit_lock);
-
if (!rss_new_add)
kfree(rss_new);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 6d7ba4d67a19..2c0bb41809a4 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1287,11 +1287,11 @@ static void iavf_configure(struct iavf_adapter *adapter)
/**
* iavf_up_complete - Finish the last steps of bringing up a connection
* @adapter: board private structure
- *
- * Expects to be called while holding crit_lock.
- **/
+ */
static void iavf_up_complete(struct iavf_adapter *adapter)
{
+ netdev_assert_locked(adapter->netdev);
+
iavf_change_state(adapter, __IAVF_RUNNING);
clear_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
@@ -1410,13 +1410,13 @@ static void iavf_clear_adv_rss_conf(struct iavf_adapter *adapter)
/**
* iavf_down - Shutdown the connection processing
* @adapter: board private structure
- *
- * Expects to be called while holding crit_lock.
- **/
+ */
void iavf_down(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ netdev_assert_locked(netdev);
+
if (adapter->state <= __IAVF_DOWN_PENDING)
return;
@@ -2025,22 +2025,21 @@ err:
* iavf_finish_config - do all netdev work that needs RTNL
* @work: our work_struct
*
- * Do work that needs both RTNL and crit_lock.
- **/
+ * Do work that needs RTNL.
+ */
static void iavf_finish_config(struct work_struct *work)
{
struct iavf_adapter *adapter;
- bool locks_released = false;
+ bool netdev_released = false;
int pairs, err;
adapter = container_of(work, struct iavf_adapter, finish_config);
/* Always take RTNL first to prevent circular lock dependency;
- * The dev->lock is needed to update the queue number
+ * the dev->lock (== netdev lock) is needed to update the queue number.
*/
rtnl_lock();
netdev_lock(adapter->netdev);
- mutex_lock(&adapter->crit_lock);
if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) &&
adapter->netdev->reg_state == NETREG_REGISTERED &&
@@ -2059,22 +2058,21 @@ static void iavf_finish_config(struct work_struct *work)
netif_set_real_num_tx_queues(adapter->netdev, pairs);
if (adapter->netdev->reg_state != NETREG_REGISTERED) {
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(adapter->netdev);
- locks_released = true;
+ netdev_released = true;
err = register_netdevice(adapter->netdev);
if (err) {
dev_err(&adapter->pdev->dev, "Unable to register netdev (%d)\n",
err);
/* go back and try again.*/
- mutex_lock(&adapter->crit_lock);
+ netdev_lock(adapter->netdev);
iavf_free_rss(adapter);
iavf_free_misc_irq(adapter);
iavf_reset_interrupt_capability(adapter);
iavf_change_state(adapter,
__IAVF_INIT_CONFIG_ADAPTER);
- mutex_unlock(&adapter->crit_lock);
+ netdev_unlock(adapter->netdev);
goto out;
}
}
@@ -2090,10 +2088,8 @@ static void iavf_finish_config(struct work_struct *work)
}
out:
- if (!locks_released) {
- mutex_unlock(&adapter->crit_lock);
+ if (!netdev_released)
netdev_unlock(adapter->netdev);
- }
rtnl_unlock();
}
@@ -2911,28 +2907,15 @@ err:
iavf_change_state(adapter, __IAVF_INIT_FAILED);
}
-/**
- * iavf_watchdog_task - Periodic call-back task
- * @work: pointer to work_struct
- **/
-static void iavf_watchdog_task(struct work_struct *work)
+static const int IAVF_NO_RESCHED = -1;
+
+/* return: msec delay for requeueing itself */
+static int iavf_watchdog_step(struct iavf_adapter *adapter)
{
- struct iavf_adapter *adapter = container_of(work,
- struct iavf_adapter,
- watchdog_task.work);
- struct net_device *netdev = adapter->netdev;
struct iavf_hw *hw = &adapter->hw;
u32 reg_val;
- netdev_lock(netdev);
- if (!mutex_trylock(&adapter->crit_lock)) {
- if (adapter->state == __IAVF_REMOVE) {
- netdev_unlock(netdev);
- return;
- }
-
- goto restart_watchdog;
- }
+ netdev_assert_locked(adapter->netdev);
if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
iavf_change_state(adapter, __IAVF_COMM_FAILED);
@@ -2940,39 +2923,19 @@ static void iavf_watchdog_task(struct work_struct *work)
switch (adapter->state) {
case __IAVF_STARTUP:
iavf_startup(adapter);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(30));
- return;
+ return 30;
case __IAVF_INIT_VERSION_CHECK:
iavf_init_version_check(adapter);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(30));
- return;
+ return 30;
case __IAVF_INIT_GET_RESOURCES:
iavf_init_get_resources(adapter);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(1));
- return;
+ return 1;
case __IAVF_INIT_EXTENDED_CAPS:
iavf_init_process_extended_caps(adapter);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(1));
- return;
+ return 1;
case __IAVF_INIT_CONFIG_ADAPTER:
iavf_init_config_adapter(adapter);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(1));
- return;
+ return 1;
case __IAVF_INIT_FAILED:
if (test_bit(__IAVF_IN_REMOVE_TASK,
&adapter->crit_section)) {
@@ -2980,27 +2943,18 @@ static void iavf_watchdog_task(struct work_struct *work)
* watchdog task, iavf_remove should handle this state
* as it can loop forever
*/
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- return;
+ return IAVF_NO_RESCHED;
}
if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
dev_err(&adapter->pdev->dev,
"Failed to communicate with PF; waiting before retry\n");
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
iavf_shutdown_adminq(hw);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq,
- &adapter->watchdog_task, (5 * HZ));
- return;
+ return 5000;
}
/* Try again from failed step*/
iavf_change_state(adapter, adapter->last_state);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task, HZ);
- return;
+ return 1000;
case __IAVF_COMM_FAILED:
if (test_bit(__IAVF_IN_REMOVE_TASK,
&adapter->crit_section)) {
@@ -3010,9 +2964,7 @@ static void iavf_watchdog_task(struct work_struct *work)
*/
iavf_change_state(adapter, __IAVF_INIT_FAILED);
adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- return;
+ return IAVF_NO_RESCHED;
}
reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
@@ -3030,18 +2982,9 @@ static void iavf_watchdog_task(struct work_struct *work)
}
adapter->aq_required = 0;
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq,
- &adapter->watchdog_task,
- msecs_to_jiffies(10));
- return;
+ return 10;
case __IAVF_RESETTING:
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- HZ * 2);
- return;
+ return 2000;
case __IAVF_DOWN:
case __IAVF_DOWN_PENDING:
case __IAVF_TESTING:
@@ -3068,9 +3011,7 @@ static void iavf_watchdog_task(struct work_struct *work)
break;
case __IAVF_REMOVE:
default:
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- return;
+ return IAVF_NO_RESCHED;
}
/* check for hw reset */
@@ -3080,24 +3021,29 @@ static void iavf_watchdog_task(struct work_struct *work)
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
iavf_schedule_reset(adapter, IAVF_FLAG_RESET_PENDING);
- mutex_unlock(&adapter->crit_lock);
- netdev_unlock(netdev);
- queue_delayed_work(adapter->wq,
- &adapter->watchdog_task, HZ * 2);
- return;
}
- mutex_unlock(&adapter->crit_lock);
-restart_watchdog:
- netdev_unlock(netdev);
+ return adapter->aq_required ? 20 : 2000;
+}
+
+static void iavf_watchdog_task(struct work_struct *work)
+{
+ struct iavf_adapter *adapter = container_of(work,
+ struct iavf_adapter,
+ watchdog_task.work);
+ struct net_device *netdev = adapter->netdev;
+ int msec_delay;
+
+ netdev_lock(netdev);
+ msec_delay = iavf_watchdog_step(adapter);
+ /* note that we schedule a different task */
if (adapter->state >= __IAVF_DOWN)
queue_work(adapter->wq, &adapter->adminq_task);
- if (adapter->aq_required)
- queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- msecs_to_jiffies(20));
- else
+
+ if (msec_delay != IAVF_NO_RESCHED)
queue_delayed_work(adapter->wq, &adapter->watchdog_task,
- HZ * 2);
+ msecs_to_jiffies(msec_delay));
+ netdev_unlock(netdev);
}
/**
@@ -3105,14 +3051,15 @@ restart_watchdog:
* @adapter: board private structure
*
* Set communication failed flag and free all resources.
- * NOTE: This function is expected to be called with crit_lock being held.
- **/
+ */
static void iavf_disable_vf(struct iavf_adapter *adapter)
{
struct iavf_mac_filter *f, *ftmp;
struct iavf_vlan_filter *fv, *fvtmp;
struct iavf_cloud_filter *cf, *cftmp;
+ netdev_assert_locked(adapter->netdev);
+
adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
/* We don't use netif_running() because it may be true prior to
@@ -3212,17 +3159,7 @@ static void iavf_reset_task(struct work_struct *work)
int i = 0, err;
bool running;
- /* When device is being removed it doesn't make sense to run the reset
- * task, just return in such a case.
- */
netdev_lock(netdev);
- if (!mutex_trylock(&adapter->crit_lock)) {
- if (adapter->state != __IAVF_REMOVE)
- queue_work(adapter->wq, &adapter->reset_task);
-
- netdev_unlock(netdev);
- return;
- }
iavf_misc_irq_disable(adapter);
if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
@@ -3267,7 +3204,6 @@ static void iavf_reset_task(struct work_struct *work)
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
reg_val);
iavf_disable_vf(adapter);
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(netdev);
return; /* Do not attempt to reinit. It's dead, Jim. */
}
@@ -3411,7 +3347,6 @@ continue_reset:
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
wake_up(&adapter->reset_waitqueue);
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(netdev);
return;
@@ -3422,7 +3357,6 @@ reset_err:
}
iavf_disable_vf(adapter);
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(netdev);
dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n");
}
@@ -3435,6 +3369,7 @@ static void iavf_adminq_task(struct work_struct *work)
{
struct iavf_adapter *adapter =
container_of(work, struct iavf_adapter, adminq_task);
+ struct net_device *netdev = adapter->netdev;
struct iavf_hw *hw = &adapter->hw;
struct iavf_arq_event_info event;
enum virtchnl_ops v_op;
@@ -3442,13 +3377,7 @@ static void iavf_adminq_task(struct work_struct *work)
u32 val, oldval;
u16 pending;
- if (!mutex_trylock(&adapter->crit_lock)) {
- if (adapter->state == __IAVF_REMOVE)
- return;
-
- queue_work(adapter->wq, &adapter->adminq_task);
- goto out;
- }
+ netdev_lock(netdev);
if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
goto unlock;
@@ -3515,8 +3444,7 @@ static void iavf_adminq_task(struct work_struct *work)
freedom:
kfree(event.msg_buf);
unlock:
- mutex_unlock(&adapter->crit_lock);
-out:
+ netdev_unlock(netdev);
/* re-enable Admin queue interrupt cause */
iavf_misc_irq_enable(adapter);
}
@@ -4209,8 +4137,8 @@ static int iavf_configure_clsflower(struct iavf_adapter *adapter,
struct flow_cls_offload *cls_flower)
{
int tc = tc_classid_to_hwtc(adapter->netdev, cls_flower->classid);
- struct iavf_cloud_filter *filter = NULL;
- int err = -EINVAL, count = 50;
+ struct iavf_cloud_filter *filter;
+ int err;
if (tc < 0) {
dev_err(&adapter->pdev->dev, "Invalid traffic class\n");
@@ -4220,17 +4148,10 @@ static int iavf_configure_clsflower(struct iavf_adapter *adapter,
filter = kzalloc(sizeof(*filter), GFP_KERNEL);
if (!filter)
return -ENOMEM;
-
- while (!mutex_trylock(&adapter->crit_lock)) {
- if (--count == 0) {
- kfree(filter);
- return err;
- }
- udelay(1);
- }
-
filter->cookie = cls_flower->cookie;
+ netdev_lock(adapter->netdev);
+
/* bail out here if filter already exists */
spin_lock_bh(&adapter->cloud_filter_list_lock);
if (iavf_find_cf(adapter, &cls_flower->cookie)) {
@@ -4264,7 +4185,7 @@ err:
if (err)
kfree(filter);
- mutex_unlock(&adapter->crit_lock);
+ netdev_unlock(adapter->netdev);
return err;
}
@@ -4568,28 +4489,13 @@ static int iavf_open(struct net_device *netdev)
return -EIO;
}
- while (!mutex_trylock(&adapter->crit_lock)) {
- /* If we are in __IAVF_INIT_CONFIG_ADAPTER state the crit_lock
- * is already taken and iavf_open is called from an upper
- * device's notifier reacting on NETDEV_REGISTER event.
- * We have to leave here to avoid dead lock.
- */
- if (adapter->state == __IAVF_INIT_CONFIG_ADAPTER)
- return -EBUSY;
-
- usleep_range(500, 1000);
- }
-
- if (adapter->state != __IAVF_DOWN) {
- err = -EBUSY;
- goto err_unlock;
- }
+ if (adapter->state != __IAVF_DOWN)
+ return -EBUSY;
if (adapter->state == __IAVF_RUNNING &&
!test_bit(__IAVF_VSI_DOWN, adapter->vsi.state)) {
dev_dbg(&adapter->pdev->dev, "VF is already open.\n");
- err = 0;
- goto err_unlock;
+ return 0;
}
/* allocate transmit descriptors */
@@ -4608,9 +4514,7 @@ static int iavf_open(struct net_device *netdev)
goto err_req_irq;
spin_lock_bh(&adapter->mac_vlan_list_lock);
-
iavf_add_filter(adapter, adapter->hw.mac.addr);
-
spin_unlock_bh(&adapter->mac_vlan_list_lock);
/* Restore filters that were removed with IFF_DOWN */
@@ -4623,8 +4527,6 @@ static int iavf_open(struct net_device *netdev)
iavf_irq_enable(adapter, true);
- mutex_unlock(&adapter->crit_lock);
-
return 0;
err_req_irq:
@@ -4634,8 +4536,6 @@ err_setup_rx:
iavf_free_all_rx_resources(adapter);
err_setup_tx:
iavf_free_all_tx_resources(adapter);
-err_unlock:
- mutex_unlock(&adapter->crit_lock);
return err;
}
@@ -4659,12 +4559,8 @@ static int iavf_close(struct net_device *netdev)
netdev_assert_locked(netdev);
- mutex_lock(&adapter->crit_lock);
-
- if (adapter->state <= __IAVF_DOWN_PENDING) {
- mutex_unlock(&adapter->crit_lock);
+ if (adapter->state <= __IAVF_DOWN_PENDING)
return 0;
- }
set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
/* We cannot send IAVF_FLAG_AQ_GET_OFFLOAD_VLAN_V2_CAPS before
@@ -4695,7 +4591,6 @@ static int iavf_close(struct net_device *netdev)
iavf_change_state(adapter, __IAVF_DOWN_PENDING);
iavf_free_traffic_irqs(adapter);
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(netdev);
/* We explicitly don't free resources here because the hardware is
@@ -4714,11 +4609,10 @@ static int iavf_close(struct net_device *netdev)
msecs_to_jiffies(500));
if (!status)
netdev_warn(netdev, "Device resources not yet released\n");
-
netdev_lock(netdev);
- mutex_lock(&adapter->crit_lock);
+
adapter->aq_required |= aq_to_restore;
- mutex_unlock(&adapter->crit_lock);
+
return 0;
}
@@ -5227,15 +5121,16 @@ iavf_shaper_set(struct net_shaper_binding *binding,
struct iavf_adapter *adapter = netdev_priv(binding->netdev);
const struct net_shaper_handle *handle = &shaper->handle;
struct iavf_ring *tx_ring;
- int ret = 0;
+ int ret;
+
+ netdev_assert_locked(adapter->netdev);
- mutex_lock(&adapter->crit_lock);
if (handle->id >= adapter->num_active_queues)
- goto unlock;
+ return 0;
ret = iavf_verify_shaper(binding, shaper, extack);
if (ret)
- goto unlock;
+ return ret;
tx_ring = &adapter->tx_rings[handle->id];
@@ -5245,9 +5140,7 @@ iavf_shaper_set(struct net_shaper_binding *binding,
adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW;
-unlock:
- mutex_unlock(&adapter->crit_lock);
- return ret;
+ return 0;
}
static int iavf_shaper_del(struct net_shaper_binding *binding,
@@ -5257,9 +5150,10 @@ static int iavf_shaper_del(struct net_shaper_binding *binding,
struct iavf_adapter *adapter = netdev_priv(binding->netdev);
struct iavf_ring *tx_ring;
- mutex_lock(&adapter->crit_lock);
+ netdev_assert_locked(adapter->netdev);
+
if (handle->id >= adapter->num_active_queues)
- goto unlock;
+ return 0;
tx_ring = &adapter->tx_rings[handle->id];
tx_ring->q_shaper.bw_min = 0;
@@ -5268,8 +5162,6 @@ static int iavf_shaper_del(struct net_shaper_binding *binding,
adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW;
-unlock:
- mutex_unlock(&adapter->crit_lock);
return 0;
}
@@ -5530,10 +5422,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_alloc_qos_cap;
}
- /* set up the locks for the AQ, do this only once in probe
- * and destroy them only once in remove
- */
- mutex_init(&adapter->crit_lock);
mutex_init(&hw->aq.asq_mutex);
mutex_init(&hw->aq.arq_mutex);
@@ -5596,22 +5484,24 @@ static int iavf_suspend(struct device *dev_d)
{
struct net_device *netdev = dev_get_drvdata(dev_d);
struct iavf_adapter *adapter = netdev_priv(netdev);
+ bool running;
netif_device_detach(netdev);
+ running = netif_running(netdev);
+ if (running)
+ rtnl_lock();
netdev_lock(netdev);
- mutex_lock(&adapter->crit_lock);
- if (netif_running(netdev)) {
- rtnl_lock();
+ if (running)
iavf_down(adapter);
- rtnl_unlock();
- }
+
iavf_free_misc_irq(adapter);
iavf_reset_interrupt_capability(adapter);
- mutex_unlock(&adapter->crit_lock);
netdev_unlock(netdev);
+ if (running)
+ rtnl_unlock();
return 0;
}
@@ -5688,20 +5578,20 @@ static void iavf_remove(struct pci_dev *pdev)
* There are flows where register/unregister netdev may race.
*/
while (1) {
- mutex_lock(&adapter->crit_lock);
+ netdev_lock(netdev);
if (adapter->state == __IAVF_RUNNING ||
adapter->state == __IAVF_DOWN ||
adapter->state == __IAVF_INIT_FAILED) {
- mutex_unlock(&adapter->crit_lock);
+ netdev_unlock(netdev);
break;
}
/* Simply return if we already went through iavf_shutdown */
if (adapter->state == __IAVF_REMOVE) {
- mutex_unlock(&adapter->crit_lock);
+ netdev_unlock(netdev);
return;
}
- mutex_unlock(&adapter->crit_lock);
+ netdev_unlock(netdev);
usleep_range(500, 1000);
}
cancel_delayed_work_sync(&adapter->watchdog_task);
@@ -5711,7 +5601,6 @@ static void iavf_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
netdev_lock(netdev);
- mutex_lock(&adapter->crit_lock);
dev_info(&adapter->pdev->dev, "Removing device\n");
iavf_change_state(adapter, __IAVF_REMOVE);
@@ -5727,9 +5616,11 @@ static void iavf_remove(struct pci_dev *pdev)
iavf_misc_irq_disable(adapter);
/* Shut down all the garbage mashers on the detention level */
+ netdev_unlock(netdev);
cancel_work_sync(&adapter->reset_task);
cancel_delayed_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->adminq_task);
+ netdev_lock(netdev);
adapter->aq_required = 0;
adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
@@ -5747,8 +5638,6 @@ static void iavf_remove(struct pci_dev *pdev)
/* destroy the locks only once, here */
mutex_destroy(&hw->aq.arq_mutex);
mutex_destroy(&hw->aq.asq_mutex);
- mutex_unlock(&adapter->crit_lock);
- mutex_destroy(&adapter->crit_lock);
netdev_unlock(netdev);
iounmap(hw->hw_addr);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 20d3baf955e3..d97d4b25b30d 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -2741,6 +2741,27 @@ void ice_map_xdp_rings(struct ice_vsi *vsi)
}
/**
+ * ice_unmap_xdp_rings - Unmap XDP rings from interrupt vectors
+ * @vsi: the VSI with XDP rings being unmapped
+ */
+static void ice_unmap_xdp_rings(struct ice_vsi *vsi)
+{
+ int v_idx;
+
+ ice_for_each_q_vector(vsi, v_idx) {
+ struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];
+ struct ice_tx_ring *ring;
+
+ ice_for_each_tx_ring(ring, q_vector->tx)
+ if (!ring->tx_buf || !ice_ring_is_xdp(ring))
+ break;
+
+ /* restore the value of last node prior to XDP setup */
+ q_vector->tx.tx_ring = ring;
+ }
+}
+
+/**
* ice_prepare_xdp_rings - Allocate, configure and setup Tx rings for XDP
* @vsi: VSI to bring up Tx rings used by XDP
* @prog: bpf program that will be assigned to VSI
@@ -2803,7 +2824,7 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog,
if (status) {
dev_err(dev, "Failed VSI LAN queue config for XDP, error: %d\n",
status);
- goto clear_xdp_rings;
+ goto unmap_xdp_rings;
}
/* assign the prog only when it's not already present on VSI;
@@ -2819,6 +2840,8 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog,
ice_vsi_assign_bpf_prog(vsi, prog);
return 0;
+unmap_xdp_rings:
+ ice_unmap_xdp_rings(vsi);
clear_xdp_rings:
ice_for_each_xdp_txq(vsi, i)
if (vsi->xdp_rings[i]) {
@@ -2835,6 +2858,8 @@ err_map_xdp:
mutex_unlock(&pf->avail_q_mutex);
devm_kfree(dev, vsi->xdp_rings);
+ vsi->xdp_rings = NULL;
+
return -ENOMEM;
}
@@ -2850,7 +2875,7 @@ int ice_destroy_xdp_rings(struct ice_vsi *vsi, enum ice_xdp_cfg cfg_type)
{
u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
struct ice_pf *pf = vsi->back;
- int i, v_idx;
+ int i;
/* q_vectors are freed in reset path so there's no point in detaching
* rings
@@ -2858,17 +2883,7 @@ int ice_destroy_xdp_rings(struct ice_vsi *vsi, enum ice_xdp_cfg cfg_type)
if (cfg_type == ICE_XDP_CFG_PART)
goto free_qmap;
- ice_for_each_q_vector(vsi, v_idx) {
- struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];
- struct ice_tx_ring *ring;
-
- ice_for_each_tx_ring(ring, q_vector->tx)
- if (!ring->tx_buf || !ice_ring_is_xdp(ring))
- break;
-
- /* restore the value of last node prior to XDP setup */
- q_vector->tx.tx_ring = ring;
- }
+ ice_unmap_xdp_rings(vsi);
free_qmap:
mutex_lock(&pf->avail_q_mutex);
@@ -3013,11 +3028,14 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
xdp_ring_err = ice_vsi_determine_xdp_res(vsi);
if (xdp_ring_err) {
NL_SET_ERR_MSG_MOD(extack, "Not enough Tx resources for XDP");
+ goto resume_if;
} else {
xdp_ring_err = ice_prepare_xdp_rings(vsi, prog,
ICE_XDP_CFG_FULL);
- if (xdp_ring_err)
+ if (xdp_ring_err) {
NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed");
+ goto resume_if;
+ }
}
xdp_features_set_redirect_target(vsi->netdev, true);
/* reallocate Rx queues that are used for zero-copy */
@@ -3035,6 +3053,7 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Rx resources failed");
}
+resume_if:
if (if_running)
ret = ice_up(vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index 6ca13c5dcb14..d9d09296d1d4 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -85,6 +85,27 @@ ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
}
/**
+ * ice_sched_find_next_vsi_node - find the next node for a given VSI
+ * @vsi_node: VSI support node to start search with
+ *
+ * Return: Next VSI support node, or NULL.
+ *
+ * The function returns a pointer to the next node from the VSI layer
+ * assigned to the given VSI, or NULL if there is no such a node.
+ */
+static struct ice_sched_node *
+ice_sched_find_next_vsi_node(struct ice_sched_node *vsi_node)
+{
+ unsigned int vsi_handle = vsi_node->vsi_handle;
+
+ while ((vsi_node = vsi_node->sibling) != NULL)
+ if (vsi_node->vsi_handle == vsi_handle)
+ break;
+
+ return vsi_node;
+}
+
+/**
* ice_aqc_send_sched_elem_cmd - send scheduling elements cmd
* @hw: pointer to the HW struct
* @cmd_opc: cmd opcode
@@ -1084,8 +1105,10 @@ ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
if (parent->num_children < max_child_nodes) {
new_num_nodes = max_child_nodes - parent->num_children;
} else {
- /* This parent is full, try the next sibling */
- parent = parent->sibling;
+ /* This parent is full,
+ * try the next available sibling.
+ */
+ parent = ice_sched_find_next_vsi_node(parent);
/* Don't modify the first node TEID memory if the
* first node was added already in the above call.
* Instead send some temp memory for all other
@@ -1528,12 +1551,23 @@ ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
/* get the first queue group node from VSI sub-tree */
qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
while (qgrp_node) {
+ struct ice_sched_node *next_vsi_node;
+
/* make sure the qgroup node is part of the VSI subtree */
if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
if (qgrp_node->num_children < max_children &&
qgrp_node->owner == owner)
break;
qgrp_node = qgrp_node->sibling;
+ if (qgrp_node)
+ continue;
+
+ next_vsi_node = ice_sched_find_next_vsi_node(vsi_node);
+ if (!next_vsi_node)
+ break;
+
+ vsi_node = next_vsi_node;
+ qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
}
/* Select the best queue group */
@@ -1604,16 +1638,16 @@ ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
/**
* ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes
* @hw: pointer to the HW struct
- * @num_qs: number of queues
+ * @num_new_qs: number of new queues that will be added to the tree
* @num_nodes: num nodes array
*
* This function calculates the number of VSI child nodes based on the
* number of queues.
*/
static void
-ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
+ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_new_qs, u16 *num_nodes)
{
- u16 num = num_qs;
+ u16 num = num_new_qs;
u8 i, qgl, vsil;
qgl = ice_sched_get_qgrp_layer(hw);
@@ -1779,7 +1813,11 @@ ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
if (!parent)
return -EIO;
- if (i == vsil)
+ /* Do not modify the VSI handle for already existing VSI nodes,
+ * (if no new VSI node was added to the tree).
+ * Assign the VSI handle only to newly added VSI nodes.
+ */
+ if (i == vsil && num_added)
parent->vsi_handle = vsi_handle;
}
@@ -1813,6 +1851,41 @@ ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
}
/**
+ * ice_sched_recalc_vsi_support_nodes - recalculate VSI support nodes count
+ * @hw: pointer to the HW struct
+ * @vsi_node: pointer to the leftmost VSI node that needs to be extended
+ * @new_numqs: new number of queues that has to be handled by the VSI
+ * @new_num_nodes: pointer to nodes count table to modify the VSI layer entry
+ *
+ * This function recalculates the number of supported nodes that need to
+ * be added after adding more Tx queues for a given VSI.
+ * The number of new VSI support nodes that shall be added will be saved
+ * to the @new_num_nodes table for the VSI layer.
+ */
+static void
+ice_sched_recalc_vsi_support_nodes(struct ice_hw *hw,
+ struct ice_sched_node *vsi_node,
+ unsigned int new_numqs, u16 *new_num_nodes)
+{
+ u32 vsi_nodes_cnt = 1;
+ u32 max_queue_cnt = 1;
+ u32 qgl, vsil;
+
+ qgl = ice_sched_get_qgrp_layer(hw);
+ vsil = ice_sched_get_vsi_layer(hw);
+
+ for (u32 i = vsil; i <= qgl; i++)
+ max_queue_cnt *= hw->max_children[i];
+
+ while ((vsi_node = ice_sched_find_next_vsi_node(vsi_node)) != NULL)
+ vsi_nodes_cnt++;
+
+ if (new_numqs > (max_queue_cnt * vsi_nodes_cnt))
+ new_num_nodes[vsil] = DIV_ROUND_UP(new_numqs, max_queue_cnt) -
+ vsi_nodes_cnt;
+}
+
+/**
* ice_sched_update_vsi_child_nodes - update VSI child nodes
* @pi: port information structure
* @vsi_handle: software VSI handle
@@ -1863,15 +1936,25 @@ ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
return status;
}
- if (new_numqs)
- ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
- /* Keep the max number of queue configuration all the time. Update the
- * tree only if number of queues > previous number of queues. This may
+ ice_sched_recalc_vsi_support_nodes(hw, vsi_node,
+ new_numqs, new_num_nodes);
+ ice_sched_calc_vsi_child_nodes(hw, new_numqs - prev_numqs,
+ new_num_nodes);
+
+ /* Never decrease the number of queues in the tree. Update the tree
+ * only if number of queues > previous number of queues. This may
* leave some extra nodes in the tree if number of queues < previous
* number but that wouldn't harm anything. Removing those extra nodes
* may complicate the code if those nodes are part of SRL or
* individually rate limited.
+ * Also, add the required VSI support nodes if the existing ones cannot
+ * handle the requested new number of queues.
*/
+ status = ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
+ new_num_nodes);
+ if (status)
+ return status;
+
status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
new_num_nodes, owner);
if (status)
@@ -2013,6 +2096,58 @@ static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node)
}
/**
+ * ice_sched_rm_vsi_subtree - remove all nodes assigned to a given VSI
+ * @pi: port information structure
+ * @vsi_node: pointer to the leftmost node of the VSI to be removed
+ * @owner: LAN or RDMA
+ * @tc: TC number
+ *
+ * Return: Zero in case of success, or -EBUSY if the VSI has leaf nodes in TC.
+ *
+ * This function removes all the VSI support nodes associated with a given VSI
+ * and its LAN or RDMA children nodes from the scheduler tree.
+ */
+static int
+ice_sched_rm_vsi_subtree(struct ice_port_info *pi,
+ struct ice_sched_node *vsi_node, u8 owner, u8 tc)
+{
+ u16 vsi_handle = vsi_node->vsi_handle;
+ bool all_vsi_nodes_removed = true;
+ int j = 0;
+
+ while (vsi_node) {
+ struct ice_sched_node *next_vsi_node;
+
+ if (ice_sched_is_leaf_node_present(vsi_node)) {
+ ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", tc);
+ return -EBUSY;
+ }
+ while (j < vsi_node->num_children) {
+ if (vsi_node->children[j]->owner == owner)
+ ice_free_sched_node(pi, vsi_node->children[j]);
+ else
+ j++;
+ }
+
+ next_vsi_node = ice_sched_find_next_vsi_node(vsi_node);
+
+ /* remove the VSI if it has no children */
+ if (!vsi_node->num_children)
+ ice_free_sched_node(pi, vsi_node);
+ else
+ all_vsi_nodes_removed = false;
+
+ vsi_node = next_vsi_node;
+ }
+
+ /* clean up aggregator related VSI info if any */
+ if (all_vsi_nodes_removed)
+ ice_sched_rm_agg_vsi_info(pi, vsi_handle);
+
+ return 0;
+}
+
+/**
* ice_sched_rm_vsi_cfg - remove the VSI and its children nodes
* @pi: port information structure
* @vsi_handle: software VSI handle
@@ -2038,7 +2173,6 @@ ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
ice_for_each_traffic_class(i) {
struct ice_sched_node *vsi_node, *tc_node;
- u8 j = 0;
tc_node = ice_sched_get_tc_node(pi, i);
if (!tc_node)
@@ -2048,31 +2182,12 @@ ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
if (!vsi_node)
continue;
- if (ice_sched_is_leaf_node_present(vsi_node)) {
- ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i);
- status = -EBUSY;
+ status = ice_sched_rm_vsi_subtree(pi, vsi_node, owner, i);
+ if (status)
goto exit_sched_rm_vsi_cfg;
- }
- while (j < vsi_node->num_children) {
- if (vsi_node->children[j]->owner == owner) {
- ice_free_sched_node(pi, vsi_node->children[j]);
- /* reset the counter again since the num
- * children will be updated after node removal
- */
- j = 0;
- } else {
- j++;
- }
- }
- /* remove the VSI if it has no children */
- if (!vsi_node->num_children) {
- ice_free_sched_node(pi, vsi_node);
- vsi_ctx->sched.vsi_node[i] = NULL;
+ vsi_ctx->sched.vsi_node[i] = NULL;
- /* clean up aggregator related VSI info if any */
- ice_sched_rm_agg_vsi_info(pi, vsi_handle);
- }
if (owner == ICE_SCHED_NODE_OWNER_LAN)
vsi_ctx->sched.max_lanq[i] = 0;
else
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index bab12ecb2df5..4eb20ec2accb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1801,11 +1801,19 @@ void idpf_vc_event_task(struct work_struct *work)
if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
return;
- if (test_bit(IDPF_HR_FUNC_RESET, adapter->flags) ||
- test_bit(IDPF_HR_DRV_LOAD, adapter->flags)) {
- set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
- idpf_init_hard_reset(adapter);
- }
+ if (test_bit(IDPF_HR_FUNC_RESET, adapter->flags))
+ goto func_reset;
+
+ if (test_bit(IDPF_HR_DRV_LOAD, adapter->flags))
+ goto drv_load;
+
+ return;
+
+func_reset:
+ idpf_vc_xn_shutdown(adapter->vcxn_mngr);
+drv_load:
+ set_bit(IDPF_HR_RESET_IN_PROG, adapter->flags);
+ idpf_init_hard_reset(adapter);
}
/**
diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
index 2e356dd10812..993c354aa27a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -362,17 +362,18 @@ netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb,
{
struct idpf_tx_offload_params offload = { };
struct idpf_tx_buf *first;
+ int csum, tso, needed;
unsigned int count;
__be16 protocol;
- int csum, tso;
count = idpf_tx_desc_count_required(tx_q, skb);
if (unlikely(!count))
return idpf_tx_drop_skb(tx_q, skb);
- if (idpf_tx_maybe_stop_common(tx_q,
- count + IDPF_TX_DESCS_PER_CACHE_LINE +
- IDPF_TX_DESCS_FOR_CTX)) {
+ needed = count + IDPF_TX_DESCS_PER_CACHE_LINE + IDPF_TX_DESCS_FOR_CTX;
+ if (!netif_subqueue_maybe_stop(tx_q->netdev, tx_q->idx,
+ IDPF_DESC_UNUSED(tx_q),
+ needed, needed)) {
idpf_tx_buf_hw_update(tx_q, tx_q->next_to_use, false);
u64_stats_update_begin(&tx_q->stats_sync);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 631679cdaa6f..5cf440e09d0a 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2184,6 +2184,19 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc,
desc->flow.qw1.compl_tag = cpu_to_le16(params->compl_tag);
}
+/* Global conditions to tell whether the txq (and related resources)
+ * has room to allow the use of "size" descriptors.
+ */
+static int idpf_txq_has_room(struct idpf_tx_queue *tx_q, u32 size)
+{
+ if (IDPF_DESC_UNUSED(tx_q) < size ||
+ IDPF_TX_COMPLQ_PENDING(tx_q->txq_grp) >
+ IDPF_TX_COMPLQ_OVERFLOW_THRESH(tx_q->txq_grp->complq) ||
+ IDPF_TX_BUF_RSV_LOW(tx_q))
+ return 0;
+ return 1;
+}
+
/**
* idpf_tx_maybe_stop_splitq - 1st level check for Tx splitq stop conditions
* @tx_q: the queue to be checked
@@ -2194,29 +2207,11 @@ void idpf_tx_splitq_build_flow_desc(union idpf_tx_flex_desc *desc,
static int idpf_tx_maybe_stop_splitq(struct idpf_tx_queue *tx_q,
unsigned int descs_needed)
{
- if (idpf_tx_maybe_stop_common(tx_q, descs_needed))
- goto out;
-
- /* If there are too many outstanding completions expected on the
- * completion queue, stop the TX queue to give the device some time to
- * catch up
- */
- if (unlikely(IDPF_TX_COMPLQ_PENDING(tx_q->txq_grp) >
- IDPF_TX_COMPLQ_OVERFLOW_THRESH(tx_q->txq_grp->complq)))
- goto splitq_stop;
-
- /* Also check for available book keeping buffers; if we are low, stop
- * the queue to wait for more completions
- */
- if (unlikely(IDPF_TX_BUF_RSV_LOW(tx_q)))
- goto splitq_stop;
-
- return 0;
-
-splitq_stop:
- netif_stop_subqueue(tx_q->netdev, tx_q->idx);
+ if (netif_subqueue_maybe_stop(tx_q->netdev, tx_q->idx,
+ idpf_txq_has_room(tx_q, descs_needed),
+ 1, 1))
+ return 0;
-out:
u64_stats_update_begin(&tx_q->stats_sync);
u64_stats_inc(&tx_q->q_stats.q_busy);
u64_stats_update_end(&tx_q->stats_sync);
@@ -2242,12 +2237,6 @@ void idpf_tx_buf_hw_update(struct idpf_tx_queue *tx_q, u32 val,
nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx);
tx_q->next_to_use = val;
- if (idpf_tx_maybe_stop_common(tx_q, IDPF_TX_DESC_NEEDED)) {
- u64_stats_update_begin(&tx_q->stats_sync);
- u64_stats_inc(&tx_q->q_stats.q_busy);
- u64_stats_update_end(&tx_q->stats_sync);
- }
-
/* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index c779fe71df99..36a0f828a6f8 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -1049,12 +1049,4 @@ bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue *rxq,
u16 cleaned_count);
int idpf_tso(struct sk_buff *skb, struct idpf_tx_offload_params *off);
-static inline bool idpf_tx_maybe_stop_common(struct idpf_tx_queue *tx_q,
- u32 needed)
-{
- return !netif_subqueue_maybe_stop(tx_q->netdev, tx_q->idx,
- IDPF_DESC_UNUSED(tx_q),
- needed, needed);
-}
-
#endif /* !_IDPF_TXRX_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 07a9f5ae34fd..24febaaa8fbb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -347,7 +347,7 @@ static void idpf_vc_xn_init(struct idpf_vc_xn_manager *vcxn_mngr)
* All waiting threads will be woken-up and their transaction aborted. Further
* operations on that object will fail.
*/
-static void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
+void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr)
{
int i;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 3522c1238ea2..77578206bada 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -150,5 +150,6 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
int idpf_send_get_set_rss_key_msg(struct idpf_vport *vport, bool get);
int idpf_send_get_set_rss_lut_msg(struct idpf_vport *vport, bool get);
+void idpf_vc_xn_shutdown(struct idpf_vc_xn_manager *vcxn_mngr);
#endif /* _IDPF_VIRTCHNL_H_ */
diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c
index b175119a6a7d..b83886a41121 100644
--- a/drivers/net/ethernet/mediatek/mtk_star_emac.c
+++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c
@@ -1463,6 +1463,8 @@ static __maybe_unused int mtk_star_suspend(struct device *dev)
if (netif_running(ndev))
mtk_star_disable(ndev);
+ netif_device_detach(ndev);
+
clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
return 0;
@@ -1487,6 +1489,8 @@ static __maybe_unused int mtk_star_resume(struct device *dev)
clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
}
+ netif_device_attach(ndev);
+
return ret;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index cd754cd76bde..d73a2044dc26 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -249,7 +249,7 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
static u32 freq_to_shift(u16 freq)
{
u32 freq_khz = freq * 1000;
- u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
+ u64 max_val_cycles = freq_khz * 1000ULL * MLX4_EN_WRAP_AROUND_SEC;
u64 max_val_cycles_rounded = 1ULL << fls64(max_val_cycles - 1);
/* calculate max possible multiplier in order to fit in 64bit */
u64 max_mul = div64_u64(ULLONG_MAX, max_val_cycles_rounded);
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
index 427bdc0e4908..7001584f1b7a 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c
@@ -879,6 +879,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
lan966x_vlan_port_set_vlan_aware(port, 0);
lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);
lan966x_vlan_port_apply(port);
+ lan966x_vlan_port_rew_host(port);
return 0;
}
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
index 1f9df67f0504..4f75f0688369 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h
@@ -497,6 +497,7 @@ void lan966x_vlan_port_apply(struct lan966x_port *port);
bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid);
void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
bool vlan_aware);
+void lan966x_vlan_port_rew_host(struct lan966x_port *port);
int lan966x_vlan_port_set_vid(struct lan966x_port *port,
u16 vid,
bool pvid,
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c b/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c
index 1c88120eb291..bcb4db76b75c 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c
@@ -297,6 +297,7 @@ static void lan966x_port_bridge_leave(struct lan966x_port *port,
lan966x_vlan_port_set_vlan_aware(port, false);
lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);
lan966x_vlan_port_apply(port);
+ lan966x_vlan_port_rew_host(port);
}
int lan966x_port_changeupper(struct net_device *dev,
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c
index fa34a739c748..7da22520724c 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vlan.c
@@ -149,6 +149,27 @@ void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
port->vlan_aware = vlan_aware;
}
+/* When the interface is in host mode, the interface should not be vlan aware
+ * but it should insert all the tags that it gets from the network stack.
+ * The tags are not in the data of the frame but actually in the skb and the ifh
+ * is configured already to get this tag. So what we need to do is to update the
+ * rewriter to insert the vlan tag for all frames which have a vlan tag
+ * different than 0.
+ */
+void lan966x_vlan_port_rew_host(struct lan966x_port *port)
+{
+ struct lan966x *lan966x = port->lan966x;
+ u32 val;
+
+ /* Tag all frames except when VID=0*/
+ val = REW_TAG_CFG_TAG_CFG_SET(2);
+
+ /* Update only some bits in the register */
+ lan_rmw(val,
+ REW_TAG_CFG_TAG_CFG,
+ lan966x, REW_TAG_CFG(port->chip_port));
+}
+
void lan966x_vlan_port_apply(struct lan966x_port *port)
{
struct lan966x *lan966x = port->lan966x;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
index c9693f77e1f6..ac6f2e3a3fcd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
@@ -32,6 +32,11 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
int i, ret = 0;
u32 ctrl;
+ if (!ptp_rate) {
+ netdev_warn(priv->dev, "Invalid PTP rate");
+ return -EINVAL;
+ }
+
ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
ret |= est_write(est_addr, EST_TER, cfg->ter, false);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 085c09039af4..1369fa70bc58 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -805,6 +805,11 @@ int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags)
if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
return -EOPNOTSUPP;
+ if (!priv->plat->clk_ptp_rate) {
+ netdev_err(priv->dev, "Invalid PTP clock rate");
+ return -EINVAL;
+ }
+
stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
priv->systime_flags = systime_flags;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 43c869f64c39..b80c1efdb323 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -430,6 +430,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
struct device_node *np = pdev->dev.of_node;
struct plat_stmmacenet_data *plat;
struct stmmac_dma_cfg *dma_cfg;
+ static int bus_id = -ENODEV;
int phy_mode;
void *ret;
int rc;
@@ -465,8 +466,14 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
of_property_read_u32(np, "max-speed", &plat->max_speed);
plat->bus_id = of_alias_get_id(np, "ethernet");
- if (plat->bus_id < 0)
- plat->bus_id = 0;
+ if (plat->bus_id < 0) {
+ if (bus_id < 0)
+ bus_id = of_alias_get_highest_id("ethernet");
+ /* No ethernet alias found, init at -1 so first bus_id is 0 */
+ if (bus_id < 0)
+ bus_id = -1;
+ plat->bus_id = ++bus_id;
+ }
/* Default to phy auto-detection */
plat->phy_addr = -1;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index 429b2d357813..3767ba495e78 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -317,7 +317,7 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
/* Calculate the clock domain crossing (CDC) error if necessary */
priv->plat->cdc_error_adj = 0;
- if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
+ if (priv->plat->has_gmac4)
priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
/* Update the ptp clock parameters based on feature discovery, when
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index e8241e998aa9..7159baa0155c 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -28,6 +28,14 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
spin_lock(&prueth->stats_lock);
for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
+ /* In MII mode TX lines are swapped inside ICSSG, so read Tx stats
+ * from slice1 for port0 and slice0 for port1 to get accurate Tx
+ * stats for a given port
+ */
+ if (emac->phy_if == PHY_INTERFACE_MODE_MII &&
+ icssg_all_miig_stats[i].offset >= ICSSG_TX_PACKET_OFFSET &&
+ icssg_all_miig_stats[i].offset <= ICSSG_TX_BYTE_OFFSET)
+ base = stats_base[slice ^ 1];
regmap_read(prueth->miig_rt,
base + icssg_all_miig_stats[i].offset,
&val);
diff --git a/drivers/net/hyperv/netvsc_bpf.c b/drivers/net/hyperv/netvsc_bpf.c
index e01c5997a551..1dd3755d9e6d 100644
--- a/drivers/net/hyperv/netvsc_bpf.c
+++ b/drivers/net/hyperv/netvsc_bpf.c
@@ -183,7 +183,7 @@ int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog)
xdp.command = XDP_SETUP_PROG;
xdp.prog = prog;
- ret = dev_xdp_propagate(vf_netdev, &xdp);
+ ret = netif_xdp_propagate(vf_netdev, &xdp);
if (ret && prog)
bpf_prog_put(prog);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 14a0d04e21ae..c41a025c66f0 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -2462,8 +2462,6 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
- netvsc_vf_setxdp(vf_netdev, NULL);
-
reinit_completion(&net_device_ctx->vf_add);
netdev_rx_handler_unregister(vf_netdev);
netdev_upper_dev_unlink(vf_netdev, ndev);
@@ -2631,7 +2629,9 @@ static int netvsc_probe(struct hv_device *dev,
continue;
netvsc_prepare_bonding(vf_netdev);
+ netdev_lock_ops(vf_netdev);
netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE);
+ netdev_unlock_ops(vf_netdev);
__netvsc_vf_setup(net, vf_netdev);
break;
}
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 10d8afecec55..ebf1e849506b 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -134,7 +134,7 @@ void ovpn_decrypt_post(void *data, int ret)
rcu_read_lock();
sock = rcu_dereference(peer->sock);
- if (sock && sock->sock->sk->sk_protocol == IPPROTO_UDP)
+ if (sock && sock->sk->sk_protocol == IPPROTO_UDP)
/* check if this peer changed local or remote endpoint */
ovpn_peer_endpoints_update(peer, skb);
rcu_read_unlock();
@@ -270,12 +270,12 @@ void ovpn_encrypt_post(void *data, int ret)
if (unlikely(!sock))
goto err_unlock;
- switch (sock->sock->sk->sk_protocol) {
+ switch (sock->sk->sk_protocol) {
case IPPROTO_UDP:
- ovpn_udp_send_skb(peer, sock->sock, skb);
+ ovpn_udp_send_skb(peer, sock->sk, skb);
break;
case IPPROTO_TCP:
- ovpn_tcp_send_skb(peer, sock->sock, skb);
+ ovpn_tcp_send_skb(peer, sock->sk, skb);
break;
default:
/* no transport configured yet */
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index bea03913bfb1..a4ec53def46e 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -501,7 +501,7 @@ int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info)
/* when using a TCP socket the remote IP is not expected */
rcu_read_lock();
sock = rcu_dereference(peer->sock);
- if (sock && sock->sock->sk->sk_protocol == IPPROTO_TCP &&
+ if (sock && sock->sk->sk_protocol == IPPROTO_TCP &&
(attrs[OVPN_A_PEER_REMOTE_IPV4] ||
attrs[OVPN_A_PEER_REMOTE_IPV6])) {
rcu_read_unlock();
@@ -559,14 +559,14 @@ static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info,
goto err_unlock;
}
- if (!net_eq(genl_info_net(info), sock_net(sock->sock->sk))) {
+ if (!net_eq(genl_info_net(info), sock_net(sock->sk))) {
id = peernet2id_alloc(genl_info_net(info),
- sock_net(sock->sock->sk),
+ sock_net(sock->sk),
GFP_ATOMIC);
if (nla_put_s32(skb, OVPN_A_PEER_SOCKET_NETNSID, id))
goto err_unlock;
}
- local_port = inet_sk(sock->sock->sk)->inet_sport;
+ local_port = inet_sk(sock->sk)->inet_sport;
rcu_read_unlock();
if (nla_put_u32(skb, OVPN_A_PEER_ID, peer->id))
@@ -1153,8 +1153,8 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
ret = -EINVAL;
goto err_unlock;
}
- genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
- msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
+ genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
+ OVPN_NLGRP_PEERS, GFP_ATOMIC);
rcu_read_unlock();
return 0;
@@ -1218,8 +1218,8 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
ret = -EINVAL;
goto err_unlock;
}
- genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sock->sk),
- msg, 0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
+ genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
+ OVPN_NLGRP_PEERS, GFP_ATOMIC);
rcu_read_unlock();
return 0;
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index a1fd27b9c038..4bfcab0c8652 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -1145,7 +1145,7 @@ static void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk,
if (sk) {
ovpn_sock = rcu_access_pointer(peer->sock);
- if (!ovpn_sock || ovpn_sock->sock->sk != sk) {
+ if (!ovpn_sock || ovpn_sock->sk != sk) {
spin_unlock_bh(&ovpn->lock);
ovpn_peer_put(peer);
return;
@@ -1175,7 +1175,7 @@ static void ovpn_peers_release_mp(struct ovpn_priv *ovpn, struct sock *sk,
if (sk) {
rcu_read_lock();
ovpn_sock = rcu_dereference(peer->sock);
- remove = ovpn_sock && ovpn_sock->sock->sk == sk;
+ remove = ovpn_sock && ovpn_sock->sk == sk;
rcu_read_unlock();
}
diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c
index a83cbab72591..9750871ab65c 100644
--- a/drivers/net/ovpn/socket.c
+++ b/drivers/net/ovpn/socket.c
@@ -24,9 +24,9 @@ static void ovpn_socket_release_kref(struct kref *kref)
struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
refcount);
- if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
+ if (sock->sk->sk_protocol == IPPROTO_UDP)
ovpn_udp_socket_detach(sock);
- else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
+ else if (sock->sk->sk_protocol == IPPROTO_TCP)
ovpn_tcp_socket_detach(sock);
}
@@ -75,14 +75,6 @@ void ovpn_socket_release(struct ovpn_peer *peer)
if (!sock)
return;
- /* sanity check: we should not end up here if the socket
- * was already closed
- */
- if (!sock->sock->sk) {
- DEBUG_NET_WARN_ON_ONCE(1);
- return;
- }
-
/* Drop the reference while holding the sock lock to avoid
* concurrent ovpn_socket_new call to mess up with a partially
* detached socket.
@@ -90,22 +82,24 @@ void ovpn_socket_release(struct ovpn_peer *peer)
* Holding the lock ensures that a socket with refcnt 0 is fully
* detached before it can be picked by a concurrent reader.
*/
- lock_sock(sock->sock->sk);
+ lock_sock(sock->sk);
released = ovpn_socket_put(peer, sock);
- release_sock(sock->sock->sk);
+ release_sock(sock->sk);
/* align all readers with sk_user_data being NULL */
synchronize_rcu();
/* following cleanup should happen with lock released */
if (released) {
- if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
+ if (sock->sk->sk_protocol == IPPROTO_UDP) {
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
- } else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) {
+ } else if (sock->sk->sk_protocol == IPPROTO_TCP) {
/* wait for TCP jobs to terminate */
ovpn_tcp_socket_wait_finish(sock);
ovpn_peer_put(sock->peer);
}
+ /* drop reference acquired in ovpn_socket_new() */
+ sock_put(sock->sk);
/* we can call plain kfree() because we already waited one RCU
* period due to synchronize_rcu()
*/
@@ -118,12 +112,14 @@ static bool ovpn_socket_hold(struct ovpn_socket *sock)
return kref_get_unless_zero(&sock->refcount);
}
-static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer)
+static int ovpn_socket_attach(struct ovpn_socket *ovpn_sock,
+ struct socket *sock,
+ struct ovpn_peer *peer)
{
- if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
- return ovpn_udp_socket_attach(sock, peer->ovpn);
- else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
- return ovpn_tcp_socket_attach(sock, peer);
+ if (sock->sk->sk_protocol == IPPROTO_UDP)
+ return ovpn_udp_socket_attach(ovpn_sock, sock, peer->ovpn);
+ else if (sock->sk->sk_protocol == IPPROTO_TCP)
+ return ovpn_tcp_socket_attach(ovpn_sock, peer);
return -EOPNOTSUPP;
}
@@ -138,14 +134,15 @@ static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer)
struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
{
struct ovpn_socket *ovpn_sock;
+ struct sock *sk = sock->sk;
int ret;
- lock_sock(sock->sk);
+ lock_sock(sk);
/* a TCP socket can only be owned by a single peer, therefore there
* can't be any other user
*/
- if (sock->sk->sk_protocol == IPPROTO_TCP && sock->sk->sk_user_data) {
+ if (sk->sk_protocol == IPPROTO_TCP && sk->sk_user_data) {
ovpn_sock = ERR_PTR(-EBUSY);
goto sock_release;
}
@@ -153,8 +150,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
/* a UDP socket can be shared across multiple peers, but we must make
* sure it is not owned by something else
*/
- if (sock->sk->sk_protocol == IPPROTO_UDP) {
- u8 type = READ_ONCE(udp_sk(sock->sk)->encap_type);
+ if (sk->sk_protocol == IPPROTO_UDP) {
+ u8 type = READ_ONCE(udp_sk(sk)->encap_type);
/* socket owned by other encapsulation module */
if (type && type != UDP_ENCAP_OVPNINUDP) {
@@ -163,7 +160,7 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
}
rcu_read_lock();
- ovpn_sock = rcu_dereference_sk_user_data(sock->sk);
+ ovpn_sock = rcu_dereference_sk_user_data(sk);
if (ovpn_sock) {
/* socket owned by another ovpn instance, we can't use it */
if (ovpn_sock->ovpn != peer->ovpn) {
@@ -200,11 +197,22 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
goto sock_release;
}
- ovpn_sock->sock = sock;
+ ovpn_sock->sk = sk;
kref_init(&ovpn_sock->refcount);
- ret = ovpn_socket_attach(ovpn_sock, peer);
+ /* the newly created ovpn_socket is holding reference to sk,
+ * therefore we increase its refcounter.
+ *
+ * This ovpn_socket instance is referenced by all peers
+ * using the same socket.
+ *
+ * ovpn_socket_release() will take care of dropping the reference.
+ */
+ sock_hold(sk);
+
+ ret = ovpn_socket_attach(ovpn_sock, sock, peer);
if (ret < 0) {
+ sock_put(sk);
kfree(ovpn_sock);
ovpn_sock = ERR_PTR(ret);
goto sock_release;
@@ -213,11 +221,11 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
/* TCP sockets are per-peer, therefore they are linked to their unique
* peer
*/
- if (sock->sk->sk_protocol == IPPROTO_TCP) {
+ if (sk->sk_protocol == IPPROTO_TCP) {
INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
ovpn_sock->peer = peer;
ovpn_peer_hold(peer);
- } else if (sock->sk->sk_protocol == IPPROTO_UDP) {
+ } else if (sk->sk_protocol == IPPROTO_UDP) {
/* in UDP we only link the ovpn instance since the socket is
* shared among multiple peers
*/
@@ -226,8 +234,8 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
GFP_KERNEL);
}
- rcu_assign_sk_user_data(sock->sk, ovpn_sock);
+ rcu_assign_sk_user_data(sk, ovpn_sock);
sock_release:
- release_sock(sock->sk);
+ release_sock(sk);
return ovpn_sock;
}
diff --git a/drivers/net/ovpn/socket.h b/drivers/net/ovpn/socket.h
index 00d856b1a5d8..4afcec71040d 100644
--- a/drivers/net/ovpn/socket.h
+++ b/drivers/net/ovpn/socket.h
@@ -22,7 +22,7 @@ struct ovpn_peer;
* @ovpn: ovpn instance owning this socket (UDP only)
* @dev_tracker: reference tracker for associated dev (UDP only)
* @peer: unique peer transmitting over this socket (TCP only)
- * @sock: the low level sock object
+ * @sk: the low level sock object
* @refcount: amount of contexts currently referencing this object
* @work: member used to schedule release routine (it may block)
* @tcp_tx_work: work for deferring outgoing packet processing (TCP only)
@@ -36,7 +36,7 @@ struct ovpn_socket {
struct ovpn_peer *peer;
};
- struct socket *sock;
+ struct sock *sk;
struct kref refcount;
struct work_struct work;
struct work_struct tcp_tx_work;
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c
index 7c42d84987ad..289f62c5d2c7 100644
--- a/drivers/net/ovpn/tcp.c
+++ b/drivers/net/ovpn/tcp.c
@@ -124,14 +124,18 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb)
* this peer, therefore ovpn_peer_hold() is not expected to fail
*/
if (WARN_ON(!ovpn_peer_hold(peer)))
- goto err;
+ goto err_nopeer;
ovpn_recv(peer, skb);
return;
err:
+ /* take reference for deferred peer deletion. should never fail */
+ if (WARN_ON(!ovpn_peer_hold(peer)))
+ goto err_nopeer;
+ schedule_work(&peer->tcp.defer_del_work);
dev_dstats_rx_dropped(peer->ovpn->dev);
+err_nopeer:
kfree_skb(skb);
- ovpn_peer_del(peer, OVPN_DEL_PEER_REASON_TRANSPORT_ERROR);
}
static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
@@ -186,18 +190,18 @@ out:
void ovpn_tcp_socket_detach(struct ovpn_socket *ovpn_sock)
{
struct ovpn_peer *peer = ovpn_sock->peer;
- struct socket *sock = ovpn_sock->sock;
+ struct sock *sk = ovpn_sock->sk;
strp_stop(&peer->tcp.strp);
skb_queue_purge(&peer->tcp.user_queue);
/* restore CBs that were saved in ovpn_sock_set_tcp_cb() */
- sock->sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready;
- sock->sk->sk_write_space = peer->tcp.sk_cb.sk_write_space;
- sock->sk->sk_prot = peer->tcp.sk_cb.prot;
- sock->sk->sk_socket->ops = peer->tcp.sk_cb.ops;
+ sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready;
+ sk->sk_write_space = peer->tcp.sk_cb.sk_write_space;
+ sk->sk_prot = peer->tcp.sk_cb.prot;
+ sk->sk_socket->ops = peer->tcp.sk_cb.ops;
- rcu_assign_sk_user_data(sock->sk, NULL);
+ rcu_assign_sk_user_data(sk, NULL);
}
void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock)
@@ -283,10 +287,10 @@ void ovpn_tcp_tx_work(struct work_struct *work)
sock = container_of(work, struct ovpn_socket, tcp_tx_work);
- lock_sock(sock->sock->sk);
+ lock_sock(sock->sk);
if (sock->peer)
- ovpn_tcp_send_sock(sock->peer, sock->sock->sk);
- release_sock(sock->sock->sk);
+ ovpn_tcp_send_sock(sock->peer, sock->sk);
+ release_sock(sock->sk);
}
static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk,
@@ -307,15 +311,15 @@ static void ovpn_tcp_send_sock_skb(struct ovpn_peer *peer, struct sock *sk,
ovpn_tcp_send_sock(peer, sk);
}
-void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock,
+void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk,
struct sk_buff *skb)
{
u16 len = skb->len;
*(__be16 *)__skb_push(skb, sizeof(u16)) = htons(len);
- spin_lock_nested(&sock->sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING);
- if (sock_owned_by_user(sock->sk)) {
+ spin_lock_nested(&sk->sk_lock.slock, OVPN_TCP_DEPTH_NESTING);
+ if (sock_owned_by_user(sk)) {
if (skb_queue_len(&peer->tcp.out_queue) >=
READ_ONCE(net_hotdata.max_backlog)) {
dev_dstats_tx_dropped(peer->ovpn->dev);
@@ -324,10 +328,10 @@ void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock,
}
__skb_queue_tail(&peer->tcp.out_queue, skb);
} else {
- ovpn_tcp_send_sock_skb(peer, sock->sk, skb);
+ ovpn_tcp_send_sock_skb(peer, sk, skb);
}
unlock:
- spin_unlock(&sock->sk->sk_lock.slock);
+ spin_unlock(&sk->sk_lock.slock);
}
static void ovpn_tcp_release(struct sock *sk)
@@ -474,7 +478,6 @@ static void ovpn_tcp_peer_del_work(struct work_struct *work)
int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
struct ovpn_peer *peer)
{
- struct socket *sock = ovpn_sock->sock;
struct strp_callbacks cb = {
.rcv_msg = ovpn_tcp_rcv,
.parse_msg = ovpn_tcp_parse,
@@ -482,20 +485,20 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
int ret;
/* make sure no pre-existing encapsulation handler exists */
- if (sock->sk->sk_user_data)
+ if (ovpn_sock->sk->sk_user_data)
return -EBUSY;
/* only a fully connected socket is expected. Connection should be
* handled in userspace
*/
- if (sock->sk->sk_state != TCP_ESTABLISHED) {
+ if (ovpn_sock->sk->sk_state != TCP_ESTABLISHED) {
net_err_ratelimited("%s: provided TCP socket is not in ESTABLISHED state: %d\n",
netdev_name(peer->ovpn->dev),
- sock->sk->sk_state);
+ ovpn_sock->sk->sk_state);
return -EINVAL;
}
- ret = strp_init(&peer->tcp.strp, sock->sk, &cb);
+ ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb);
if (ret < 0) {
DEBUG_NET_WARN_ON_ONCE(1);
return ret;
@@ -503,31 +506,31 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work);
- __sk_dst_reset(sock->sk);
+ __sk_dst_reset(ovpn_sock->sk);
skb_queue_head_init(&peer->tcp.user_queue);
skb_queue_head_init(&peer->tcp.out_queue);
/* save current CBs so that they can be restored upon socket release */
- peer->tcp.sk_cb.sk_data_ready = sock->sk->sk_data_ready;
- peer->tcp.sk_cb.sk_write_space = sock->sk->sk_write_space;
- peer->tcp.sk_cb.prot = sock->sk->sk_prot;
- peer->tcp.sk_cb.ops = sock->sk->sk_socket->ops;
+ peer->tcp.sk_cb.sk_data_ready = ovpn_sock->sk->sk_data_ready;
+ peer->tcp.sk_cb.sk_write_space = ovpn_sock->sk->sk_write_space;
+ peer->tcp.sk_cb.prot = ovpn_sock->sk->sk_prot;
+ peer->tcp.sk_cb.ops = ovpn_sock->sk->sk_socket->ops;
/* assign our static CBs and prot/ops */
- sock->sk->sk_data_ready = ovpn_tcp_data_ready;
- sock->sk->sk_write_space = ovpn_tcp_write_space;
+ ovpn_sock->sk->sk_data_ready = ovpn_tcp_data_ready;
+ ovpn_sock->sk->sk_write_space = ovpn_tcp_write_space;
- if (sock->sk->sk_family == AF_INET) {
- sock->sk->sk_prot = &ovpn_tcp_prot;
- sock->sk->sk_socket->ops = &ovpn_tcp_ops;
+ if (ovpn_sock->sk->sk_family == AF_INET) {
+ ovpn_sock->sk->sk_prot = &ovpn_tcp_prot;
+ ovpn_sock->sk->sk_socket->ops = &ovpn_tcp_ops;
} else {
- sock->sk->sk_prot = &ovpn_tcp6_prot;
- sock->sk->sk_socket->ops = &ovpn_tcp6_ops;
+ ovpn_sock->sk->sk_prot = &ovpn_tcp6_prot;
+ ovpn_sock->sk->sk_socket->ops = &ovpn_tcp6_ops;
}
/* avoid using task_frag */
- sock->sk->sk_allocation = GFP_ATOMIC;
- sock->sk->sk_use_task_frag = false;
+ ovpn_sock->sk->sk_allocation = GFP_ATOMIC;
+ ovpn_sock->sk->sk_use_task_frag = false;
/* enqueue the RX worker */
strp_check_rcv(&peer->tcp.strp);
diff --git a/drivers/net/ovpn/tcp.h b/drivers/net/ovpn/tcp.h
index 10aefa834cf3..a3aa3570ae5e 100644
--- a/drivers/net/ovpn/tcp.h
+++ b/drivers/net/ovpn/tcp.h
@@ -30,7 +30,8 @@ void ovpn_tcp_socket_wait_finish(struct ovpn_socket *sock);
* Required by the OpenVPN protocol in order to extract packets from
* the TCP stream on the receiver side.
*/
-void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct socket *sock, struct sk_buff *skb);
+void ovpn_tcp_send_skb(struct ovpn_peer *peer, struct sock *sk,
+ struct sk_buff *skb);
void ovpn_tcp_tx_work(struct work_struct *work);
#endif /* _NET_OVPN_TCP_H_ */
diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index aef8c0406ec9..bff00946eae2 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -43,7 +43,7 @@ static struct ovpn_socket *ovpn_socket_from_udp_sock(struct sock *sk)
return NULL;
/* make sure that sk matches our stored transport socket */
- if (unlikely(!ovpn_sock->sock || sk != ovpn_sock->sock->sk))
+ if (unlikely(!ovpn_sock->sk || sk != ovpn_sock->sk))
return NULL;
return ovpn_sock;
@@ -335,32 +335,22 @@ out:
/**
* ovpn_udp_send_skb - prepare skb and send it over via UDP
* @peer: the destination peer
- * @sock: the RCU protected peer socket
+ * @sk: peer socket
* @skb: the packet to send
*/
-void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock,
+void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk,
struct sk_buff *skb)
{
- int ret = -1;
+ int ret;
skb->dev = peer->ovpn->dev;
/* no checksum performed at this layer */
skb->ip_summed = CHECKSUM_NONE;
- /* get socket info */
- if (unlikely(!sock)) {
- net_warn_ratelimited("%s: no sock for remote peer %u\n",
- netdev_name(peer->ovpn->dev), peer->id);
- goto out;
- }
-
/* crypto layer -> transport (UDP) */
- ret = ovpn_udp_output(peer, &peer->dst_cache, sock->sk, skb);
-out:
- if (unlikely(ret < 0)) {
+ ret = ovpn_udp_output(peer, &peer->dst_cache, sk, skb);
+ if (unlikely(ret < 0))
kfree_skb(skb);
- return;
- }
}
static void ovpn_udp_encap_destroy(struct sock *sk)
@@ -383,6 +373,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk)
/**
* ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn
* @ovpn_sock: socket to configure
+ * @sock: the socket container to be passed to setup_udp_tunnel_sock()
* @ovpn: the openvp instance to link
*
* After invoking this function, the sock will be controlled by ovpn so that
@@ -390,7 +381,7 @@ static void ovpn_udp_encap_destroy(struct sock *sk)
*
* Return: 0 on success or a negative error code otherwise
*/
-int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
+int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
struct ovpn_priv *ovpn)
{
struct udp_tunnel_sock_cfg cfg = {
@@ -398,17 +389,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
.encap_rcv = ovpn_udp_encap_recv,
.encap_destroy = ovpn_udp_encap_destroy,
};
- struct socket *sock = ovpn_sock->sock;
struct ovpn_socket *old_data;
int ret;
/* make sure no pre-existing encapsulation handler exists */
rcu_read_lock();
- old_data = rcu_dereference_sk_user_data(sock->sk);
+ old_data = rcu_dereference_sk_user_data(ovpn_sock->sk);
if (!old_data) {
/* socket is currently unused - we can take it */
rcu_read_unlock();
- setup_udp_tunnel_sock(sock_net(sock->sk), sock, &cfg);
+ setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock, &cfg);
return 0;
}
@@ -421,7 +411,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
* Unlikely TCP, a single UDP socket can be used to talk to many remote
* hosts and therefore openvpn instantiates one only for all its peers
*/
- if ((READ_ONCE(udp_sk(sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) &&
+ if ((READ_ONCE(udp_sk(ovpn_sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) &&
old_data->ovpn == ovpn) {
netdev_dbg(ovpn->dev,
"provided socket already owned by this interface\n");
@@ -442,8 +432,16 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
*/
void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock)
{
- struct udp_tunnel_sock_cfg cfg = { };
+ struct sock *sk = ovpn_sock->sk;
+
+ /* Re-enable multicast loopback */
+ inet_set_bit(MC_LOOP, sk);
+ /* Disable CHECKSUM_UNNECESSARY to CHECKSUM_COMPLETE conversion */
+ inet_dec_convert_csum(sk);
+
+ WRITE_ONCE(udp_sk(sk)->encap_type, 0);
+ WRITE_ONCE(udp_sk(sk)->encap_rcv, NULL);
+ WRITE_ONCE(udp_sk(sk)->encap_destroy, NULL);
- setup_udp_tunnel_sock(sock_net(ovpn_sock->sock->sk), ovpn_sock->sock,
- &cfg);
+ rcu_assign_sk_user_data(sk, NULL);
}
diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h
index 9994eb6e0428..fe26fbe25c5a 100644
--- a/drivers/net/ovpn/udp.h
+++ b/drivers/net/ovpn/udp.h
@@ -15,11 +15,11 @@ struct ovpn_peer;
struct ovpn_priv;
struct socket;
-int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock,
+int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
struct ovpn_priv *ovpn);
void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock);
-void ovpn_udp_send_skb(struct ovpn_peer *peer, struct socket *sock,
+void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sock *sk,
struct sk_buff *skb);
#endif /* _NET_OVPN_UDP_H_ */
diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c
index 453a2cf82753..9201ee10a13f 100644
--- a/drivers/net/usb/aqc111.c
+++ b/drivers/net/usb/aqc111.c
@@ -31,11 +31,11 @@ static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
USB_RECIP_DEVICE, value, index, data, size);
if (unlikely(ret < size)) {
- ret = ret < 0 ? ret : -ENODATA;
-
netdev_warn(dev->net,
"Failed to read(0x%x) reg index 0x%04x: %d\n",
cmd, index, ret);
+
+ ret = ret < 0 ? ret : -ENODATA;
}
return ret;
@@ -50,11 +50,11 @@ static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value,
USB_RECIP_DEVICE, value, index, data, size);
if (unlikely(ret < size)) {
- ret = ret < 0 ? ret : -ENODATA;
-
netdev_warn(dev->net,
"Failed to read(0x%x) reg index 0x%04x: %d\n",
cmd, index, ret);
+
+ ret = ret < 0 ? ret : -ENODATA;
}
return ret;
diff --git a/drivers/net/usb/ch9200.c b/drivers/net/usb/ch9200.c
index f69d9b902da0..a206ffa76f1b 100644
--- a/drivers/net/usb/ch9200.c
+++ b/drivers/net/usb/ch9200.c
@@ -178,6 +178,7 @@ static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
unsigned char buff[2];
+ int ret;
netdev_dbg(netdev, "%s phy_id:%02x loc:%02x\n",
__func__, phy_id, loc);
@@ -185,8 +186,10 @@ static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc)
if (phy_id != 0)
return -ENODEV;
- control_read(dev, REQUEST_READ, 0, loc * 2, buff, 0x02,
- CONTROL_TIMEOUT_MS);
+ ret = control_read(dev, REQUEST_READ, 0, loc * 2, buff, 0x02,
+ CONTROL_TIMEOUT_MS);
+ if (ret < 0)
+ return ret;
return (buff[0] | buff[1] << 8);
}
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 2440e30c5bd1..0572f6a9bdb6 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1572,6 +1572,30 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
return (hlen + (hdr.tcp->doff << 2));
}
+static void
+vmxnet3_lro_tunnel(struct sk_buff *skb, __be16 ip_proto)
+{
+ struct udphdr *uh = NULL;
+
+ if (ip_proto == htons(ETH_P_IP)) {
+ struct iphdr *iph = (struct iphdr *)skb->data;
+
+ if (iph->protocol == IPPROTO_UDP)
+ uh = (struct udphdr *)(iph + 1);
+ } else {
+ struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
+
+ if (iph->nexthdr == IPPROTO_UDP)
+ uh = (struct udphdr *)(iph + 1);
+ }
+ if (uh) {
+ if (uh->check)
+ skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;
+ else
+ skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL;
+ }
+}
+
static int
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter, int quota)
@@ -1885,6 +1909,8 @@ sop_done:
if (segCnt != 0 && mss != 0) {
skb_shinfo(skb)->gso_type = rcd->v4 ?
SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
+ if (encap_lro)
+ vmxnet3_lro_tunnel(skb, skb->protocol);
skb_shinfo(skb)->gso_size = mss;
skb_shinfo(skb)->gso_segs = segCnt;
} else if ((segCnt != 0 || skb->len > mtu) && !encap_lro) {
diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c
index 3ffeeba5dccf..4a529f1f9bea 100644
--- a/drivers/net/wireguard/device.c
+++ b/drivers/net/wireguard/device.c
@@ -366,6 +366,7 @@ static int wg_newlink(struct net_device *dev,
if (ret < 0)
goto err_free_handshake_queue;
+ dev_set_threaded(dev, true);
ret = register_netdevice(dev);
if (ret < 0)
goto err_uninit_ratelimiter;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c
index 73ed8d5cab43..9d2c087360e7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c
@@ -349,10 +349,6 @@ int iwl_mld_load_fw(struct iwl_mld *mld)
if (ret)
goto err;
- ret = iwl_mld_init_mcc(mld);
- if (ret)
- goto err;
-
mld->fw_status.running = true;
return 0;
@@ -546,6 +542,10 @@ int iwl_mld_start_fw(struct iwl_mld *mld)
if (ret)
goto error;
+ ret = iwl_mld_init_mcc(mld);
+ if (ret)
+ goto error;
+
return 0;
error:
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 8cdd960c5245..e8820e7cf8fa 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
@@ -653,7 +653,8 @@ iwl_mld_nic_error(struct iwl_op_mode *op_mode,
* It might not actually be true that we'll restart, but the
* setting doesn't matter if we're going to be unbound either.
*/
- if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT)
+ if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT &&
+ mld->fw_status.running)
mld->fw_status.in_hw_restart = true;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 0f056a6641bd..956b491ae5a4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -6360,8 +6360,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
(struct iwl_mvm_internal_rxq_notif *)cmd->payload;
struct iwl_host_cmd hcmd = {
.id = WIDE_ID(DATA_PATH_GROUP, TRIGGER_RX_QUEUES_NOTIF_CMD),
- .data[0] = &cmd,
- .len[0] = sizeof(cmd),
+ .data[0] = cmd,
+ .len[0] = __struct_size(cmd),
.data[1] = data,
.len[1] = size,
.flags = CMD_SEND_IN_RFKILL | (sync ? 0 : CMD_ASYNC),
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 38ad719161e6..c8f4f3a1d2eb 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -125,7 +125,7 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans)
reset_done =
inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE;
} else {
- inta_hw = iwl_read32(trans, CSR_INT_MASK);
+ inta_hw = iwl_read32(trans, CSR_INT);
reset_done = inta_hw & CSR_INT_BIT_RESET_DONE;
}
diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c
index 8755c5e6a65b..c814fbd756a1 100644
--- a/drivers/net/wwan/mhi_wwan_mbim.c
+++ b/drivers/net/wwan/mhi_wwan_mbim.c
@@ -550,8 +550,8 @@ static int mhi_mbim_newlink(void *ctxt, struct net_device *ndev, u32 if_id,
struct mhi_mbim_link *link = wwan_netdev_drvpriv(ndev);
struct mhi_mbim_context *mbim = ctxt;
- link->session = if_id;
link->mbim = mbim;
+ link->session = mhi_mbim_get_link_mux_id(link->mbim->mdev->mhi_cntrl) + if_id;
link->ndev = ndev;
u64_stats_init(&link->rx_syncp);
u64_stats_init(&link->tx_syncp);
@@ -607,7 +607,7 @@ static int mhi_mbim_probe(struct mhi_device *mhi_dev, const struct mhi_device_id
{
struct mhi_controller *cntrl = mhi_dev->mhi_cntrl;
struct mhi_mbim_context *mbim;
- int err, link_id;
+ int err;
mbim = devm_kzalloc(&mhi_dev->dev, sizeof(*mbim), GFP_KERNEL);
if (!mbim)
@@ -628,11 +628,8 @@ static int mhi_mbim_probe(struct mhi_device *mhi_dev, const struct mhi_device_id
/* Number of transfer descriptors determines size of the queue */
mbim->rx_queue_sz = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
- /* Get the corresponding mux_id from mhi */
- link_id = mhi_mbim_get_link_mux_id(cntrl);
-
/* Register wwan link ops with MHI controller representing WWAN instance */
- return wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_mbim_wwan_ops, mbim, link_id);
+ return wwan_register_ops(&cntrl->mhi_dev->dev, &mhi_mbim_wwan_ops, mbim, 0);
}
static void mhi_mbim_remove(struct mhi_device *mhi_dev)
diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.c b/drivers/net/wwan/t7xx/t7xx_netdev.c
index 91fa082e9cab..fc0a7cb181df 100644
--- a/drivers/net/wwan/t7xx/t7xx_netdev.c
+++ b/drivers/net/wwan/t7xx/t7xx_netdev.c
@@ -302,7 +302,7 @@ static int t7xx_ccmni_wwan_newlink(void *ctxt, struct net_device *dev, u32 if_id
ccmni->ctlb = ctlb;
ccmni->dev = dev;
atomic_set(&ccmni->usage, 0);
- ctlb->ccmni_inst[if_id] = ccmni;
+ WRITE_ONCE(ctlb->ccmni_inst[if_id], ccmni);
ret = register_netdevice(dev);
if (ret)
@@ -324,6 +324,7 @@ static void t7xx_ccmni_wwan_dellink(void *ctxt, struct net_device *dev, struct l
if (WARN_ON(ctlb->ccmni_inst[if_id] != ccmni))
return;
+ WRITE_ONCE(ctlb->ccmni_inst[if_id], NULL);
unregister_netdevice(dev);
}
@@ -419,7 +420,7 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu
skb_cb = T7XX_SKB_CB(skb);
netif_id = skb_cb->netif_idx;
- ccmni = ccmni_ctlb->ccmni_inst[netif_id];
+ ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]);
if (!ccmni) {
dev_kfree_skb(skb);
return;
@@ -441,7 +442,7 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu
static void t7xx_ccmni_queue_tx_irq_notify(struct t7xx_ccmni_ctrl *ctlb, int qno)
{
- struct t7xx_ccmni *ccmni = ctlb->ccmni_inst[0];
+ struct t7xx_ccmni *ccmni = READ_ONCE(ctlb->ccmni_inst[0]);
struct netdev_queue *net_queue;
if (netif_running(ccmni->dev) && atomic_read(&ccmni->usage) > 0) {
@@ -453,7 +454,7 @@ static void t7xx_ccmni_queue_tx_irq_notify(struct t7xx_ccmni_ctrl *ctlb, int qno
static void t7xx_ccmni_queue_tx_full_notify(struct t7xx_ccmni_ctrl *ctlb, int qno)
{
- struct t7xx_ccmni *ccmni = ctlb->ccmni_inst[0];
+ struct t7xx_ccmni *ccmni = READ_ONCE(ctlb->ccmni_inst[0]);
struct netdev_queue *net_queue;
if (atomic_read(&ccmni->usage) > 0) {
@@ -471,7 +472,7 @@ static void t7xx_ccmni_queue_state_notify(struct t7xx_pci_dev *t7xx_dev,
if (ctlb->md_sta != MD_STATE_READY)
return;
- if (!ctlb->ccmni_inst[0]) {
+ if (!READ_ONCE(ctlb->ccmni_inst[0])) {
dev_warn(&t7xx_dev->pdev->dev, "No netdev registered yet\n");
return;
}
diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c
index 3b6d759bcdf2..91e273b89fea 100644
--- a/drivers/nvme/common/auth.c
+++ b/drivers/nvme/common/auth.c
@@ -471,7 +471,7 @@ EXPORT_SYMBOL_GPL(nvme_auth_generate_key);
* @c1: Value of challenge C1
* @c2: Value of challenge C2
* @hash_len: Hash length of the hash algorithm
- * @ret_psk: Pointer too the resulting generated PSK
+ * @ret_psk: Pointer to the resulting generated PSK
* @ret_len: length of @ret_psk
*
* Generate a PSK for TLS as specified in NVMe base specification, section
@@ -759,8 +759,8 @@ int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len,
goto out_free_prk;
/*
- * 2 addtional bytes for the length field from HDKF-Expand-Label,
- * 2 addtional bytes for the HMAC ID, and one byte for the space
+ * 2 additional bytes for the length field from HDKF-Expand-Label,
+ * 2 additional bytes for the HMAC ID, and one byte for the space
* separator.
*/
info_len = strlen(psk_digest) + strlen(psk_prefix) + 5;
diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
index 7dca58f0a237..31974c7dd20c 100644
--- a/drivers/nvme/host/Kconfig
+++ b/drivers/nvme/host/Kconfig
@@ -106,7 +106,7 @@ config NVME_TCP_TLS
help
Enables TLS encryption for NVMe TCP using the netlink handshake API.
- The TLS handshake daemon is availble at
+ The TLS handshake daemon is available at
https://github.com/oracle/ktls-utils.
If unsure, say N.
diff --git a/drivers/nvme/host/constants.c b/drivers/nvme/host/constants.c
index 2b9e6cfaf2a8..1a0058be5821 100644
--- a/drivers/nvme/host/constants.c
+++ b/drivers/nvme/host/constants.c
@@ -145,7 +145,7 @@ static const char * const nvme_statuses[] = {
[NVME_SC_BAD_ATTRIBUTES] = "Conflicting Attributes",
[NVME_SC_INVALID_PI] = "Invalid Protection Information",
[NVME_SC_READ_ONLY] = "Attempted Write to Read Only Range",
- [NVME_SC_ONCS_NOT_SUPPORTED] = "ONCS Not Supported",
+ [NVME_SC_CMD_SIZE_LIM_EXCEEDED ] = "Command Size Limits Exceeded",
[NVME_SC_ZONE_BOUNDARY_ERROR] = "Zoned Boundary Error",
[NVME_SC_ZONE_FULL] = "Zone Is Full",
[NVME_SC_ZONE_READ_ONLY] = "Zone Is Read Only",
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f69a232a000a..92697f98c601 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -290,7 +290,6 @@ static blk_status_t nvme_error_status(u16 status)
case NVME_SC_NS_NOT_READY:
return BLK_STS_TARGET;
case NVME_SC_BAD_ATTRIBUTES:
- case NVME_SC_ONCS_NOT_SUPPORTED:
case NVME_SC_INVALID_OPCODE:
case NVME_SC_INVALID_FIELD:
case NVME_SC_INVALID_NS:
@@ -1027,7 +1026,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
if (ns->head->ms) {
/*
- * If formated with metadata, the block layer always provides a
+ * If formatted with metadata, the block layer always provides a
* metadata buffer if CONFIG_BLK_DEV_INTEGRITY is enabled. Else
* we enable the PRACT bit for protection information or set the
* namespace capacity to zero to prevent any I/O.
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 93e9041b9657..2e58a7ce1090 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -582,7 +582,7 @@ EXPORT_SYMBOL_GPL(nvmf_connect_io_queue);
* Do not retry when:
*
* - the DNR bit is set and the specification states no further connect
- * attempts with the same set of paramenters should be attempted.
+ * attempts with the same set of parameters should be attempted.
*
* - when the authentication attempt fails, because the key was invalid.
* This error code is set on the host side.
diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h
index 9cf5b020adba..1b58ee7d0dce 100644
--- a/drivers/nvme/host/fabrics.h
+++ b/drivers/nvme/host/fabrics.h
@@ -80,7 +80,7 @@ enum {
* @transport: Holds the fabric transport "technology name" (for a lack of
* better description) that will be used by an NVMe controller
* being added.
- * @subsysnqn: Hold the fully qualified NQN subystem name (format defined
+ * @subsysnqn: Hold the fully qualified NQN subsystem name (format defined
* in the NVMe specification, "NVMe Qualified Names").
* @traddr: The transport-specific TRADDR field for a port on the
* subsystem which is adding a controller.
@@ -156,7 +156,7 @@ struct nvmf_ctrl_options {
* @create_ctrl(): function pointer that points to a non-NVMe
* implementation-specific fabric technology
* that would go into starting up that fabric
- * for the purpose of conneciton to an NVMe controller
+ * for the purpose of connection to an NVMe controller
* using that fabric technology.
*
* Notes:
@@ -165,7 +165,7 @@ struct nvmf_ctrl_options {
* 2. create_ctrl() must be defined (even if it does nothing)
* 3. struct nvmf_transport_ops must be statically allocated in the
* modules .bss section so that a pure module_get on @module
- * prevents the memory from beeing freed.
+ * prevents the memory from being freed.
*/
struct nvmf_transport_ops {
struct list_head entry;
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index fdafa3e9e66f..014b387f1e8b 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -1955,7 +1955,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
}
/*
- * For the linux implementation, if we have an unsuccesful
+ * For the linux implementation, if we have an unsucceesful
* status, they blk-mq layer can typically be called with the
* non-zero status and the content of the cqe isn't important.
*/
@@ -2479,7 +2479,7 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues)
* writing the registers for shutdown and polling (call
* nvme_disable_ctrl()). Given a bunch of i/o was potentially
* just aborted and we will wait on those contexts, and given
- * there was no indication of how live the controlelr is on the
+ * there was no indication of how live the controller is on the
* link, don't send more io to create more contexts for the
* shutdown. Let the controller fail via keepalive failure if
* its still present.
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
index ca86d3bf7ea4..0b50da2f1175 100644
--- a/drivers/nvme/host/ioctl.c
+++ b/drivers/nvme/host/ioctl.c
@@ -493,13 +493,15 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
d.timeout_ms = READ_ONCE(cmd->timeout_ms);
if (d.data_len && (ioucmd->flags & IORING_URING_CMD_FIXED)) {
- /* fixedbufs is only for non-vectored io */
- if (vec)
- return -EINVAL;
+ int ddir = nvme_is_write(&c) ? WRITE : READ;
- ret = io_uring_cmd_import_fixed(d.addr, d.data_len,
- nvme_is_write(&c) ? WRITE : READ, &iter, ioucmd,
- issue_flags);
+ if (vec)
+ ret = io_uring_cmd_import_fixed_vec(ioucmd,
+ u64_to_user_ptr(d.addr), d.data_len,
+ ddir, &iter, issue_flags);
+ else
+ ret = io_uring_cmd_import_fixed(d.addr, d.data_len,
+ ddir, &iter, ioucmd, issue_flags);
if (ret < 0)
return ret;
@@ -521,7 +523,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
if (d.data_len) {
ret = nvme_map_user_request(req, d.addr, d.data_len,
nvme_to_user_ptr(d.metadata), d.metadata_len,
- map_iter, vec);
+ map_iter, vec ? NVME_IOCTL_VEC : 0);
if (ret)
goto out_free_req;
}
@@ -727,7 +729,7 @@ int nvme_ns_head_ioctl(struct block_device *bdev, blk_mode_t mode,
/*
* Handle ioctls that apply to the controller instead of the namespace
- * seperately and drop the ns SRCU reference early. This avoids a
+ * separately and drop the ns SRCU reference early. This avoids a
* deadlock when deleting namespaces using the passthrough interface.
*/
if (is_ctrl_ioctl(cmd))
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 878ea8b1a0ac..140079ff86e6 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -760,7 +760,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
* controller's scan_work context. If a path error occurs here, the IO
* will wait until a path becomes available or all paths are torn down,
* but that action also occurs within scan_work, so it would deadlock.
- * Defer the partion scan to a different context that does not block
+ * Defer the partition scan to a different context that does not block
* scan_work.
*/
set_bit(GD_SUPPRESS_PART_SCAN, &head->disk->state);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index ad0c1f834f09..a468cdc5b5cb 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -523,7 +523,7 @@ static inline bool nvme_ns_head_multipath(struct nvme_ns_head *head)
enum nvme_ns_features {
NVME_NS_EXT_LBAS = 1 << 0, /* support extended LBA format */
NVME_NS_METADATA_SUPPORTED = 1 << 1, /* support getting generated md */
- NVME_NS_DEAC = 1 << 2, /* DEAC bit in Write Zeores supported */
+ NVME_NS_DEAC = 1 << 2, /* DEAC bit in Write Zeroes supported */
};
struct nvme_ns {
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e0bfe04a2bc2..8ff12e415cb5 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -3015,7 +3015,7 @@ static void nvme_reset_work(struct work_struct *work)
goto out;
/*
- * Freeze and update the number of I/O queues as thos might have
+ * Freeze and update the number of I/O queues as those might have
* changed. If there are no I/O queues left after this reset, keep the
* controller around but remove all namespaces.
*/
@@ -3186,7 +3186,7 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
/*
* Exclude some Kingston NV1 and A2000 devices from
* NVME_QUIRK_SIMPLE_SUSPEND. Do a full suspend to save a
- * lot fo energy with s2idle sleep on some TUXEDO platforms.
+ * lot of energy with s2idle sleep on some TUXEDO platforms.
*/
if (dmi_match(DMI_BOARD_NAME, "NS5X_NS7XAU") ||
dmi_match(DMI_BOARD_NAME, "NS5x_7xAU") ||
diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c
index cf2d2c5039dd..ca6a74607b13 100644
--- a/drivers/nvme/host/pr.c
+++ b/drivers/nvme/host/pr.c
@@ -82,8 +82,6 @@ static int nvme_status_to_pr_err(int status)
return PR_STS_SUCCESS;
case NVME_SC_RESERVATION_CONFLICT:
return PR_STS_RESERVATION_CONFLICT;
- case NVME_SC_ONCS_NOT_SUPPORTED:
- return -EOPNOTSUPP;
case NVME_SC_BAD_ATTRIBUTES:
case NVME_SC_INVALID_OPCODE:
case NVME_SC_INVALID_FIELD:
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index b5a0295b5bf4..9bd3646568d0 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -221,7 +221,7 @@ static struct nvme_rdma_qe *nvme_rdma_alloc_ring(struct ib_device *ibdev,
/*
* Bind the CQEs (post recv buffers) DMA mapping to the RDMA queue
- * lifetime. It's safe, since any chage in the underlying RDMA device
+ * lifetime. It's safe, since any change in the underlying RDMA device
* will issue error recovery and queue re-creation.
*/
for (i = 0; i < ib_queue_size; i++) {
@@ -800,7 +800,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl,
/*
* Bind the async event SQE DMA mapping to the admin queue lifetime.
- * It's safe, since any chage in the underlying RDMA device will issue
+ * It's safe, since any change in the underlying RDMA device will issue
* error recovery and queue re-creation.
*/
error = nvme_rdma_alloc_qe(ctrl->device->dev, &ctrl->async_event_sqe,
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index f6379aa33d77..d924008c3949 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -452,7 +452,8 @@ nvme_tcp_fetch_request(struct nvme_tcp_queue *queue)
return NULL;
}
- list_del(&req->entry);
+ list_del_init(&req->entry);
+ init_llist_node(&req->lentry);
return req;
}
@@ -565,6 +566,8 @@ static int nvme_tcp_init_request(struct blk_mq_tag_set *set,
req->queue = queue;
nvme_req(rq)->ctrl = &ctrl->ctrl;
nvme_req(rq)->cmd = &pdu->cmd;
+ init_llist_node(&req->lentry);
+ INIT_LIST_HEAD(&req->entry);
return 0;
}
@@ -769,6 +772,14 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue,
return -EPROTO;
}
+ if (llist_on_list(&req->lentry) ||
+ !list_empty(&req->entry)) {
+ dev_err(queue->ctrl->ctrl.device,
+ "req %d unexpected r2t while processing request\n",
+ rq->tag);
+ return -EPROTO;
+ }
+
req->pdu_len = 0;
req->h2cdata_left = r2t_length;
req->h2cdata_offset = r2t_offset;
@@ -1355,7 +1366,7 @@ static int nvme_tcp_try_recv(struct nvme_tcp_queue *queue)
queue->nr_cqe = 0;
consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb);
release_sock(sk);
- return consumed;
+ return consumed == -EAGAIN ? 0 : consumed;
}
static void nvme_tcp_io_work(struct work_struct *w)
@@ -1383,6 +1394,11 @@ static void nvme_tcp_io_work(struct work_struct *w)
else if (unlikely(result < 0))
return;
+ /* did we get some space after spending time in recv? */
+ if (nvme_tcp_queue_has_pending(queue) &&
+ sk_stream_is_writeable(queue->sock->sk))
+ pending = true;
+
if (!pending || !queue->rd_enabled)
return;
@@ -2350,7 +2366,7 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
nvme_tcp_teardown_admin_queue(ctrl, false);
ret = nvme_tcp_configure_admin_queue(ctrl, false);
if (ret)
- return ret;
+ goto destroy_admin;
}
if (ctrl->icdoff) {
@@ -2594,6 +2610,8 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg)
ctrl->async_req.offset = 0;
ctrl->async_req.curr_bio = NULL;
ctrl->async_req.data_len = 0;
+ init_llist_node(&ctrl->async_req.lentry);
+ INIT_LIST_HEAD(&ctrl->async_req.entry);
nvme_tcp_queue_request(&ctrl->async_req, true);
}
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index c7317299078d..3e378153a781 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -1165,7 +1165,7 @@ static void nvmet_execute_identify(struct nvmet_req *req)
* A "minimum viable" abort implementation: the command is mandatory in the
* spec, but we are not required to do any useful work. We couldn't really
* do a useful abort, so don't bother even with waiting for the command
- * to be exectuted and return immediately telling the command to abort
+ * to be executed and return immediately telling the command to abort
* wasn't found.
*/
static void nvmet_execute_abort(struct nvmet_req *req)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index db7b17d1094e..175c5b6d4dd5 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -62,14 +62,7 @@ inline u16 errno_to_nvme_status(struct nvmet_req *req, int errno)
return NVME_SC_LBA_RANGE | NVME_STATUS_DNR;
case -EOPNOTSUPP:
req->error_loc = offsetof(struct nvme_common_command, opcode);
- switch (req->cmd->common.opcode) {
- case nvme_cmd_dsm:
- case nvme_cmd_write_zeroes:
- return NVME_SC_ONCS_NOT_SUPPORTED | NVME_STATUS_DNR;
- default:
- return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
- }
- break;
+ return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
case -ENODATA:
req->error_loc = offsetof(struct nvme_rw_command, nsid);
return NVME_SC_ACCESS_DENIED;
@@ -651,7 +644,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
* Now that we removed the namespaces from the lookup list, we
* can kill the per_cpu ref and wait for any remaining references
* to be dropped, as well as a RCU grace period for anyone only
- * using the namepace under rcu_read_lock(). Note that we can't
+ * using the namespace under rcu_read_lock(). Note that we can't
* use call_rcu here as we need to ensure the namespaces have
* been fully destroyed before unloading the module.
*/
diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c
index 254537b93e63..25598a46bf0d 100644
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -1339,7 +1339,7 @@ nvmet_fc_portentry_rebind_tgt(struct nvmet_fc_tgtport *tgtport)
/**
* nvmet_fc_register_targetport - transport entry point called by an
* LLDD to register the existence of a local
- * NVME subystem FC port.
+ * NVME subsystem FC port.
* @pinfo: pointer to information about the port to be registered
* @template: LLDD entrypoints and operational parameters for the port
* @dev: physical hardware device node port corresponds to. Will be
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 83be0657e6df..eba42df2f821 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -133,7 +133,7 @@ u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
* Right now there exists M : 1 mapping between block layer error
* to the NVMe status code (see nvme_error_status()). For consistency,
* when we reverse map we use most appropriate NVMe Status code from
- * the group of the NVMe staus codes used in the nvme_error_status().
+ * the group of the NVMe status codes used in the nvme_error_status().
*/
switch (blk_sts) {
case BLK_STS_NOSPC:
@@ -145,15 +145,8 @@ u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts)
req->error_loc = offsetof(struct nvme_rw_command, slba);
break;
case BLK_STS_NOTSUPP:
+ status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
req->error_loc = offsetof(struct nvme_common_command, opcode);
- switch (req->cmd->common.opcode) {
- case nvme_cmd_dsm:
- case nvme_cmd_write_zeroes:
- status = NVME_SC_ONCS_NOT_SUPPORTED | NVME_STATUS_DNR;
- break;
- default:
- status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
- }
break;
case BLK_STS_MEDIUM:
status = NVME_SC_ACCESS_DENIED;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 26e2907ce8bb..b7515c53829b 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -99,7 +99,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
/*
* The passthru NVMe driver may have a limit on the number of segments
- * which depends on the host's memory fragementation. To solve this,
+ * which depends on the host's memory fragmentation. To solve this,
* ensure mdts is limited to the pages equal to the number of segments.
*/
max_hw_sectors = min_not_zero(pctrl->max_segments << PAGE_SECTORS_SHIFT,
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 3de07ef52490..d370b2ad11e7 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -40,6 +40,19 @@ config NVMEM_APPLE_EFUSES
This driver can also be built as a module. If so, the module will
be called nvmem-apple-efuses.
+config NVMEM_APPLE_SPMI
+ tristate "Apple SPMI NVMEM"
+ depends on ARCH_APPLE || COMPILE_TEST
+ depends on SPMI
+ select REGMAP_SPMI
+ help
+ Say y here to build a driver to expose NVMEM cells for a set of power
+ and RTC-related settings on a SPMI-attached PMIC present on Apple
+ devices, such as Apple Silicon Macs.
+
+ This driver can also be built as a module. If so, the module
+ will be called apple-nvmem-spmi.
+
config NVMEM_BCM_OCOTP
tristate "Broadcom On-Chip OTP Controller support"
depends on ARCH_BCM_IPROC || COMPILE_TEST
@@ -272,6 +285,7 @@ config NVMEM_RCAR_EFUSE
config NVMEM_RMEM
tristate "Reserved Memory Based Driver Support"
depends on HAS_IOMEM
+ select CRC32
help
This driver maps reserved memory into an nvmem device. It might be
useful to expose information left by firmware in memory.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index a9d03cfbbd27..2021d59688db 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -12,6 +12,8 @@ obj-y += layouts/
# Devices
obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o
nvmem-apple-efuses-y := apple-efuses.o
+obj-$(CONFIG_NVMEM_APPLE_SPMI) += apple_nvmem_spmi.o
+apple_nvmem_spmi-y := apple-spmi-nvmem.o
obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o
nvmem-bcm-ocotp-y := bcm-ocotp.o
obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o
diff --git a/drivers/nvmem/apple-spmi-nvmem.c b/drivers/nvmem/apple-spmi-nvmem.c
new file mode 100644
index 000000000000..88614005d5ce
--- /dev/null
+++ b/drivers/nvmem/apple-spmi-nvmem.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Apple SPMI NVMEM driver
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/spmi.h>
+#include <linux/regmap.h>
+
+static const struct regmap_config apple_spmi_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0xffff,
+};
+
+static int apple_spmi_nvmem_probe(struct spmi_device *sdev)
+{
+ struct regmap *regmap;
+ struct nvmem_config nvmem_cfg = {
+ .dev = &sdev->dev,
+ .name = "spmi_nvmem",
+ .id = NVMEM_DEVID_AUTO,
+ .word_size = 1,
+ .stride = 1,
+ .size = 0xffff,
+ .reg_read = (void *)regmap_bulk_read,
+ .reg_write = (void *)regmap_bulk_write,
+ };
+
+ regmap = devm_regmap_init_spmi_ext(sdev, &apple_spmi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ nvmem_cfg.priv = regmap;
+
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(&sdev->dev, &nvmem_cfg));
+}
+
+static const struct of_device_id apple_spmi_nvmem_id_table[] = {
+ { .compatible = "apple,spmi-nvmem" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, apple_spmi_nvmem_id_table);
+
+static struct spmi_driver apple_spmi_nvmem_driver = {
+ .probe = apple_spmi_nvmem_probe,
+ .driver = {
+ .name = "apple-spmi-nvmem",
+ .of_match_table = apple_spmi_nvmem_id_table,
+ },
+};
+
+module_spmi_driver(apple_spmi_nvmem_driver);
+
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_DESCRIPTION("Apple SPMI NVMEM driver");
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index e206efc29a00..fd2a9698d1c9 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -47,9 +47,6 @@ struct nvmem_cell {
static DEFINE_MUTEX(nvmem_mutex);
static DEFINE_IDA(nvmem_ida);
-static DEFINE_MUTEX(nvmem_cell_mutex);
-static LIST_HEAD(nvmem_cell_tables);
-
static DEFINE_MUTEX(nvmem_lookup_mutex);
static LIST_HEAD(nvmem_lookup_list);
@@ -719,41 +716,6 @@ int nvmem_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(nvmem_unregister_notifier);
-static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
-{
- const struct nvmem_cell_info *info;
- struct nvmem_cell_table *table;
- struct nvmem_cell_entry *cell;
- int rval = 0, i;
-
- mutex_lock(&nvmem_cell_mutex);
- list_for_each_entry(table, &nvmem_cell_tables, node) {
- if (strcmp(nvmem_dev_name(nvmem), table->nvmem_name) == 0) {
- for (i = 0; i < table->ncells; i++) {
- info = &table->cells[i];
-
- cell = kzalloc(sizeof(*cell), GFP_KERNEL);
- if (!cell) {
- rval = -ENOMEM;
- goto out;
- }
-
- rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell);
- if (rval) {
- kfree(cell);
- goto out;
- }
-
- nvmem_cell_entry_add(cell);
- }
- }
- }
-
-out:
- mutex_unlock(&nvmem_cell_mutex);
- return rval;
-}
-
static struct nvmem_cell_entry *
nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id)
{
@@ -1040,10 +1002,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_remove_cells;
}
- rval = nvmem_add_cells_from_table(nvmem);
- if (rval)
- goto err_remove_cells;
-
if (config->add_legacy_fixed_of_cells) {
rval = nvmem_add_cells_from_legacy_of(nvmem);
if (rval)
@@ -2152,32 +2110,6 @@ int nvmem_device_write(struct nvmem_device *nvmem,
EXPORT_SYMBOL_GPL(nvmem_device_write);
/**
- * nvmem_add_cell_table() - register a table of cell info entries
- *
- * @table: table of cell info entries
- */
-void nvmem_add_cell_table(struct nvmem_cell_table *table)
-{
- mutex_lock(&nvmem_cell_mutex);
- list_add_tail(&table->node, &nvmem_cell_tables);
- mutex_unlock(&nvmem_cell_mutex);
-}
-EXPORT_SYMBOL_GPL(nvmem_add_cell_table);
-
-/**
- * nvmem_del_cell_table() - remove a previously registered cell info table
- *
- * @table: table of cell info entries
- */
-void nvmem_del_cell_table(struct nvmem_cell_table *table)
-{
- mutex_lock(&nvmem_cell_mutex);
- list_del(&table->node);
- mutex_unlock(&nvmem_cell_mutex);
-}
-EXPORT_SYMBOL_GPL(nvmem_del_cell_table);
-
-/**
* nvmem_add_cell_lookups() - register a list of cell lookup entries
*
* @entries: array of cell lookup entries
diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c
index 8682adaacd69..7da717d6c7fa 100644
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -213,6 +213,7 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
econfig.word_size = 1;
econfig.size = ZYNQMP_NVMEM_SIZE;
econfig.dev = dev;
+ econfig.priv = dev;
econfig.add_legacy_fixed_of_cells = true;
econfig.reg_read = zynqmp_nvmem_read;
econfig.reg_write = zynqmp_nvmem_write;
diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c
index 4337c8f5acf0..60dcd3542373 100644
--- a/drivers/pwm/pwm-axi-pwmgen.c
+++ b/drivers/pwm/pwm-axi-pwmgen.c
@@ -257,7 +257,7 @@ static int axi_pwmgen_probe(struct platform_device *pdev)
struct regmap *regmap;
struct pwm_chip *chip;
struct axi_pwmgen_ddata *ddata;
- struct clk *clk;
+ struct clk *axi_clk, *clk;
void __iomem *io_base;
int ret;
@@ -280,9 +280,26 @@ static int axi_pwmgen_probe(struct platform_device *pdev)
ddata = pwmchip_get_drvdata(chip);
ddata->regmap = regmap;
- clk = devm_clk_get_enabled(dev, NULL);
+ /*
+ * Using NULL here instead of "axi" for backwards compatibility. There
+ * are some dtbs that don't give clock-names and have the "ext" clock
+ * as the one and only clock (due to mistake in the original bindings).
+ */
+ axi_clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(axi_clk))
+ return dev_err_probe(dev, PTR_ERR(axi_clk), "failed to get axi clock\n");
+
+ clk = devm_clk_get_optional_enabled(dev, "ext");
if (IS_ERR(clk))
- return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
+ return dev_err_probe(dev, PTR_ERR(clk), "failed to get ext clock\n");
+
+ /*
+ * If there is no "ext" clock, it means the HDL was compiled with
+ * ASYNC_CLK_EN=0. In this case, the AXI clock is also used for the
+ * PWM output clock.
+ */
+ if (!clk)
+ clk = axi_clk;
ret = devm_clk_rate_exclusive_get(dev, clk);
if (ret)
diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c
index 5e7171b9065a..41fd15adfd1f 100644
--- a/drivers/regulator/max14577-regulator.c
+++ b/drivers/regulator/max14577-regulator.c
@@ -40,11 +40,14 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
struct max14577 *max14577 = rdev_get_drvdata(rdev);
const struct maxim_charger_current *limits =
&maxim_charger_currents[max14577->dev_type];
+ int ret;
if (rdev_get_id(rdev) != MAX14577_CHARGER)
return -EINVAL;
- max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
+ ret = max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, &reg_data);
+ if (ret < 0)
+ return ret;
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
return limits->min;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 838bdc138ffe..9aec922613ce 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1388,6 +1388,18 @@ config RTC_DRV_ASM9260
This driver can also be built as a module. If so, the module
will be called rtc-asm9260.
+config RTC_DRV_CV1800
+ tristate "Sophgo CV1800 RTC"
+ depends on SOPHGO_CV1800_RTCSYS || COMPILE_TEST
+ select MFD_SYSCON
+ select REGMAP
+ help
+ If you say yes here you get support the RTC driver for Sophgo CV1800
+ series SoC.
+
+ This driver can also be built as a module. If so, the module will be
+ called rtc-cv1800.
+
config RTC_DRV_DIGICOLOR
tristate "Conexant Digicolor RTC"
depends on ARCH_DIGICOLOR || COMPILE_TEST
@@ -2088,7 +2100,7 @@ config RTC_DRV_AMLOGIC_A4
tristate "Amlogic RTC"
depends on ARCH_MESON || COMPILE_TEST
select REGMAP_MMIO
- default y
+ default ARCH_MESON
help
If you say yes here you get support for the RTC block on the
Amlogic A113L2(A4) and A113X2(A5) SoCs.
@@ -2096,4 +2108,15 @@ config RTC_DRV_AMLOGIC_A4
This driver can also be built as a module. If so, the module
will be called "rtc-amlogic-a4".
+config RTC_DRV_S32G
+ tristate "RTC driver for S32G2/S32G3 SoCs"
+ depends on ARCH_S32 || COMPILE_TEST
+ depends on COMMON_CLK
+ help
+ Say yes to enable RTC driver for platforms based on the
+ S32G2/S32G3 SoC family.
+
+ This RTC module can be used as a wakeup source.
+ Please note that it is not battery-powered.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 31473b3276d9..4619aa2ac469 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_CADENCE) += rtc-cadence.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
obj-$(CONFIG_RTC_DRV_CROS_EC) += rtc-cros-ec.o
+obj-$(CONFIG_RTC_DRV_CV1800) += rtc-cv1800.o
obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
@@ -160,6 +161,7 @@ obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o
obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3) += rtc-renesas-rtca3.o
+obj-$(CONFIG_RTC_DRV_S32G) += rtc-s32g.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index b88cd4fb295b..b1a2be1f9e3b 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -326,7 +326,7 @@ static void rtc_device_get_offset(struct rtc_device *rtc)
*
* Otherwise the offset seconds should be 0.
*/
- if (rtc->start_secs > rtc->range_max ||
+ if ((rtc->start_secs >= 0 && rtc->start_secs > rtc->range_max) ||
rtc->start_secs + range_secs - 1 < rtc->range_min)
rtc->offset_secs = rtc->start_secs - rtc->range_min;
else if (rtc->start_secs > rtc->range_min)
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index aaf76406cd7d..dc741ba29fa3 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -205,7 +205,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc,
mutex_unlock(&rtc->ops_lock);
- trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
+ trace_rtc_read_alarm(err?0:rtc_tm_to_time64(&alarm->time), err);
return err;
}
diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
index fe361652727a..13b5b1f20465 100644
--- a/drivers/rtc/lib.c
+++ b/drivers/rtc/lib.c
@@ -46,24 +46,38 @@ EXPORT_SYMBOL(rtc_year_days);
* rtc_time64_to_tm - converts time64_t to rtc_time.
*
* @time: The number of seconds since 01-01-1970 00:00:00.
- * (Must be positive.)
+ * Works for values since at least 1900
* @tm: Pointer to the struct rtc_time.
*/
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
- unsigned int secs;
- int days;
+ int days, secs;
u64 u64tmp;
u32 u32tmp, udays, century, day_of_century, year_of_century, year,
day_of_year, month, day;
bool is_Jan_or_Feb, is_leap_year;
- /* time must be positive */
+ /*
+ * Get days and seconds while preserving the sign to
+ * handle negative time values (dates before 1970-01-01)
+ */
days = div_s64_rem(time, 86400, &secs);
+ /*
+ * We need 0 <= secs < 86400 which isn't given for negative
+ * values of time. Fixup accordingly.
+ */
+ if (secs < 0) {
+ days -= 1;
+ secs += 86400;
+ }
+
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
+ /* Ensure tm_wday is always positive */
+ if (tm->tm_wday < 0)
+ tm->tm_wday += 7;
/*
* The following algorithm is, basically, Proposition 6.3 of Neri
@@ -93,7 +107,7 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
* thus, is slightly different from [1].
*/
- udays = ((u32) days) + 719468;
+ udays = days + 719468;
u32tmp = 4 * udays + 3;
century = u32tmp / 146097;
diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/lib_test.c
index c30c759662e3..0eebad1fe2a0 100644
--- a/drivers/rtc/lib_test.c
+++ b/drivers/rtc/lib_test.c
@@ -6,8 +6,10 @@
/*
* Advance a date by one day.
*/
-static void advance_date(int *year, int *month, int *mday, int *yday)
+static void advance_date(int *year, int *month, int *mday, int *yday, int *wday)
{
+ *wday = (*wday + 1) % 7;
+
if (*mday != rtc_month_days(*month - 1, *year)) {
++*mday;
++*yday;
@@ -39,35 +41,38 @@ static void rtc_time64_to_tm_test_date_range(struct kunit *test, int years)
*/
time64_t total_secs = ((time64_t)years) / 400 * 146097 * 86400;
- int year = 1970;
+ int year = 1900;
int month = 1;
int mday = 1;
int yday = 1;
+ int wday = 1; /* Jan 1st 1900 was a Monday */
struct rtc_time result;
time64_t secs;
- s64 days;
+ const time64_t sec_offset = RTC_TIMESTAMP_BEGIN_1900 + ((1 * 60) + 2) * 60 + 3;
for (secs = 0; secs <= total_secs; secs += 86400) {
- rtc_time64_to_tm(secs, &result);
-
- days = div_s64(secs, 86400);
+ rtc_time64_to_tm(secs + sec_offset, &result);
- #define FAIL_MSG "%d/%02d/%02d (%2d) : %lld", \
- year, month, mday, yday, days
+ #define FAIL_MSG "%d/%02d/%02d (%2d, %d) : %lld", \
+ year, month, mday, yday, wday, secs + sec_offset
KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG);
KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG);
KUNIT_ASSERT_EQ_MSG(test, mday, result.tm_mday, FAIL_MSG);
KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 1, result.tm_hour, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 2, result.tm_min, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, 3, result.tm_sec, FAIL_MSG);
+ KUNIT_ASSERT_EQ_MSG(test, wday, result.tm_wday, FAIL_MSG);
- advance_date(&year, &month, &mday, &yday);
+ advance_date(&year, &month, &mday, &yday, &wday);
}
}
/*
- * Checks every day in a 160000 years interval starting on 1970-01-01
+ * Checks every day in a 160000 years interval starting on 1900-01-01
* against the expected result.
*/
static void rtc_time64_to_tm_test_date_range_160000(struct kunit *test)
@@ -76,7 +81,7 @@ static void rtc_time64_to_tm_test_date_range_160000(struct kunit *test)
}
/*
- * Checks every day in a 1000 years interval starting on 1970-01-01
+ * Checks every day in a 1000 years interval starting on 1900-01-01
* against the expected result.
*/
static void rtc_time64_to_tm_test_date_range_1000(struct kunit *test)
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index f6b0102a843a..643734dbae33 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -654,4 +654,3 @@ module_platform_driver_probe(at91_rtc_driver, at91_rtc_probe);
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_rtc");
diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c
index 568a89e79c11..c170345ac076 100644
--- a/drivers/rtc/rtc-cpcap.c
+++ b/drivers/rtc/rtc-cpcap.c
@@ -320,7 +320,6 @@ static struct platform_driver cpcap_rtc_driver = {
module_platform_driver(cpcap_rtc_driver);
-MODULE_ALIAS("platform:cpcap-rtc");
MODULE_DESCRIPTION("CPCAP RTC driver");
MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-cv1800.c b/drivers/rtc/rtc-cv1800.c
new file mode 100644
index 000000000000..678c2c10bf58
--- /dev/null
+++ b/drivers/rtc/rtc-cv1800.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rtc-cv1800.c: RTC driver for Sophgo cv1800 RTC
+ *
+ * Author: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define SEC_PULSE_GEN 0x1004
+#define ALARM_TIME 0x1008
+#define ALARM_ENABLE 0x100C
+#define SET_SEC_CNTR_VAL 0x1010
+#define SET_SEC_CNTR_TRIG 0x1014
+#define SEC_CNTR_VAL 0x1018
+
+/*
+ * When in VDDBKUP domain, this MACRO register
+ * does not power down
+ */
+#define MACRO_RO_T 0x14A8
+#define MACRO_RG_SET_T 0x1498
+
+#define ALARM_ENABLE_MASK BIT(0)
+#define SEL_SEC_PULSE BIT(31)
+
+struct cv1800_rtc_priv {
+ struct rtc_device *rtc_dev;
+ struct regmap *rtc_map;
+ struct clk *clk;
+ int irq;
+};
+
+static bool cv1800_rtc_enabled(struct device *dev)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 reg;
+
+ regmap_read(info->rtc_map, SEC_PULSE_GEN, &reg);
+
+ return (reg & SEL_SEC_PULSE) == 0;
+}
+
+static void cv1800_rtc_enable(struct device *dev)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+
+ /* Sec pulse generated internally */
+ regmap_update_bits(info->rtc_map, SEC_PULSE_GEN, SEL_SEC_PULSE, 0);
+}
+
+static int cv1800_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+
+ regmap_write(info->rtc_map, ALARM_ENABLE, enabled);
+
+ return 0;
+}
+
+static int cv1800_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ unsigned long alarm_time;
+
+ alarm_time = rtc_tm_to_time64(&alrm->time);
+
+ cv1800_rtc_alarm_irq_enable(dev, 0);
+
+ regmap_write(info->rtc_map, ALARM_TIME, alarm_time);
+
+ cv1800_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+ return 0;
+}
+
+static int cv1800_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 enabled;
+ u32 time;
+
+ if (!cv1800_rtc_enabled(dev)) {
+ alarm->enabled = 0;
+ return 0;
+ }
+
+ regmap_read(info->rtc_map, ALARM_ENABLE, &enabled);
+
+ alarm->enabled = enabled & ALARM_ENABLE_MASK;
+
+ regmap_read(info->rtc_map, ALARM_TIME, &time);
+
+ rtc_time64_to_tm(time, &alarm->time);
+
+ return 0;
+}
+
+static int cv1800_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ u32 sec;
+
+ if (!cv1800_rtc_enabled(dev))
+ return -EINVAL;
+
+ regmap_read(info->rtc_map, SEC_CNTR_VAL, &sec);
+
+ rtc_time64_to_tm(sec, tm);
+
+ return 0;
+}
+
+static int cv1800_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
+ unsigned long sec;
+
+ sec = rtc_tm_to_time64(tm);
+
+ regmap_write(info->rtc_map, SET_SEC_CNTR_VAL, sec);
+ regmap_write(info->rtc_map, SET_SEC_CNTR_TRIG, 1);
+
+ regmap_write(info->rtc_map, MACRO_RG_SET_T, sec);
+
+ cv1800_rtc_enable(dev);
+
+ return 0;
+}
+
+static irqreturn_t cv1800_rtc_irq_handler(int irq, void *dev_id)
+{
+ struct cv1800_rtc_priv *info = dev_id;
+
+ rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+ regmap_write(info->rtc_map, ALARM_ENABLE, 0);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops cv1800_rtc_ops = {
+ .read_time = cv1800_rtc_read_time,
+ .set_time = cv1800_rtc_set_time,
+ .read_alarm = cv1800_rtc_read_alarm,
+ .set_alarm = cv1800_rtc_set_alarm,
+ .alarm_irq_enable = cv1800_rtc_alarm_irq_enable,
+};
+
+static int cv1800_rtc_probe(struct platform_device *pdev)
+{
+ struct cv1800_rtc_priv *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->rtc_map = device_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(rtc->rtc_map))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_map),
+ "cannot get parent regmap\n");
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0)
+ return rtc->irq;
+
+ rtc->clk = devm_clk_get_enabled(pdev->dev.parent, "rtc");
+ if (IS_ERR(rtc->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rtc->clk),
+ "rtc clk not found\n");
+
+ platform_set_drvdata(pdev, rtc);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ rtc->rtc_dev->ops = &cv1800_rtc_ops;
+ rtc->rtc_dev->range_max = U32_MAX;
+
+ ret = devm_request_irq(&pdev->dev, rtc->irq, cv1800_rtc_irq_handler,
+ IRQF_TRIGGER_HIGH, "rtc alarm", rtc);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "cannot register interrupt handler\n");
+
+ return devm_rtc_register_device(rtc->rtc_dev);
+}
+
+static const struct platform_device_id cv1800_rtc_id[] = {
+ { .name = "cv1800b-rtc" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, cv1800_rtc_id);
+
+static struct platform_driver cv1800_rtc_driver = {
+ .driver = {
+ .name = "sophgo-cv1800-rtc",
+ },
+ .probe = cv1800_rtc_probe,
+ .id_table = cv1800_rtc_id,
+};
+
+module_platform_driver(cv1800_rtc_driver);
+MODULE_AUTHOR("Jingbao Qiu");
+MODULE_DESCRIPTION("Sophgo cv1800 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index 859397541f29..557c9b29dcc1 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -194,26 +194,17 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data,
config->rtc_count_year_mask;
}
-static int da9063_rtc_stop_alarm(struct device *dev)
-{
- struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
- const struct da9063_compatible_rtc_regmap *config = rtc->config;
-
- return regmap_update_bits(rtc->regmap,
- config->rtc_alarm_year_reg,
- config->rtc_alarm_on_mask,
- 0);
-}
-
-static int da9063_rtc_start_alarm(struct device *dev)
+static int da9063_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
{
struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev);
const struct da9063_compatible_rtc_regmap *config = rtc->config;
+ u8 set_bit = enabled ? config->rtc_alarm_on_mask : 0;
return regmap_update_bits(rtc->regmap,
config->rtc_alarm_year_reg,
config->rtc_alarm_on_mask,
- config->rtc_alarm_on_mask);
+ set_bit);
}
static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -312,7 +303,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
da9063_tm_to_data(&alrm->time, data, rtc);
- ret = da9063_rtc_stop_alarm(dev);
+ ret = da9063_rtc_alarm_irq_enable(dev, 0);
if (ret < 0) {
dev_err(dev, "Failed to stop alarm: %d\n", ret);
return ret;
@@ -330,7 +321,7 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
da9063_data_to_tm(data, &rtc->alarm_time, rtc);
if (alrm->enabled) {
- ret = da9063_rtc_start_alarm(dev);
+ ret = da9063_rtc_alarm_irq_enable(dev, 1);
if (ret < 0) {
dev_err(dev, "Failed to start alarm: %d\n", ret);
return ret;
@@ -340,15 +331,6 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return ret;
}
-static int da9063_rtc_alarm_irq_enable(struct device *dev,
- unsigned int enabled)
-{
- if (enabled)
- return da9063_rtc_start_alarm(dev);
- else
- return da9063_rtc_stop_alarm(dev);
-}
-
static irqreturn_t da9063_alarm_event(int irq, void *data)
{
struct da9063_compatible_rtc *rtc = data;
@@ -513,4 +495,3 @@ module_platform_driver(da9063_rtc_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC);
diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c
index 44bba356268c..11fce47be780 100644
--- a/drivers/rtc/rtc-jz4740.c
+++ b/drivers/rtc/rtc-jz4740.c
@@ -437,4 +437,3 @@ module_platform_driver(jz4740_rtc_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
-MODULE_ALIAS("platform:jz4740-rtc");
diff --git a/drivers/rtc/rtc-loongson.c b/drivers/rtc/rtc-loongson.c
index 97e5625c064c..2ca7ffd5d7a9 100644
--- a/drivers/rtc/rtc-loongson.c
+++ b/drivers/rtc/rtc-loongson.c
@@ -129,6 +129,14 @@ static u32 loongson_rtc_handler(void *id)
{
struct loongson_rtc_priv *priv = (struct loongson_rtc_priv *)id;
+ rtc_update_irq(priv->rtcdev, 1, RTC_AF | RTC_IRQF);
+
+ /*
+ * The TOY_MATCH0_REG should be cleared 0 here,
+ * otherwise the interrupt cannot be cleared.
+ */
+ regmap_write(priv->regmap, TOY_MATCH0_REG, 0);
+
spin_lock(&priv->lock);
/* Disable RTC alarm wakeup and interrupt */
writel(readl(priv->pm_base + PM1_EN_REG) & ~RTC_EN,
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 1f58ae8b151e..c568639d2151 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/string.h>
+#include <linux/delay.h>
#ifdef CONFIG_RTC_DRV_M41T80_WDT
#include <linux/fs.h>
#include <linux/ioctl.h>
@@ -204,14 +205,14 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
return flags;
if (flags & M41T80_FLAGS_OF) {
- dev_err(&client->dev, "Oscillator failure, data is invalid.\n");
+ dev_err(&client->dev, "Oscillator failure, time may not be accurate, write time to RTC to fix it.\n");
return -EINVAL;
}
err = i2c_smbus_read_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
- dev_err(&client->dev, "Unable to read date\n");
+ dev_dbg(&client->dev, "Unable to read date\n");
return err;
}
@@ -227,21 +228,31 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
-static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *in_tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
+ struct rtc_time tm = *in_tm;
unsigned char buf[8];
int err, flags;
+ time64_t time = 0;
+ flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ if (flags < 0)
+ return flags;
+ if (flags & M41T80_FLAGS_OF) {
+ /* add 4sec of oscillator stablize time otherwise we are behind 4sec */
+ time = rtc_tm_to_time64(&tm);
+ rtc_time64_to_tm(time + 4, &tm);
+ }
buf[M41T80_REG_SSEC] = 0;
- buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
- buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
- buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
- buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
- buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
- buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
- buf[M41T80_REG_WDAY] = tm->tm_wday;
+ buf[M41T80_REG_SEC] = bin2bcd(tm.tm_sec);
+ buf[M41T80_REG_MIN] = bin2bcd(tm.tm_min);
+ buf[M41T80_REG_HOUR] = bin2bcd(tm.tm_hour);
+ buf[M41T80_REG_DAY] = bin2bcd(tm.tm_mday);
+ buf[M41T80_REG_MON] = bin2bcd(tm.tm_mon + 1);
+ buf[M41T80_REG_YEAR] = bin2bcd(tm.tm_year - 100);
+ buf[M41T80_REG_WDAY] = tm.tm_wday;
/* If the square wave output is controlled in the weekday register */
if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
@@ -257,20 +268,37 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
- dev_err(&client->dev, "Unable to write to date registers\n");
+ dev_dbg(&client->dev, "Unable to write to date registers\n");
return err;
}
-
- /* Clear the OF bit of Flags Register */
- flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
- if (flags < 0)
- return flags;
-
- err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
- flags & ~M41T80_FLAGS_OF);
- if (err < 0) {
- dev_err(&client->dev, "Unable to write flags register\n");
- return err;
+ if (flags & M41T80_FLAGS_OF) {
+ /* OF cannot be immediately reset: oscillator has to be restarted. */
+ dev_warn(&client->dev, "OF bit is still set, kickstarting clock.\n");
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, M41T80_SEC_ST);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Can't set ST bit\n");
+ return err;
+ }
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, flags & ~M41T80_SEC_ST);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Can't clear ST bit\n");
+ return err;
+ }
+ /* oscillator must run for 4sec before we attempt to reset OF bit */
+ msleep(4000);
+ /* Clear the OF bit of Flags Register */
+ err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags & ~M41T80_FLAGS_OF);
+ if (err < 0) {
+ dev_dbg(&client->dev, "Unable to write flags register\n");
+ return err;
+ }
+ flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ if (flags < 0) {
+ return flags;
+ } else if (flags & M41T80_FLAGS_OF) {
+ dev_dbg(&client->dev, "Can't clear the OF bit check battery\n");
+ return err;
+ }
}
return err;
@@ -308,7 +336,7 @@ static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
if (retval < 0) {
- dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
+ dev_dbg(dev, "Unable to enable alarm IRQ %d\n", retval);
return retval;
}
return 0;
@@ -333,7 +361,7 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
ret & ~(M41T80_ALMON_AFE));
if (err < 0) {
- dev_err(dev, "Unable to clear AFE bit\n");
+ dev_dbg(dev, "Unable to clear AFE bit\n");
return err;
}
@@ -347,7 +375,7 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
ret & ~(M41T80_FLAGS_AF));
if (err < 0) {
- dev_err(dev, "Unable to clear AF bit\n");
+ dev_dbg(dev, "Unable to clear AF bit\n");
return err;
}
diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c
index 6979d225a78e..692c00ff544b 100644
--- a/drivers/rtc/rtc-mt6397.c
+++ b/drivers/rtc/rtc-mt6397.c
@@ -332,6 +332,7 @@ static const struct mtk_rtc_data mt6397_rtc_data = {
static const struct of_device_id mt6397_rtc_of_match[] = {
{ .compatible = "mediatek,mt6323-rtc", .data = &mt6397_rtc_data },
+ { .compatible = "mediatek,mt6357-rtc", .data = &mt6358_rtc_data },
{ .compatible = "mediatek,mt6358-rtc", .data = &mt6358_rtc_data },
{ .compatible = "mediatek,mt6397-rtc", .data = &mt6397_rtc_data },
{ }
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 5a084d426e58..b2611697fa5e 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -285,7 +285,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
buf[2] = bin2bcd(tm->time.tm_mday);
buf[3] = tm->time.tm_wday & 0x07;
- err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC, buf,
+ err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_AMN, buf,
sizeof(buf));
if (err)
return err;
diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c
index 3c1dddcc81df..e624f848c22b 100644
--- a/drivers/rtc/rtc-pm8xxx.c
+++ b/drivers/rtc/rtc-pm8xxx.c
@@ -576,13 +576,20 @@ static int pm8xxx_rtc_probe_offset(struct pm8xxx_rtc *rtc_dd)
}
/* Use UEFI storage as fallback if available */
- if (efivar_is_available()) {
- rc = pm8xxx_rtc_read_uefi_offset(rtc_dd);
- if (rc == 0)
- rtc_dd->use_uefi = true;
+ rtc_dd->use_uefi = of_property_read_bool(rtc_dd->dev->of_node,
+ "qcom,uefi-rtc-info");
+ if (!rtc_dd->use_uefi)
+ return 0;
+
+ if (!efivar_is_available()) {
+ if (IS_ENABLED(CONFIG_EFI))
+ return -EPROBE_DEFER;
+
+ dev_warn(rtc_dd->dev, "efivars not available\n");
+ rtc_dd->use_uefi = false;
}
- return 0;
+ return pm8xxx_rtc_read_uefi_offset(rtc_dd);
}
static int pm8xxx_rtc_probe(struct platform_device *pdev)
@@ -676,7 +683,6 @@ static struct platform_driver pm8xxx_rtc_driver = {
module_platform_driver(pm8xxx_rtc_driver);
-MODULE_ALIAS("platform:rtc-pm8xxx");
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c
index eeb9612a666f..c4ed43735457 100644
--- a/drivers/rtc/rtc-rzn1.c
+++ b/drivers/rtc/rtc-rzn1.c
@@ -12,6 +12,7 @@
*/
#include <linux/bcd.h>
+#include <linux/clk.h>
#include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@@ -22,9 +23,9 @@
#include <linux/spinlock.h>
#define RZN1_RTC_CTL0 0x00
-#define RZN1_RTC_CTL0_SLSB_SUBU 0
#define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
#define RZN1_RTC_CTL0_AMPM BIT(5)
+#define RZN1_RTC_CTL0_CEST BIT(6)
#define RZN1_RTC_CTL0_CE BIT(7)
#define RZN1_RTC_CTL1 0x04
@@ -49,6 +50,8 @@
#define RZN1_RTC_SUBU_DEV BIT(7)
#define RZN1_RTC_SUBU_DECR BIT(6)
+#define RZN1_RTC_SCMP 0x3c
+
#define RZN1_RTC_ALM 0x40
#define RZN1_RTC_ALH 0x44
#define RZN1_RTC_ALW 0x48
@@ -356,7 +359,7 @@ static int rzn1_rtc_set_offset(struct device *dev, long offset)
return 0;
}
-static const struct rtc_class_ops rzn1_rtc_ops = {
+static const struct rtc_class_ops rzn1_rtc_ops_subu = {
.read_time = rzn1_rtc_read_time,
.set_time = rzn1_rtc_set_time,
.read_alarm = rzn1_rtc_read_alarm,
@@ -366,11 +369,21 @@ static const struct rtc_class_ops rzn1_rtc_ops = {
.set_offset = rzn1_rtc_set_offset,
};
+static const struct rtc_class_ops rzn1_rtc_ops_scmp = {
+ .read_time = rzn1_rtc_read_time,
+ .set_time = rzn1_rtc_set_time,
+ .read_alarm = rzn1_rtc_read_alarm,
+ .set_alarm = rzn1_rtc_set_alarm,
+ .alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
+};
+
static int rzn1_rtc_probe(struct platform_device *pdev)
{
struct rzn1_rtc *rtc;
- int irq;
- int ret;
+ u32 val, scmp_val = 0;
+ struct clk *xtal;
+ unsigned long rate;
+ int irq, ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
@@ -393,7 +406,6 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
rtc->rtcdev->alarm_offset_max = 7 * 86400;
- rtc->rtcdev->ops = &rzn1_rtc_ops;
ret = devm_pm_runtime_enable(&pdev->dev);
if (ret < 0)
@@ -402,12 +414,44 @@ static int rzn1_rtc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- /*
- * Ensure the clock counter is enabled.
- * Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
- */
- writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
- rtc->base + RZN1_RTC_CTL0);
+ /* Only switch to scmp if we have an xtal clock with a valid rate and != 32768 */
+ xtal = devm_clk_get_optional(&pdev->dev, "xtal");
+ if (IS_ERR(xtal)) {
+ ret = PTR_ERR(xtal);
+ goto dis_runtime_pm;
+ } else if (xtal) {
+ rate = clk_get_rate(xtal);
+
+ if (rate < 32000 || rate > BIT(22)) {
+ ret = -EOPNOTSUPP;
+ goto dis_runtime_pm;
+ }
+
+ if (rate != 32768)
+ scmp_val = RZN1_RTC_CTL0_SLSB_SCMP;
+ }
+
+ /* Disable controller during SUBU/SCMP setup */
+ val = readl(rtc->base + RZN1_RTC_CTL0) & ~RZN1_RTC_CTL0_CE;
+ writel(val, rtc->base + RZN1_RTC_CTL0);
+ /* Wait 2-4 32k clock cycles for the disabled controller */
+ ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL0, val,
+ !(val & RZN1_RTC_CTL0_CEST), 62, 123);
+ if (ret)
+ goto dis_runtime_pm;
+
+ /* Set desired modes leaving the controller disabled */
+ writel(RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
+
+ if (scmp_val) {
+ writel(rate - 1, rtc->base + RZN1_RTC_SCMP);
+ rtc->rtcdev->ops = &rzn1_rtc_ops_scmp;
+ } else {
+ rtc->rtcdev->ops = &rzn1_rtc_ops_subu;
+ }
+
+ /* Enable controller finally */
+ writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | scmp_val, rtc->base + RZN1_RTC_CTL0);
/* Disable all interrupts */
writel(0, rtc->base + RZN1_RTC_CTL1);
@@ -444,6 +488,11 @@ dis_runtime_pm:
static void rzn1_rtc_remove(struct platform_device *pdev)
{
+ struct rzn1_rtc *rtc = platform_get_drvdata(pdev);
+
+ /* Disable all interrupts */
+ writel(0, rtc->base + RZN1_RTC_CTL1);
+
pm_runtime_put(&pdev->dev);
}
diff --git a/drivers/rtc/rtc-s32g.c b/drivers/rtc/rtc-s32g.c
new file mode 100644
index 000000000000..3a0818e972eb
--- /dev/null
+++ b/drivers/rtc/rtc-s32g.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define RTCC_OFFSET 0x4ul
+#define RTCS_OFFSET 0x8ul
+#define APIVAL_OFFSET 0x10ul
+
+/* RTCC fields */
+#define RTCC_CNTEN BIT(31)
+#define RTCC_APIEN BIT(15)
+#define RTCC_APIIE BIT(14)
+#define RTCC_CLKSEL_MASK GENMASK(13, 12)
+#define RTCC_DIV512EN BIT(11)
+#define RTCC_DIV32EN BIT(10)
+
+/* RTCS fields */
+#define RTCS_INV_API BIT(17)
+#define RTCS_APIF BIT(13)
+
+#define APIVAL_MAX_VAL GENMASK(31, 0)
+#define RTC_SYNCH_TIMEOUT (100 * USEC_PER_MSEC)
+
+/*
+ * S32G2 and S32G3 SoCs have RTC clock source1 reserved and
+ * should not be used.
+ */
+#define RTC_CLK_SRC1_RESERVED BIT(1)
+
+/*
+ * S32G RTC module has a 512 value and a 32 value hardware frequency
+ * divisors (DIV512 and DIV32) which could be used to achieve higher
+ * counter ranges by lowering the RTC frequency.
+ */
+enum {
+ DIV1 = 1,
+ DIV32 = 32,
+ DIV512 = 512,
+ DIV512_32 = 16384
+};
+
+static const char *const rtc_clk_src[] = {
+ "source0",
+ "source1",
+ "source2",
+ "source3"
+};
+
+struct rtc_priv {
+ struct rtc_device *rdev;
+ void __iomem *rtc_base;
+ struct clk *ipg;
+ struct clk *clk_src;
+ const struct rtc_soc_data *rtc_data;
+ u64 rtc_hz;
+ time64_t sleep_sec;
+ int irq;
+ u32 clk_src_idx;
+};
+
+struct rtc_soc_data {
+ u32 clk_div;
+ u32 reserved_clk_mask;
+};
+
+static const struct rtc_soc_data rtc_s32g2_data = {
+ .clk_div = DIV512_32,
+ .reserved_clk_mask = RTC_CLK_SRC1_RESERVED,
+};
+
+static irqreturn_t s32g_rtc_handler(int irq, void *dev)
+{
+ struct rtc_priv *priv = platform_get_drvdata(dev);
+ u32 status;
+
+ status = readl(priv->rtc_base + RTCS_OFFSET);
+
+ if (status & RTCS_APIF) {
+ writel(0x0, priv->rtc_base + APIVAL_OFFSET);
+ writel(status | RTCS_APIF, priv->rtc_base + RTCS_OFFSET);
+ }
+
+ rtc_update_irq(priv->rdev, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * The function is not really getting time from the RTC since the S32G RTC
+ * has several limitations. Thus, to setup alarm use system time.
+ */
+static int s32g_rtc_read_time(struct device *dev,
+ struct rtc_time *tm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ time64_t sec;
+
+ if (check_add_overflow(ktime_get_real_seconds(),
+ priv->sleep_sec, &sec))
+ return -ERANGE;
+
+ rtc_time64_to_tm(sec, tm);
+
+ return 0;
+}
+
+static int s32g_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 rtcc, rtcs;
+
+ rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+ rtcs = readl(priv->rtc_base + RTCS_OFFSET);
+
+ alrm->enabled = rtcc & RTCC_APIIE;
+ if (alrm->enabled)
+ alrm->pending = !(rtcs & RTCS_APIF);
+
+ return 0;
+}
+
+static int s32g_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 rtcc;
+
+ /* RTC API functionality is used both for triggering interrupts
+ * and as a wakeup event. Hence it should always be enabled.
+ */
+ rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+ rtcc |= RTCC_APIEN | RTCC_APIIE;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+
+ return 0;
+}
+
+static int s32g_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ unsigned long long cycles;
+ long long t_offset;
+ time64_t alrm_time;
+ u32 rtcs;
+ int ret;
+
+ alrm_time = rtc_tm_to_time64(&alrm->time);
+ t_offset = alrm_time - ktime_get_real_seconds() - priv->sleep_sec;
+ if (t_offset < 0)
+ return -ERANGE;
+
+ cycles = t_offset * priv->rtc_hz;
+ if (cycles > APIVAL_MAX_VAL)
+ return -ERANGE;
+
+ /* APIVAL could have been reset from the IRQ handler.
+ * Hence, we wait in case there is a synchronization process.
+ */
+ ret = read_poll_timeout(readl, rtcs, !(rtcs & RTCS_INV_API),
+ 0, RTC_SYNCH_TIMEOUT, false, priv->rtc_base + RTCS_OFFSET);
+ if (ret)
+ return ret;
+
+ writel(cycles, priv->rtc_base + APIVAL_OFFSET);
+
+ return read_poll_timeout(readl, rtcs, !(rtcs & RTCS_INV_API),
+ 0, RTC_SYNCH_TIMEOUT, false, priv->rtc_base + RTCS_OFFSET);
+}
+
+/*
+ * Disable the 32-bit free running counter.
+ * This allows Clock Source and Divisors selection
+ * to be performed without causing synchronization issues.
+ */
+static void s32g_rtc_disable(struct rtc_priv *priv)
+{
+ u32 rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+
+ rtcc &= ~RTCC_CNTEN;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+}
+
+static void s32g_rtc_enable(struct rtc_priv *priv)
+{
+ u32 rtcc = readl(priv->rtc_base + RTCC_OFFSET);
+
+ rtcc |= RTCC_CNTEN;
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+}
+
+static int rtc_clk_src_setup(struct rtc_priv *priv)
+{
+ u32 rtcc;
+
+ rtcc = FIELD_PREP(RTCC_CLKSEL_MASK, priv->clk_src_idx);
+
+ switch (priv->rtc_data->clk_div) {
+ case DIV512_32:
+ rtcc |= RTCC_DIV512EN;
+ rtcc |= RTCC_DIV32EN;
+ break;
+ case DIV512:
+ rtcc |= RTCC_DIV512EN;
+ break;
+ case DIV32:
+ rtcc |= RTCC_DIV32EN;
+ break;
+ case DIV1:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rtcc |= RTCC_APIEN | RTCC_APIIE;
+ /*
+ * Make sure the CNTEN is 0 before we configure
+ * the clock source and dividers.
+ */
+ s32g_rtc_disable(priv);
+ writel(rtcc, priv->rtc_base + RTCC_OFFSET);
+ s32g_rtc_enable(priv);
+
+ return 0;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+ .read_time = s32g_rtc_read_time,
+ .read_alarm = s32g_rtc_read_alarm,
+ .set_alarm = s32g_rtc_set_alarm,
+ .alarm_irq_enable = s32g_rtc_alarm_irq_enable,
+};
+
+static int rtc_clk_dts_setup(struct rtc_priv *priv,
+ struct device *dev)
+{
+ u32 i;
+
+ priv->ipg = devm_clk_get_enabled(dev, "ipg");
+ if (IS_ERR(priv->ipg))
+ return dev_err_probe(dev, PTR_ERR(priv->ipg),
+ "Failed to get 'ipg' clock\n");
+
+ for (i = 0; i < ARRAY_SIZE(rtc_clk_src); i++) {
+ if (priv->rtc_data->reserved_clk_mask & BIT(i))
+ return -EOPNOTSUPP;
+
+ priv->clk_src = devm_clk_get_enabled(dev, rtc_clk_src[i]);
+ if (!IS_ERR(priv->clk_src)) {
+ priv->clk_src_idx = i;
+ break;
+ }
+ }
+
+ if (IS_ERR(priv->clk_src))
+ return dev_err_probe(dev, PTR_ERR(priv->clk_src),
+ "Failed to get rtc module clock source\n");
+
+ return 0;
+}
+
+static int s32g_rtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rtc_priv *priv;
+ unsigned long rtc_hz;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->rtc_data = of_device_get_match_data(dev);
+ if (!priv->rtc_data)
+ return -ENODEV;
+
+ priv->rtc_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->rtc_base))
+ return PTR_ERR(priv->rtc_base);
+
+ device_init_wakeup(dev, true);
+
+ ret = rtc_clk_dts_setup(priv, dev);
+ if (ret)
+ return ret;
+
+ priv->rdev = devm_rtc_allocate_device(dev);
+ if (IS_ERR(priv->rdev))
+ return PTR_ERR(priv->rdev);
+
+ ret = rtc_clk_src_setup(priv);
+ if (ret)
+ return ret;
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0) {
+ ret = priv->irq;
+ goto disable_rtc;
+ }
+
+ rtc_hz = clk_get_rate(priv->clk_src);
+ if (!rtc_hz) {
+ dev_err(dev, "Failed to get RTC frequency\n");
+ ret = -EINVAL;
+ goto disable_rtc;
+ }
+
+ priv->rtc_hz = DIV_ROUND_UP(rtc_hz, priv->rtc_data->clk_div);
+
+ platform_set_drvdata(pdev, priv);
+ priv->rdev->ops = &rtc_ops;
+
+ ret = devm_request_irq(dev, priv->irq,
+ s32g_rtc_handler, 0, dev_name(dev), pdev);
+ if (ret) {
+ dev_err(dev, "Request interrupt %d failed, error: %d\n",
+ priv->irq, ret);
+ goto disable_rtc;
+ }
+
+ ret = devm_rtc_register_device(priv->rdev);
+ if (ret)
+ goto disable_rtc;
+
+ return 0;
+
+disable_rtc:
+ s32g_rtc_disable(priv);
+ return ret;
+}
+
+static int s32g_rtc_suspend(struct device *dev)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+ u32 apival = readl(priv->rtc_base + APIVAL_OFFSET);
+
+ if (check_add_overflow(priv->sleep_sec, div64_u64(apival, priv->rtc_hz),
+ &priv->sleep_sec)) {
+ dev_warn(dev, "Overflow on sleep cycles occurred. Resetting to 0.\n");
+ priv->sleep_sec = 0;
+ }
+
+ return 0;
+}
+
+static int s32g_rtc_resume(struct device *dev)
+{
+ struct rtc_priv *priv = dev_get_drvdata(dev);
+
+ /* The transition from resume to run is a reset event.
+ * This leads to the RTC registers being reset after resume from
+ * suspend. It is uncommon, but this behaviour has been observed
+ * on S32G RTC after issuing a Suspend to RAM operation.
+ * Thus, reconfigure RTC registers on the resume path.
+ */
+ return rtc_clk_src_setup(priv);
+}
+
+static const struct of_device_id rtc_dt_ids[] = {
+ { .compatible = "nxp,s32g2-rtc", .data = &rtc_s32g2_data },
+ { /* sentinel */ },
+};
+
+static DEFINE_SIMPLE_DEV_PM_OPS(s32g_rtc_pm_ops,
+ s32g_rtc_suspend, s32g_rtc_resume);
+
+static struct platform_driver s32g_rtc_driver = {
+ .driver = {
+ .name = "s32g-rtc",
+ .pm = pm_sleep_ptr(&s32g_rtc_pm_ops),
+ .of_match_table = rtc_dt_ids,
+ },
+ .probe = s32g_rtc_probe,
+};
+module_platform_driver(s32g_rtc_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP RTC driver for S32G2/S32G3");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 58c957eb753d..5dd575865adf 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -609,4 +609,3 @@ module_platform_driver(s3c_rtc_driver);
MODULE_DESCRIPTION("Samsung S3C RTC Driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-rtc");
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 9ea40f40188f..f15ef3aa82a0 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -5,6 +5,7 @@
* Copyright (C) 2006 - 2009 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
* Copyright (C) 2008 Angelo Castello
+ * Copyright (C) 2025 Wolfram Sang, Renesas Electronics Corporation
*
* Based on the old arch/sh/kernel/cpu/rtc.c by:
*
@@ -31,7 +32,7 @@
/* Default values for RZ/A RTC */
#define rtc_reg_size sizeof(u16)
#define RTC_BIT_INVERTED 0 /* no chip bugs */
-#define RTC_CAP_4_DIGIT_YEAR (1 << 0)
+#define RTC_CAP_4_DIGIT_YEAR BIT(0)
#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR
#endif
@@ -70,62 +71,35 @@
*/
/* ALARM Bits - or with BCD encoded value */
-#define AR_ENB 0x80 /* Enable for alarm cmp */
-
-/* Period Bits */
-#define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */
-#define PF_COUNT 0x200 /* Half periodic counter */
-#define PF_OXS 0x400 /* Periodic One x Second */
-#define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */
-#define PF_MASK 0xf00
+#define AR_ENB BIT(7) /* Enable for alarm cmp */
/* RCR1 Bits */
-#define RCR1_CF 0x80 /* Carry Flag */
-#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define RCR1_AF 0x01 /* Alarm Flag */
+#define RCR1_CF BIT(7) /* Carry Flag */
+#define RCR1_CIE BIT(4) /* Carry Interrupt Enable */
+#define RCR1_AIE BIT(3) /* Alarm Interrupt Enable */
+#define RCR1_AF BIT(0) /* Alarm Flag */
/* RCR2 Bits */
-#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
-#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
-#define RCR2_RTCEN 0x08 /* ENable RTC */
-#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
-#define RCR2_RESET 0x02 /* Reset bit */
-#define RCR2_START 0x01 /* Start bit */
+#define RCR2_RTCEN BIT(3) /* ENable RTC */
+#define RCR2_ADJ BIT(2) /* ADJustment (30-second) */
+#define RCR2_RESET BIT(1) /* Reset bit */
+#define RCR2_START BIT(0) /* Start bit */
struct sh_rtc {
void __iomem *regbase;
- unsigned long regsize;
- struct resource *res;
int alarm_irq;
- int periodic_irq;
- int carry_irq;
struct clk *clk;
struct rtc_device *rtc_dev;
- spinlock_t lock;
+ spinlock_t lock; /* protecting register access */
unsigned long capabilities; /* See asm/rtc.h for cap bits */
- unsigned short periodic_freq;
};
-static int __sh_rtc_interrupt(struct sh_rtc *rtc)
+static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
{
+ struct sh_rtc *rtc = dev_id;
unsigned int tmp, pending;
- tmp = readb(rtc->regbase + RCR1);
- pending = tmp & RCR1_CF;
- tmp &= ~RCR1_CF;
- writeb(tmp, rtc->regbase + RCR1);
-
- /* Users have requested One x Second IRQ */
- if (pending && rtc->periodic_freq & PF_OXS)
- rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
-
- return pending;
-}
-
-static int __sh_rtc_alarm(struct sh_rtc *rtc)
-{
- unsigned int tmp, pending;
+ spin_lock(&rtc->lock);
tmp = readb(rtc->regbase + RCR1);
pending = tmp & RCR1_AF;
@@ -135,84 +109,12 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc)
if (pending)
rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
- return pending;
-}
-
-static int __sh_rtc_periodic(struct sh_rtc *rtc)
-{
- unsigned int tmp, pending;
-
- tmp = readb(rtc->regbase + RCR2);
- pending = tmp & RCR2_PEF;
- tmp &= ~RCR2_PEF;
- writeb(tmp, rtc->regbase + RCR2);
-
- if (!pending)
- return 0;
-
- /* Half period enabled than one skipped and the next notified */
- if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT))
- rtc->periodic_freq &= ~PF_COUNT;
- else {
- if (rtc->periodic_freq & PF_HP)
- rtc->periodic_freq |= PF_COUNT;
- rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
- }
-
- return pending;
-}
-
-static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_interrupt(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_alarm(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_periodic(rtc);
- spin_unlock(&rtc->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static irqreturn_t sh_rtc_shared(int irq, void *dev_id)
-{
- struct sh_rtc *rtc = dev_id;
- int ret;
-
- spin_lock(&rtc->lock);
- ret = __sh_rtc_interrupt(rtc);
- ret |= __sh_rtc_alarm(rtc);
- ret |= __sh_rtc_periodic(rtc);
spin_unlock(&rtc->lock);
- return IRQ_RETVAL(ret);
+ return IRQ_RETVAL(pending);
}
-static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
+static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
unsigned int tmp;
@@ -229,45 +131,7 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
writeb(tmp, rtc->regbase + RCR1);
spin_unlock_irq(&rtc->lock);
-}
-
-static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
-{
- struct sh_rtc *rtc = dev_get_drvdata(dev);
- unsigned int tmp;
-
- tmp = readb(rtc->regbase + RCR1);
- seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no");
-
- tmp = readb(rtc->regbase + RCR2);
- seq_printf(seq, "periodic_IRQ\t: %s\n",
- (tmp & RCR2_PESMASK) ? "yes" : "no");
-
- return 0;
-}
-
-static inline void sh_rtc_setcie(struct device *dev, unsigned int enable)
-{
- struct sh_rtc *rtc = dev_get_drvdata(dev);
- unsigned int tmp;
-
- spin_lock_irq(&rtc->lock);
-
- tmp = readb(rtc->regbase + RCR1);
-
- if (!enable)
- tmp &= ~RCR1_CIE;
- else
- tmp |= RCR1_CIE;
-
- writeb(tmp, rtc->regbase + RCR1);
-
- spin_unlock_irq(&rtc->lock);
-}
-static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
-{
- sh_rtc_setaie(dev, enabled);
return 0;
}
@@ -320,14 +184,8 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec--;
#endif
- /* only keep the carry interrupt enabled if UIE is on */
- if (!(rtc->periodic_freq & PF_OXS))
- sh_rtc_setcie(dev, 0);
-
- dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ __func__, tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
return 0;
@@ -461,16 +319,17 @@ static const struct rtc_class_ops sh_rtc_ops = {
.set_time = sh_rtc_set_time,
.read_alarm = sh_rtc_read_alarm,
.set_alarm = sh_rtc_set_alarm,
- .proc = sh_rtc_proc,
.alarm_irq_enable = sh_rtc_alarm_irq_enable,
};
static int __init sh_rtc_probe(struct platform_device *pdev)
{
struct sh_rtc *rtc;
- struct resource *res;
+ struct resource *res, *req_res;
char clk_name[14];
int clk_id, ret;
+ unsigned int tmp;
+ resource_size_t regsize;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
@@ -478,34 +337,32 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
spin_lock_init(&rtc->lock);
- /* get periodic/carry/alarm irqs */
ret = platform_get_irq(pdev, 0);
if (unlikely(ret <= 0)) {
dev_err(&pdev->dev, "No IRQ resource\n");
return -ENOENT;
}
- rtc->periodic_irq = ret;
- rtc->carry_irq = platform_get_irq(pdev, 1);
- rtc->alarm_irq = platform_get_irq(pdev, 2);
+ if (!pdev->dev.of_node)
+ rtc->alarm_irq = platform_get_irq(pdev, 2);
+ else
+ rtc->alarm_irq = ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(res == NULL)) {
+ if (!res) {
dev_err(&pdev->dev, "No IO resource\n");
return -ENOENT;
}
- rtc->regsize = resource_size(res);
-
- rtc->res = devm_request_mem_region(&pdev->dev, res->start,
- rtc->regsize, pdev->name);
- if (unlikely(!rtc->res))
+ regsize = resource_size(res);
+ req_res = devm_request_mem_region(&pdev->dev, res->start, regsize, pdev->name);
+ if (!req_res)
return -EBUSY;
- rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, rtc->regsize);
- if (unlikely(!rtc->regbase))
+ rtc->regbase = devm_ioremap(&pdev->dev, req_res->start, regsize);
+ if (!rtc->regbase)
return -EINVAL;
if (!pdev->dev.of_node) {
@@ -515,8 +372,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
clk_id = 0;
snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id);
- } else
+ } else {
snprintf(clk_name, sizeof(clk_name), "fck");
+ }
rtc->clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(rtc->clk)) {
@@ -550,51 +408,19 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
}
#endif
- if (rtc->carry_irq <= 0) {
- /* register shared periodic/carry/alarm irq */
- ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
- sh_rtc_shared, 0, "sh-rtc", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request IRQ failed with %d, IRQ %d\n", ret,
- rtc->periodic_irq);
- goto err_unmap;
- }
- } else {
- /* register periodic/carry/alarm irqs */
- ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
- sh_rtc_periodic, 0, "sh-rtc period", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request period IRQ failed with %d, IRQ %d\n",
- ret, rtc->periodic_irq);
- goto err_unmap;
- }
-
- ret = devm_request_irq(&pdev->dev, rtc->carry_irq,
- sh_rtc_interrupt, 0, "sh-rtc carry", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request carry IRQ failed with %d, IRQ %d\n",
- ret, rtc->carry_irq);
- goto err_unmap;
- }
-
- ret = devm_request_irq(&pdev->dev, rtc->alarm_irq,
- sh_rtc_alarm, 0, "sh-rtc alarm", rtc);
- if (unlikely(ret)) {
- dev_err(&pdev->dev,
- "request alarm IRQ failed with %d, IRQ %d\n",
- ret, rtc->alarm_irq);
- goto err_unmap;
- }
+ ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "request alarm IRQ failed with %d, IRQ %d\n",
+ ret, rtc->alarm_irq);
+ goto err_unmap;
}
platform_set_drvdata(pdev, rtc);
/* everything disabled by default */
- sh_rtc_setaie(&pdev->dev, 0);
- sh_rtc_setcie(&pdev->dev, 0);
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~(RCR1_CIE | RCR1_AIE);
+ writeb(tmp, rtc->regbase + RCR1);
rtc->rtc_dev->ops = &sh_rtc_ops;
rtc->rtc_dev->max_user_freq = 256;
@@ -624,36 +450,27 @@ static void __exit sh_rtc_remove(struct platform_device *pdev)
{
struct sh_rtc *rtc = platform_get_drvdata(pdev);
- sh_rtc_setaie(&pdev->dev, 0);
- sh_rtc_setcie(&pdev->dev, 0);
+ sh_rtc_alarm_irq_enable(&pdev->dev, 0);
clk_disable(rtc->clk);
}
-static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
+static int __maybe_unused sh_rtc_suspend(struct device *dev)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
- irq_set_irq_wake(rtc->periodic_irq, enabled);
-
- if (rtc->carry_irq > 0) {
- irq_set_irq_wake(rtc->carry_irq, enabled);
- irq_set_irq_wake(rtc->alarm_irq, enabled);
- }
-}
-
-static int __maybe_unused sh_rtc_suspend(struct device *dev)
-{
if (device_may_wakeup(dev))
- sh_rtc_set_irq_wake(dev, 1);
+ irq_set_irq_wake(rtc->alarm_irq, 1);
return 0;
}
static int __maybe_unused sh_rtc_resume(struct device *dev)
{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+
if (device_may_wakeup(dev))
- sh_rtc_set_irq_wake(dev, 0);
+ irq_set_irq_wake(rtc->alarm_irq, 0);
return 0;
}
@@ -684,8 +501,8 @@ static struct platform_driver sh_rtc_platform_driver __refdata = {
module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
MODULE_DESCRIPTION("SuperH on-chip RTC driver");
-MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, "
- "Jamie Lenehan <lenehan@twibble.org>, "
- "Angelo Castello <angelo.castello@st.com>");
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_AUTHOR("Jamie Lenehan <lenehan@twibble.org>");
+MODULE_AUTHOR("Angelo Castello <angelo.castello@st.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 1b715db47160..ef8fb88aab48 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -1283,7 +1283,6 @@ static struct platform_driver stm32_rtc_driver = {
module_platform_driver(stm32_rtc_driver);
-MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 8c384c25dca1..0a5888b53d6d 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -93,7 +93,6 @@ enum {
#define AAC_NUM_MGT_FIB 8
#define AAC_NUM_IO_FIB (1024 - AAC_NUM_MGT_FIB)
-#define AAC_NUM_FIB (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB)
#define AAC_MAX_LUN 256
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index ffef61c4aa01..7d9a4dce236b 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -48,15 +48,7 @@
static int fib_map_alloc(struct aac_dev *dev)
{
- if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE)
- dev->max_cmd_size = AAC_MAX_NATIVE_SIZE;
- else
- dev->max_cmd_size = dev->max_fib_size;
- if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) {
- dev->max_cmd_size = AAC_MAX_NATIVE_SIZE;
- } else {
- dev->max_cmd_size = dev->max_fib_size;
- }
+ dev->max_cmd_size = AAC_MAX_NATIVE_SIZE;
dprintk((KERN_INFO
"allocate hardware fibs dma_alloc_coherent(%p, %d * (%d + %d), %p)\n",
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index a348df895dca..8ff679e67bbf 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -836,7 +836,7 @@ int __init scsi_init_devinfo(void)
goto out;
for (i = 0; scsi_static_device_list[i].vendor; i++) {
- error = scsi_dev_info_list_add(1 /* compatibile */,
+ error = scsi_dev_info_list_add(1 /* compatible */,
scsi_static_device_list[i].vendor,
scsi_static_device_list[i].model,
NULL,
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index 644b44d2aef2..18261cbd413b 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -745,7 +745,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+ reset = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index c8f64ec69344..b56210734caa 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -523,7 +523,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
- reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+ reset = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c
index 330078b1d50f..c6489e90b8b9 100644
--- a/drivers/spi/spi-pci1xxxx.c
+++ b/drivers/spi/spi-pci1xxxx.c
@@ -685,6 +685,17 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
return pci1xxxx_spi_isr_io(irq, dev);
}
+static irqreturn_t pci1xxxx_spi_shared_isr(int irq, void *dev)
+{
+ struct pci1xxxx_spi *par = dev;
+ u8 i = 0;
+
+ for (i = 0; i < par->total_hw_instances; i++)
+ pci1xxxx_spi_isr(irq, par->spi_int[i]);
+
+ return IRQ_HANDLED;
+}
+
static bool pci1xxxx_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
@@ -702,6 +713,7 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
struct device *dev = &pdev->dev;
struct pci1xxxx_spi *spi_bus;
struct spi_controller *spi_host;
+ int num_vector = 0;
u32 regval;
int ret;
@@ -749,9 +761,9 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
if (!spi_bus->reg_base)
return -EINVAL;
- ret = pci_alloc_irq_vectors(pdev, hw_inst_cnt, hw_inst_cnt,
- PCI_IRQ_ALL_TYPES);
- if (ret < 0) {
+ num_vector = pci_alloc_irq_vectors(pdev, 1, hw_inst_cnt,
+ PCI_IRQ_ALL_TYPES);
+ if (num_vector < 0) {
dev_err(&pdev->dev, "Error allocating MSI vectors\n");
return ret;
}
@@ -765,9 +777,15 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
spi_sub_ptr->irq = pci_irq_vector(pdev, 0);
- ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
- pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
- pci_name(pdev), spi_sub_ptr);
+ if (num_vector >= hw_inst_cnt)
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ else
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
+ pci1xxxx_spi_shared_isr,
+ PCI1XXXX_IRQ_FLAGS | IRQF_SHARED,
+ pci_name(pdev), spi_bus);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request irq : %d",
spi_sub_ptr->irq);
@@ -798,14 +816,16 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
regval &= ~SPI_INTR;
writel(regval, spi_bus->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
- spi_sub_ptr->irq = pci_irq_vector(pdev, iter);
- ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
- pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
- pci_name(pdev), spi_sub_ptr);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to request irq : %d",
- spi_sub_ptr->irq);
- return -ENODEV;
+ if (num_vector >= hw_inst_cnt) {
+ spi_sub_ptr->irq = pci_irq_vector(pdev, iter);
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request irq : %d",
+ spi_sub_ptr->irq);
+ return -ENODEV;
+ }
}
}
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
index 3f747fd61d19..77d9cc65477a 100644
--- a/drivers/spi/spi-qpic-snand.c
+++ b/drivers/spi/spi-qpic-snand.c
@@ -639,6 +639,20 @@ static int qcom_spi_check_error(struct qcom_nand_controller *snandc)
unsigned int stat;
stat = buffer & BS_CORRECTABLE_ERR_MSK;
+
+ /*
+ * The exact number of the corrected bits is
+ * unknown because the hardware only reports the
+ * number of the corrected bytes.
+ *
+ * Since we have no better solution at the moment,
+ * report that value as the number of bit errors
+ * despite that it is inaccurate in most cases.
+ */
+ if (stat && stat != ecc_cfg->strength)
+ dev_warn_once(snandc->dev,
+ "Warning: due to hw limitation, the reported number of the corrected bits may be inaccurate\n");
+
snandc->qspi->ecc_stats.corrected += stat;
max_bitflips = max(max_bitflips, stat);
}
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 737802046314..a80cf4047b86 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -11,9 +11,18 @@ menuconfig SPMI
if SPMI
+config SPMI_APPLE
+ tristate "Apple SoC SPMI Controller platform driver"
+ depends on ARCH_APPLE || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ SPMI controller present on many Apple SoCs, including the
+ t8103 (M1) and t600x (M1 Pro/Max).
+
config SPMI_HISI3670
tristate "Hisilicon 3670 SPMI Controller"
select IRQ_DOMAIN_HIERARCHY
+ depends on ARM64 || COMPILE_TEST
depends on HAS_IOMEM
help
If you say yes to this option, support will be included for the
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 7f152167bb05..38ac635645ba 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_SPMI) += spmi.o spmi-devres.o
+obj-$(CONFIG_SPMI_APPLE) += spmi-apple-controller.o
obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
obj-$(CONFIG_SPMI_MTK_PMIF) += spmi-mtk-pmif.o
diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c
new file mode 100644
index 000000000000..697b3e8bb023
--- /dev/null
+++ b/drivers/spmi/spmi-apple-controller.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple SoC SPMI device driver
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * Inspired by:
+ * OpenBSD support Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
+ * Correllium support Copyright (C) 2021 Corellium LLC
+ * hisi-spmi-controller.c
+ * spmi-pmic-arb.c Copyright (c) 2021, The Linux Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+
+/* SPMI Controller Registers */
+#define SPMI_STATUS_REG 0
+#define SPMI_CMD_REG 0x4
+#define SPMI_RSP_REG 0x8
+
+#define SPMI_RX_FIFO_EMPTY BIT(24)
+
+#define REG_POLL_INTERVAL_US 10000
+#define REG_POLL_TIMEOUT_US (REG_POLL_INTERVAL_US * 5)
+
+struct apple_spmi {
+ void __iomem *regs;
+};
+
+#define poll_reg(spmi, reg, val, cond) \
+ readl_poll_timeout((spmi)->regs + (reg), (val), (cond), \
+ REG_POLL_INTERVAL_US, REG_POLL_TIMEOUT_US)
+
+static inline u32 apple_spmi_pack_cmd(u8 opc, u8 sid, u16 saddr, size_t len)
+{
+ return opc | sid << 8 | saddr << 16 | (len - 1) | (1 << 15);
+}
+
+/* Wait for Rx FIFO to have something */
+static int apple_spmi_wait_rx_not_empty(struct spmi_controller *ctrl)
+{
+ struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl);
+ int ret;
+ u32 status;
+
+ ret = poll_reg(spmi, SPMI_STATUS_REG, status, !(status & SPMI_RX_FIFO_EMPTY));
+ if (ret) {
+ dev_err(&ctrl->dev,
+ "failed to wait for RX FIFO not empty\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+ u16 saddr, u8 *buf, size_t len)
+{
+ struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl);
+ u32 spmi_cmd = apple_spmi_pack_cmd(opc, sid, saddr, len);
+ u32 rsp;
+ size_t len_read = 0;
+ u8 i;
+ int ret;
+
+ writel(spmi_cmd, spmi->regs + SPMI_CMD_REG);
+
+ ret = apple_spmi_wait_rx_not_empty(ctrl);
+ if (ret)
+ return ret;
+
+ /* Discard SPMI reply status */
+ readl(spmi->regs + SPMI_RSP_REG);
+
+ /* Read SPMI data reply */
+ while (len_read < len) {
+ rsp = readl(spmi->regs + SPMI_RSP_REG);
+ i = 0;
+ while ((len_read < len) && (i < 4)) {
+ buf[len_read++] = ((0xff << (8 * i)) & rsp) >> (8 * i);
+ i += 1;
+ }
+ }
+
+ return 0;
+}
+
+static int spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
+ u16 saddr, const u8 *buf, size_t len)
+{
+ struct apple_spmi *spmi = spmi_controller_get_drvdata(ctrl);
+ u32 spmi_cmd = apple_spmi_pack_cmd(opc, sid, saddr, len);
+ size_t i = 0, j;
+ int ret;
+
+ writel(spmi_cmd, spmi->regs + SPMI_CMD_REG);
+
+ while (i < len) {
+ j = 0;
+ spmi_cmd = 0;
+ while ((j < 4) & (i < len))
+ spmi_cmd |= buf[i++] << (j++ * 8);
+
+ writel(spmi_cmd, spmi->regs + SPMI_CMD_REG);
+ }
+
+ ret = apple_spmi_wait_rx_not_empty(ctrl);
+ if (ret)
+ return ret;
+
+ /* Discard */
+ readl(spmi->regs + SPMI_RSP_REG);
+
+ return 0;
+}
+
+static int apple_spmi_probe(struct platform_device *pdev)
+{
+ struct apple_spmi *spmi;
+ struct spmi_controller *ctrl;
+ int ret;
+
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*spmi));
+ if (IS_ERR(ctrl))
+ return -ENOMEM;
+
+ spmi = spmi_controller_get_drvdata(ctrl);
+
+ spmi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(spmi->regs))
+ return PTR_ERR(spmi->regs);
+
+ ctrl->dev.of_node = pdev->dev.of_node;
+
+ ctrl->read_cmd = spmi_read_cmd;
+ ctrl->write_cmd = spmi_write_cmd;
+
+ ret = devm_spmi_controller_add(&pdev->dev, ctrl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "spmi_controller_add failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id apple_spmi_match_table[] = {
+ { .compatible = "apple,spmi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_spmi_match_table);
+
+static struct platform_driver apple_spmi_driver = {
+ .probe = apple_spmi_probe,
+ .driver = {
+ .name = "apple-spmi",
+ .of_match_table = apple_spmi_match_table,
+ },
+};
+module_platform_driver(apple_spmi_driver);
+
+MODULE_AUTHOR("Jean-Francois Bortolotti <jeff@borto.fr>");
+MODULE_DESCRIPTION("Apple SoC SPMI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 5c058db21821..91581974ef84 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1737,7 +1737,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
dev_dbg(&pdev->dev, "adding irq domain for bus %d\n", bus_index);
- bus->domain = irq_domain_add_tree(node, &pmic_arb_irq_domain_ops, bus);
+ bus->domain = irq_domain_create_tree(of_fwnode_handle(node), &pmic_arb_irq_domain_ops, bus);
if (!bus->domain) {
dev_err(&pdev->dev, "unable to create irq_domain\n");
return -ENOMEM;
diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
index dcf6a70455cc..c2655768209a 100644
--- a/drivers/staging/fbtft/Kconfig
+++ b/drivers/staging/fbtft/Kconfig
@@ -8,160 +8,136 @@ menuconfig FB_TFT
select FB_BACKLIGHT
select FB_SYSMEM_HELPERS_DEFERRED
+if FB_TFT
+
config FB_TFT_AGM1264K_FL
tristate "FB driver for the AGM1264K-FL LCD display"
- depends on FB_TFT
help
Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatible chips)
config FB_TFT_BD663474
tristate "FB driver for the BD663474 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for BD663474
config FB_TFT_HX8340BN
tristate "FB driver for the HX8340BN LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for HX8340BN
config FB_TFT_HX8347D
tristate "FB driver for the HX8347D LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for HX8347D
config FB_TFT_HX8353D
tristate "FB driver for the HX8353D LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for HX8353D
config FB_TFT_HX8357D
tristate "FB driver for the HX8357D LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for HX8357D
config FB_TFT_ILI9163
tristate "FB driver for the ILI9163 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9163
config FB_TFT_ILI9320
tristate "FB driver for the ILI9320 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9320
config FB_TFT_ILI9325
tristate "FB driver for the ILI9325 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9325
config FB_TFT_ILI9340
tristate "FB driver for the ILI9340 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9340
config FB_TFT_ILI9341
tristate "FB driver for the ILI9341 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9341
config FB_TFT_ILI9481
tristate "FB driver for the ILI9481 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9481
config FB_TFT_ILI9486
tristate "FB driver for the ILI9486 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ILI9486
config FB_TFT_PCD8544
tristate "FB driver for the PCD8544 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for PCD8544
config FB_TFT_RA8875
tristate "FB driver for the RA8875 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for RA8875
config FB_TFT_S6D02A1
tristate "FB driver for the S6D02A1 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for S6D02A1
config FB_TFT_S6D1121
tristate "FB driver for the S6D1211 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for S6D1121
config FB_TFT_SEPS525
tristate "FB driver for the SEPS525 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for SEPS525
Say Y if you have such a display that utilizes this controller.
config FB_TFT_SH1106
tristate "FB driver for the SH1106 OLED Controller"
- depends on FB_TFT
help
Framebuffer support for SH1106
config FB_TFT_SSD1289
tristate "FB driver for the SSD1289 LCD Controller"
- depends on FB_TFT
help
Framebuffer support for SSD1289
config FB_TFT_SSD1305
tristate "FB driver for the SSD1305 OLED Controller"
- depends on FB_TFT
help
Framebuffer support for SSD1305
config FB_TFT_SSD1306
tristate "FB driver for the SSD1306 OLED Controller"
- depends on FB_TFT
help
Framebuffer support for SSD1306
config FB_TFT_SSD1331
tristate "FB driver for the SSD1331 LCD Controller"
- depends on FB_TFT
help
Framebuffer support for SSD1331
config FB_TFT_SSD1351
tristate "FB driver for the SSD1351 LCD Controller"
- depends on FB_TFT
help
Framebuffer support for SSD1351
config FB_TFT_ST7735R
tristate "FB driver for the ST7735R LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for ST7735R
config FB_TFT_ST7789V
tristate "FB driver for the ST7789V LCD Controller"
- depends on FB_TFT
help
This enables generic framebuffer support for the Sitronix ST7789V
display controller. The controller is intended for small color
@@ -171,30 +147,27 @@ config FB_TFT_ST7789V
config FB_TFT_TINYLCD
tristate "FB driver for tinylcd.com display"
- depends on FB_TFT
help
Custom Framebuffer support for tinylcd.com display
config FB_TFT_TLS8204
tristate "FB driver for the TLS8204 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for TLS8204
config FB_TFT_UC1611
tristate "FB driver for the UC1611 LCD controller"
- depends on FB_TFT
help
Generic Framebuffer support for UC1611
config FB_TFT_UC1701
tristate "FB driver for the UC1701 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for UC1701
config FB_TFT_UPD161704
tristate "FB driver for the uPD161704 LCD Controller"
- depends on FB_TFT
help
Generic Framebuffer support for uPD161704
+
+endif
diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c
index 445b9380ff98..94bbb3b6576d 100644
--- a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c
+++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c
@@ -27,10 +27,10 @@ MODULE_DESCRIPTION("GPIB driver for Agilent 82350b");
static int read_transfer_counter(struct agilent_82350b_priv *a_priv);
static unsigned short read_and_clear_event_status(struct gpib_board *board);
static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count);
-static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82350b_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
-static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82350b_accel_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
@@ -39,7 +39,7 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer,
int retval = 0;
unsigned short event_status;
int i, num_fifo_bytes;
- //hardware doesn't support checking for end-of-string character when using fifo
+ /* hardware doesn't support checking for end-of-string character when using fifo */
if (tms_priv->eos_flags & REOS)
return tms9914_read(board, tms_priv, buffer, length, end, bytes_read);
@@ -50,9 +50,9 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer,
*bytes_read = 0;
if (length == 0)
return 0;
- //disable fifo for the moment
+ /* disable fifo for the moment */
writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
- // handle corner case of board not in holdoff and one byte might slip in early
+ /* handle corner case of board not in holdoff and one byte might slip in early */
if (tms_priv->holdoff_active == 0 && length > 1) {
size_t num_bytes;
@@ -67,7 +67,8 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer,
tms9914_release_holdoff(tms_priv);
i = 0;
num_fifo_bytes = length - 1;
- write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0); // disable BI interrupts
+ /* disable BI interrupts */
+ write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0);
while (i < num_fifo_bytes && *end == 0) {
int block_size;
int j;
@@ -111,17 +112,18 @@ static int agilent_82350b_accel_read(struct gpib_board *board, uint8_t *buffer,
break;
}
}
- write_byte(tms_priv, tms_priv->imr0_bits, IMR0); // re-enable BI interrupts
+ /* re-enable BI interrupts */
+ write_byte(tms_priv, tms_priv->imr0_bits, IMR0);
*bytes_read += i;
buffer += i;
length -= i;
writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
if (retval < 0)
return retval;
- // read last bytes if we havn't received an END yet
+ /* read last bytes if we havn't received an END yet */
if (*end == 0) {
size_t num_bytes;
- // try to make sure we holdoff after last byte read
+ /* try to make sure we holdoff after last byte read */
retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes);
*bytes_read += num_bytes;
if (retval < 0)
@@ -145,7 +147,7 @@ static int translate_wait_return_value(struct gpib_board *board, int retval)
return 0;
}
-static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82350b_accel_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi,
size_t *bytes_written)
{
@@ -169,7 +171,7 @@ static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer,
event_status = read_and_clear_event_status(board);
#ifdef EXPERIMENTAL
- // wait for previous BO to complete if any
+ /* wait for previous BO to complete if any */
retval = wait_event_interruptible(board->wait,
test_bit(DEV_CLEAR_BN, &tms_priv->state) ||
test_bit(WRITE_READY_BN, &tms_priv->state) ||
@@ -192,7 +194,7 @@ static int agilent_82350b_accel_write(struct gpib_board *board, uint8_t *buffer,
block_size = min(fifotransferlength - i, agilent_82350b_fifo_size);
set_transfer_counter(a_priv, block_size);
for (j = 0; j < block_size; ++j, ++i) {
- // load data into board's sram
+ /* load data into board's sram */
writeb(buffer[i], a_priv->sram_base + j);
}
writeb(ENABLE_TI_TO_SRAM, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG);
@@ -262,7 +264,7 @@ static irqreturn_t agilent_82350b_interrupt(int irq, void *arg)
tms9914_interrupt_have_status(board, &a_priv->tms9914_priv, tms9914_status1,
tms9914_status2);
}
-//write-clear status bits
+ /* write-clear status bits */
if (event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT)) {
writeb(event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT),
a_priv->gpib_base + EVENT_STATUS_REG);
@@ -292,12 +294,12 @@ static void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count)
writeb(complement & 0xff, a_priv->gpib_base + XFER_COUNT_LO_REG);
writeb((complement >> 8) & 0xff, a_priv->gpib_base + XFER_COUNT_MID_REG);
- //I don't think the hi count reg is even used, but oh well
+ /* I don't think the hi count reg is even used, but oh well */
writeb((complement >> 16) & 0xf, a_priv->gpib_base + XFER_COUNT_HI_REG);
}
-// wrappers for interface functions
-static int agilent_82350b_read(struct gpib_board *board, uint8_t *buffer,
+/* wrappers for interface functions */
+static int agilent_82350b_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct agilent_82350b_priv *priv = board->private_data;
@@ -305,7 +307,7 @@ static int agilent_82350b_read(struct gpib_board *board, uint8_t *buffer,
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
-static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82350b_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
@@ -314,7 +316,7 @@ static int agilent_82350b_write(struct gpib_board *board, uint8_t *buffer,
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
-static int agilent_82350b_command(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82350b_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
@@ -339,9 +341,7 @@ static int agilent_82350b_go_to_standby(struct gpib_board *board)
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
-static void agilent_82350b_request_system_control(struct gpib_board *board,
- int request_control)
-
+static int agilent_82350b_request_system_control(struct gpib_board *board, int request_control)
{
struct agilent_82350b_priv *a_priv = board->private_data;
@@ -355,7 +355,7 @@ static void agilent_82350b_request_system_control(struct gpib_board *board,
writeb(0, a_priv->gpib_base + INTERNAL_CONFIG_REG);
}
writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG);
- tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control);
+ return tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control);
}
static void agilent_82350b_interface_clear(struct gpib_board *board, int assert)
@@ -373,7 +373,7 @@ static void agilent_82350b_remote_enable(struct gpib_board *board, int enable)
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
-static int agilent_82350b_enable_eos(struct gpib_board *board, uint8_t eos_byte,
+static int agilent_82350b_enable_eos(struct gpib_board *board, u8 eos_byte,
int compare_8_bits)
{
struct agilent_82350b_priv *priv = board->private_data;
@@ -412,7 +412,7 @@ static int agilent_82350b_secondary_address(struct gpib_board *board,
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
-static int agilent_82350b_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int agilent_82350b_parallel_poll(struct gpib_board *board, u8 *result)
{
struct agilent_82350b_priv *priv = board->private_data;
@@ -420,7 +420,7 @@ static int agilent_82350b_parallel_poll(struct gpib_board *board, uint8_t *resul
}
static void agilent_82350b_parallel_poll_configure(struct gpib_board *board,
- uint8_t config)
+ u8 config)
{
struct agilent_82350b_priv *priv = board->private_data;
@@ -434,14 +434,14 @@ static void agilent_82350b_parallel_poll_response(struct gpib_board *board, int
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
-static void agilent_82350b_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void agilent_82350b_serial_poll_response(struct gpib_board *board, u8 status)
{
struct agilent_82350b_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
-static uint8_t agilent_82350b_serial_poll_status(struct gpib_board *board)
+static u8 agilent_82350b_serial_poll_status(struct gpib_board *board)
{
struct agilent_82350b_priv *priv = board->private_data;
@@ -492,7 +492,7 @@ static void agilent_82350b_free_private(struct gpib_board *board)
}
static int init_82350a_hardware(struct gpib_board *board,
- const gpib_board_config_t *config)
+ const struct gpib_board_config *config)
{
struct agilent_82350b_priv *a_priv = board->private_data;
static const unsigned int firmware_length = 5302;
@@ -511,18 +511,18 @@ static int init_82350a_hardware(struct gpib_board *board,
PLX9050_PCI_RETRY_DELAY_BITS(64) |
PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT;
-// load borg data
+ /* load borg data */
borg_status = readb(a_priv->borg_base);
if ((borg_status & BORG_DONE_BIT))
return 0;
- // need to programme borg
+ /* need to programme borg */
if (!config->init_data || config->init_data_length != firmware_length) {
dev_err(board->gpib_dev, "the 82350A board requires firmware after powering on.\n");
return -EIO;
}
dev_dbg(board->gpib_dev, "Loading firmware...\n");
- // tickle the borg
+ /* tickle the borg */
writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT,
a_priv->plx_base + PLX9050_CNTRL_REG);
usleep_range(1000, 2000);
@@ -563,7 +563,7 @@ static int test_sram(struct gpib_board *board)
struct agilent_82350b_priv *a_priv = board->private_data;
unsigned int i;
const unsigned int sram_length = pci_resource_len(a_priv->pci_device, SRAM_82350A_REGION);
- // test SRAM
+ /* test SRAM */
const unsigned int byte_mask = 0xff;
for (i = 0; i < sram_length; ++i) {
@@ -587,7 +587,7 @@ static int test_sram(struct gpib_board *board)
}
static int agilent_82350b_generic_attach(struct gpib_board *board,
- const gpib_board_config_t *config,
+ const struct gpib_board_config *config,
int use_fifos)
{
@@ -606,7 +606,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board,
tms_priv->write_byte = tms9914_iomem_write_byte;
tms_priv->offset = 1;
- // find board
+ /* find board */
a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT,
PCI_DEVICE_ID_82350B, NULL);
if (a_priv->pci_device) {
@@ -702,7 +702,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board,
writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG);
if (a_priv->model == MODEL_82350A) {
- // enable PCI interrupts for 82350a
+ /* enable PCI interrupts for 82350a */
writel(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR2_POLARITY_BIT |
PLX9050_PCI_INTR_EN_BIT,
a_priv->plx_base + PLX9050_INTCSR_REG);
@@ -713,7 +713,7 @@ static int agilent_82350b_generic_attach(struct gpib_board *board,
a_priv->gpib_base + EVENT_ENABLE_REG);
writeb(ENABLE_TERM_COUNT_INTERRUPT_BIT | ENABLE_BUFFER_END_INTERRUPT_BIT |
ENABLE_TMS9914_INTERRUPTS_BIT, a_priv->gpib_base + INTERRUPT_ENABLE_REG);
- //write-clear event status bits
+ /* write-clear event status bits */
writeb(BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT,
a_priv->gpib_base + EVENT_STATUS_REG);
} else {
@@ -730,13 +730,13 @@ static int agilent_82350b_generic_attach(struct gpib_board *board,
}
static int agilent_82350b_unaccel_attach(struct gpib_board *board,
- const gpib_board_config_t *config)
+ const struct gpib_board_config *config)
{
return agilent_82350b_generic_attach(board, config, 0);
}
static int agilent_82350b_accel_attach(struct gpib_board *board,
- const gpib_board_config_t *config)
+ const struct gpib_board_config *config)
{
return agilent_82350b_generic_attach(board, config, 1);
}
@@ -747,7 +747,7 @@ static void agilent_82350b_detach(struct gpib_board *board)
struct tms9914_priv *tms_priv;
if (a_priv) {
- if (a_priv->plx_base) // disable interrupts
+ if (a_priv->plx_base) /* disable interrupts */
writel(0, a_priv->plx_base + PLX9050_INTCSR_REG);
tms_priv = &a_priv->tms9914_priv;
@@ -773,7 +773,7 @@ static void agilent_82350b_detach(struct gpib_board *board)
agilent_82350b_free_private(board);
}
-static gpib_interface_t agilent_82350b_unaccel_interface = {
+static struct gpib_interface agilent_82350b_unaccel_interface = {
.name = "agilent_82350b_unaccel",
.attach = agilent_82350b_unaccel_attach,
.detach = agilent_82350b_detach,
@@ -790,7 +790,7 @@ static gpib_interface_t agilent_82350b_unaccel_interface = {
.parallel_poll = agilent_82350b_parallel_poll,
.parallel_poll_configure = agilent_82350b_parallel_poll_configure,
.parallel_poll_response = agilent_82350b_parallel_poll_response,
- .local_parallel_poll_mode = NULL, // XXX
+ .local_parallel_poll_mode = NULL, /* XXX */
.line_status = agilent_82350b_line_status,
.update_status = agilent_82350b_update_status,
.primary_address = agilent_82350b_primary_address,
@@ -801,7 +801,7 @@ static gpib_interface_t agilent_82350b_unaccel_interface = {
.return_to_local = agilent_82350b_return_to_local,
};
-static gpib_interface_t agilent_82350b_interface = {
+static struct gpib_interface agilent_82350b_interface = {
.name = "agilent_82350b",
.attach = agilent_82350b_accel_attach,
.detach = agilent_82350b_detach,
@@ -818,7 +818,7 @@ static gpib_interface_t agilent_82350b_interface = {
.parallel_poll = agilent_82350b_parallel_poll,
.parallel_poll_configure = agilent_82350b_parallel_poll_configure,
.parallel_poll_response = agilent_82350b_parallel_poll_response,
- .local_parallel_poll_mode = NULL, // XXX
+ .local_parallel_poll_mode = NULL, /* XXX */
.line_status = agilent_82350b_line_status,
.update_status = agilent_82350b_update_status,
.primary_address = agilent_82350b_primary_address,
diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.h b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h
index 1573230c619d..ef841957297f 100644
--- a/drivers/staging/gpib/agilent_82350b/agilent_82350b.h
+++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h
@@ -41,11 +41,11 @@ enum board_model {
MODEL_82351A
};
-// struct which defines private_data for board
+/* struct which defines private_data for board */
struct agilent_82350b_priv {
struct tms9914_priv tms9914_priv;
struct pci_dev *pci_device;
- void __iomem *plx_base; //82350a only
+ void __iomem *plx_base; /* 82350a only */
void __iomem *gpib_base;
void __iomem *sram_base;
void __iomem *misc_base;
@@ -57,12 +57,12 @@ struct agilent_82350b_priv {
bool using_fifos;
};
-//registers
+/* registers */
enum agilent_82350b_gpib_registers
{
CARD_MODE_REG = 0x1,
- CONFIG_DATA_REG = 0x2, // 82350A specific
+ CONFIG_DATA_REG = 0x2, /* 82350A specific */
INTERRUPT_ENABLE_REG = 0x3,
EVENT_STATUS_REG = 0x4,
EVENT_ENABLE_REG = 0x5,
@@ -76,8 +76,8 @@ enum agilent_82350b_gpib_registers
XFER_COUNT_HI_REG = 0xe,
TMS9914_BASE_REG = 0x10,
INTERNAL_CONFIG_REG = 0x18,
- IMR0_READ_REG = 0x19, //read
- T1_DELAY_REG = 0x19, // write
+ IMR0_READ_REG = 0x19, /* read */
+ T1_DELAY_REG = 0x19, /* write */
IMR1_READ_REG = 0x1a,
ADR_READ_REG = 0x1b,
SPMR_READ_REG = 0x1c,
@@ -89,7 +89,7 @@ enum agilent_82350b_gpib_registers
enum card_mode_bits
{
- ACTIVE_CONTROLLER_BIT = 0x2, // read-only
+ ACTIVE_CONTROLLER_BIT = 0x2, /* read-only */
CM_SYSTEM_CONTROLLER_BIT = 0x8,
ENABLE_BUS_MONITOR_BIT = 0x10,
ENABLE_PCI_IRQ_BIT = 0x20,
@@ -115,15 +115,15 @@ enum event_status_bits
{
TMS9914_IRQ_STATUS_BIT = 0x1,
IRQ_STATUS_BIT = 0x2,
- BUFFER_END_STATUS_BIT = 0x10, // write-clear
- TERM_COUNT_STATUS_BIT = 0x20, // write-clear
+ BUFFER_END_STATUS_BIT = 0x10, /* write-clear */
+ TERM_COUNT_STATUS_BIT = 0x20, /* write-clear */
};
enum stream_status_bits
{
- HALTED_STATUS_BIT = 0x1, //read
- RESTART_STREAM_BIT = 0x1, //write
+ HALTED_STATUS_BIT = 0x1, /* read */
+ RESTART_STREAM_BIT = 0x1, /* write */
};
enum internal_config_bits
@@ -135,9 +135,9 @@ enum internal_config_bits
enum sram_access_control_bits
{
- DIRECTION_GPIB_TO_HOST = 0x20, // transfer direction
- ENABLE_TI_TO_SRAM = 0x40, // enable fifo
- ENABLE_FAST_TALKER = 0x80 // added for 82350A (not used)
+ DIRECTION_GPIB_TO_HOST = 0x20, /* transfer direction */
+ ENABLE_TI_TO_SRAM = 0x40, /* enable fifo */
+ ENABLE_FAST_TALKER = 0x80 /* added for 82350A (not used) */
};
enum borg_bits
diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c
index da229965d98e..454d46b8b677 100644
--- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c
+++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c
@@ -26,7 +26,7 @@ static struct usb_interface *agilent_82357a_driver_interfaces[MAX_NUM_82357A_INT
static DEFINE_MUTEX(agilent_82357a_hotplug_lock); // protect board insertion and removal
static unsigned int agilent_82357a_update_status(struct gpib_board *board,
- unsigned int clear_mask);
+ unsigned int clear_mask);
static int agilent_82357a_take_control_internal(struct gpib_board *board, int synchronous);
@@ -34,7 +34,7 @@ static void agilent_82357a_bulk_complete(struct urb *urb)
{
struct agilent_82357a_urb_ctx *context = urb->context;
- up(&context->complete);
+ complete(&context->complete);
}
static void agilent_82357a_timeout_handler(struct timer_list *t)
@@ -43,7 +43,7 @@ static void agilent_82357a_timeout_handler(struct timer_list *t)
struct agilent_82357a_urb_ctx *context = &a_priv->context;
context->timed_out = 1;
- up(&context->complete);
+ complete(&context->complete);
}
static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void *data,
@@ -74,7 +74,7 @@ static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void
}
usb_dev = interface_to_usbdev(a_priv->bus_interface);
out_pipe = usb_sndbulkpipe(usb_dev, a_priv->bulk_out_endpoint);
- sema_init(&context->complete, 0);
+ init_completion(&context->complete);
context->timed_out = 0;
usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, out_pipe, data, data_length,
&agilent_82357a_bulk_complete, context);
@@ -89,7 +89,7 @@ static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void
goto cleanup;
}
mutex_unlock(&a_priv->bulk_alloc_lock);
- if (down_interruptible(&context->complete)) {
+ if (wait_for_completion_interruptible(&context->complete)) {
retval = -ERESTARTSYS;
goto cleanup;
}
@@ -142,7 +142,7 @@ static int agilent_82357a_receive_bulk_msg(struct agilent_82357a_priv *a_priv, v
}
usb_dev = interface_to_usbdev(a_priv->bus_interface);
in_pipe = usb_rcvbulkpipe(usb_dev, AGILENT_82357_BULK_IN_ENDPOINT);
- sema_init(&context->complete, 0);
+ init_completion(&context->complete);
context->timed_out = 0;
usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, in_pipe, data, data_length,
&agilent_82357a_bulk_complete, context);
@@ -157,7 +157,7 @@ static int agilent_82357a_receive_bulk_msg(struct agilent_82357a_priv *a_priv, v
goto cleanup;
}
mutex_unlock(&a_priv->bulk_alloc_lock);
- if (down_interruptible(&context->complete)) {
+ if (wait_for_completion_interruptible(&context->complete)) {
retval = -ERESTARTSYS;
goto cleanup;
}
@@ -420,10 +420,10 @@ cleanup:
}
// interface functions
-int agilent_82357a_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+int agilent_82357a_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written);
-static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int agilent_82357a_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *nbytes)
{
int retval;
@@ -524,9 +524,10 @@ static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t
}
kfree(in_data);
- /* Fix for a bug in 9914A that does not return the contents of ADSR
- * when the board is in listener active state and ATN is not asserted.
- * Set ATN here to obtain a valid board level ibsta
+ /*
+ * Fix for a bug in 9914A that does not return the contents of ADSR
+ * when the board is in listener active state and ATN is not asserted.
+ * Set ATN here to obtain a valid board level ibsta
*/
agilent_82357a_take_control_internal(board, 0);
@@ -535,7 +536,7 @@ static int agilent_82357a_read(struct gpib_board *board, uint8_t *buffer, size_t
}
static ssize_t agilent_82357a_generic_write(struct gpib_board *board,
- uint8_t *buffer, size_t length,
+ u8 *buffer, size_t length,
int send_commands, int send_eoi,
size_t *bytes_written)
{
@@ -675,13 +676,13 @@ static ssize_t agilent_82357a_generic_write(struct gpib_board *board,
return 0;
}
-static int agilent_82357a_write(struct gpib_board *board, uint8_t *buffer,
+static int agilent_82357a_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
return agilent_82357a_generic_write(board, buffer, length, 0, send_eoi, bytes_written);
}
-int agilent_82357a_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+int agilent_82357a_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
return agilent_82357a_generic_write(board, buffer, length, 1, 0, bytes_written);
@@ -715,9 +716,10 @@ static int agilent_82357a_take_control(struct gpib_board *board, int synchronous
if (!a_priv->bus_interface)
return -ENODEV;
-/* It looks like the 9914 does not handle tcs properly.
- * See comment above tms9914_take_control_workaround() in
- * drivers/gpib/tms9914/tms9914_aux.c
+/*
+ * It looks like the 9914 does not handle tcs properly.
+ * See comment above tms9914_take_control_workaround() in
+ * drivers/gpib/tms9914/tms9914_aux.c
*/
if (synchronous)
return -ETIMEDOUT;
@@ -754,9 +756,7 @@ static int agilent_82357a_go_to_standby(struct gpib_board *board)
return 0;
}
-//FIXME should change prototype to return int
-static void agilent_82357a_request_system_control(struct gpib_board *board,
- int request_control)
+static int agilent_82357a_request_system_control(struct gpib_board *board, int request_control)
{
struct agilent_82357a_priv *a_priv = board->private_data;
struct usb_device *usb_dev;
@@ -765,7 +765,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board,
int i = 0;
if (!a_priv->bus_interface)
- return; // -ENODEV;
+ return -ENODEV;
usb_dev = interface_to_usbdev(a_priv->bus_interface);
/* 82357B needs bit to be set in 9914 AUXCR register */
@@ -774,9 +774,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board,
writes[i].value = AUX_RQC;
a_priv->hw_control_bits |= SYSTEM_CONTROLLER;
} else {
- writes[i].value = AUX_RLC;
- a_priv->is_cic = 0;
- a_priv->hw_control_bits &= ~SYSTEM_CONTROLLER;
+ return -EINVAL;
}
++i;
writes[i].address = HW_CONTROL;
@@ -785,7 +783,7 @@ static void agilent_82357a_request_system_control(struct gpib_board *board,
retval = agilent_82357a_write_registers(a_priv, writes, i);
if (retval)
dev_err(&usb_dev->dev, "write_registers() returned error\n");
- return;// retval;
+ return retval;
}
static void agilent_82357a_interface_clear(struct gpib_board *board, int assert)
@@ -832,7 +830,7 @@ static void agilent_82357a_remote_enable(struct gpib_board *board, int enable)
return;// 0;
}
-static int agilent_82357a_enable_eos(struct gpib_board *board, uint8_t eos_byte,
+static int agilent_82357a_enable_eos(struct gpib_board *board, u8 eos_byte,
int compare_8_bits)
{
struct agilent_82357a_priv *a_priv = board->private_data;
@@ -946,7 +944,7 @@ static int agilent_82357a_secondary_address(struct gpib_board *board,
return 0;
}
-static int agilent_82357a_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int agilent_82357a_parallel_poll(struct gpib_board *board, u8 *result)
{
struct agilent_82357a_priv *a_priv = board->private_data;
struct usb_device *usb_dev;
@@ -988,7 +986,7 @@ static int agilent_82357a_parallel_poll(struct gpib_board *board, uint8_t *resul
return 0;
}
-static void agilent_82357a_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void agilent_82357a_parallel_poll_configure(struct gpib_board *board, u8 config)
{
//board can only be system controller
return;// 0;
@@ -1000,13 +998,13 @@ static void agilent_82357a_parallel_poll_response(struct gpib_board *board, int
return;// 0;
}
-static void agilent_82357a_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void agilent_82357a_serial_poll_response(struct gpib_board *board, u8 status)
{
//board can only be system controller
return;// 0;
}
-static uint8_t agilent_82357a_serial_poll_status(struct gpib_board *board)
+static u8 agilent_82357a_serial_poll_status(struct gpib_board *board)
{
//board can only be system controller
return 0;
@@ -1292,7 +1290,7 @@ static int agilent_82357a_init(struct gpib_board *board)
}
static inline int agilent_82357a_device_match(struct usb_interface *interface,
- const gpib_board_config_t *config)
+ const struct gpib_board_config *config)
{
struct usb_device * const usbdev = interface_to_usbdev(interface);
@@ -1305,7 +1303,7 @@ static inline int agilent_82357a_device_match(struct usb_interface *interface,
return 1;
}
-static int agilent_82357a_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int agilent_82357a_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int retval;
int i;
@@ -1432,7 +1430,7 @@ static void agilent_82357a_detach(struct gpib_board *board)
mutex_unlock(&agilent_82357a_hotplug_lock);
}
-static gpib_interface_t agilent_82357a_gpib_interface = {
+static struct gpib_interface agilent_82357a_gpib_interface = {
.name = "agilent_82357a",
.attach = agilent_82357a_attach,
.detach = agilent_82357a_detach,
@@ -1591,7 +1589,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface)
{
struct usb_device *usb_dev = interface_to_usbdev(interface);
struct gpib_board *board;
- int i, retval;
+ int i, retval = 0;
mutex_lock(&agilent_82357a_hotplug_lock);
@@ -1602,8 +1600,10 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface)
break;
}
}
- if (i == MAX_NUM_82357A_INTERFACES)
+ if (i == MAX_NUM_82357A_INTERFACES) {
+ retval = -ENOENT;
goto resume_exit;
+ }
struct agilent_82357a_priv *a_priv = board->private_data;
@@ -1626,7 +1626,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface)
return retval;
}
// set/unset system controller
- agilent_82357a_request_system_control(board, board->master);
+ retval = agilent_82357a_request_system_control(board, board->master);
// toggle ifc if master
if (board->master) {
agilent_82357a_interface_clear(board, 1);
@@ -1644,7 +1644,7 @@ static int agilent_82357a_driver_resume(struct usb_interface *interface)
resume_exit:
mutex_unlock(&agilent_82357a_hotplug_lock);
- return 0;
+ return retval;
}
static struct usb_driver agilent_82357a_bus_driver = {
diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h
index cdbc3ec5d8bd..23aa4799eb86 100644
--- a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h
+++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h
@@ -6,7 +6,7 @@
#include <linux/kernel.h>
#include <linux/mutex.h>
-#include <linux/semaphore.h>
+#include <linux/completion.h>
#include <linux/usb.h>
#include <linux/timer.h>
#include <linux/compiler_attributes.h>
@@ -115,7 +115,7 @@ enum xfer_abort_type {
#define INTERRUPT_BUF_LEN 8
struct agilent_82357a_urb_ctx {
- struct semaphore complete;
+ struct completion complete;
unsigned timed_out : 1;
};
diff --git a/drivers/staging/gpib/cb7210/cb7210.c b/drivers/staging/gpib/cb7210/cb7210.c
index 6b22a33a8c4f..298ed306189d 100644
--- a/drivers/staging/gpib/cb7210/cb7210.c
+++ b/drivers/staging/gpib/cb7210/cb7210.c
@@ -27,7 +27,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver Measurement Computing boards using cb7210.2 and cbi488.2");
-static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int cb7210_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read);
static inline int have_fifo_word(const struct cb7210_priv *cb_priv)
@@ -76,7 +76,7 @@ static inline void input_fifo_enable(struct gpib_board *board, int enable)
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, uint8_t *buffer,
+static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
@@ -170,7 +170,7 @@ static int fifo_read(struct gpib_board *board, struct cb7210_priv *cb_priv, uint
return retval;
}
-static int cb7210_accel_read(struct gpib_board *board, uint8_t *buffer,
+static int cb7210_accel_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval;
@@ -264,7 +264,7 @@ static inline void output_fifo_enable(struct gpib_board *board, int enable)
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static int fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fifo_write(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
size_t count = 0;
@@ -350,7 +350,7 @@ static int fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length,
return retval;
}
-static int cb7210_accel_write(struct gpib_board *board, uint8_t *buffer,
+static int cb7210_accel_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
struct cb7210_priv *cb_priv = board->private_data;
@@ -533,14 +533,14 @@ static irqreturn_t cb7210_interrupt(int irq, void *arg)
return cb7210_internal_interrupt(arg);
}
-static int cb_pci_attach(struct gpib_board *board, const gpib_board_config_t *config);
-static int cb_isa_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int cb_pci_attach(struct gpib_board *board, const struct gpib_board_config *config);
+static int cb_isa_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void cb_pci_detach(struct gpib_board *board);
static void cb_isa_detach(struct gpib_board *board);
// wrappers for interface functions
-static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int cb7210_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct cb7210_priv *priv = board->private_data;
@@ -548,7 +548,7 @@ static int cb7210_read(struct gpib_board *board, uint8_t *buffer, size_t length,
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
-static int cb7210_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int cb7210_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct cb7210_priv *priv = board->private_data;
@@ -556,7 +556,7 @@ static int cb7210_write(struct gpib_board *board, uint8_t *buffer, size_t length
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int cb7210_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int cb7210_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct cb7210_priv *priv = board->private_data;
@@ -578,7 +578,7 @@ static int cb7210_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void cb7210_request_system_control(struct gpib_board *board, int request_control)
+static int cb7210_request_system_control(struct gpib_board *board, int request_control)
{
struct cb7210_priv *priv = board->private_data;
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
@@ -589,7 +589,7 @@ static void cb7210_request_system_control(struct gpib_board *board, int request_
priv->hs_mode_bits &= ~HS_SYS_CONTROL;
cb7210_write_byte(priv, priv->hs_mode_bits, HS_MODE);
- nec7210_request_system_control(board, nec_priv, request_control);
+ return nec7210_request_system_control(board, nec_priv, request_control);
}
static void cb7210_interface_clear(struct gpib_board *board, int assert)
@@ -606,7 +606,7 @@ static void cb7210_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int cb7210_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int cb7210_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct cb7210_priv *priv = board->private_data;
@@ -641,14 +641,14 @@ static int cb7210_secondary_address(struct gpib_board *board, unsigned int addre
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int cb7210_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int cb7210_parallel_poll(struct gpib_board *board, u8 *result)
{
struct cb7210_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-static void cb7210_parallel_poll_configure(struct gpib_board *board, uint8_t configuration)
+static void cb7210_parallel_poll_configure(struct gpib_board *board, u8 configuration)
{
struct cb7210_priv *priv = board->private_data;
@@ -662,14 +662,14 @@ static void cb7210_parallel_poll_response(struct gpib_board *board, int ist)
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-static void cb7210_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void cb7210_serial_poll_response(struct gpib_board *board, u8 status)
{
struct cb7210_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-static uint8_t cb7210_serial_poll_status(struct gpib_board *board)
+static u8 cb7210_serial_poll_status(struct gpib_board *board)
{
struct cb7210_priv *priv = board->private_data;
@@ -686,7 +686,7 @@ static void cb7210_return_to_local(struct gpib_board *board)
write_byte(nec_priv, AUX_RTL, AUXMR);
}
-static gpib_interface_t cb_pci_unaccel_interface = {
+static struct gpib_interface cb_pci_unaccel_interface = {
.name = "cbi_pci_unaccel",
.attach = cb_pci_attach,
.detach = cb_pci_detach,
@@ -714,7 +714,7 @@ static gpib_interface_t cb_pci_unaccel_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_pci_accel_interface = {
+static struct gpib_interface cb_pci_accel_interface = {
.name = "cbi_pci_accel",
.attach = cb_pci_attach,
.detach = cb_pci_detach,
@@ -742,7 +742,7 @@ static gpib_interface_t cb_pci_accel_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_pci_interface = {
+static struct gpib_interface cb_pci_interface = {
.name = "cbi_pci",
.attach = cb_pci_attach,
.detach = cb_pci_detach,
@@ -769,7 +769,7 @@ static gpib_interface_t cb_pci_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_isa_unaccel_interface = {
+static struct gpib_interface cb_isa_unaccel_interface = {
.name = "cbi_isa_unaccel",
.attach = cb_isa_attach,
.detach = cb_isa_detach,
@@ -797,7 +797,7 @@ static gpib_interface_t cb_isa_unaccel_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_isa_interface = {
+static struct gpib_interface cb_isa_interface = {
.name = "cbi_isa",
.attach = cb_isa_attach,
.detach = cb_isa_detach,
@@ -824,7 +824,7 @@ static gpib_interface_t cb_isa_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_isa_accel_interface = {
+static struct gpib_interface cb_isa_accel_interface = {
.name = "cbi_isa_accel",
.attach = cb_isa_attach,
.detach = cb_isa_detach,
@@ -905,7 +905,8 @@ static int cb7210_init(struct cb7210_priv *cb_priv, struct gpib_board *board)
cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE);
write_byte(nec_priv, AUX_LO_SPEED, AUXMR);
- /* set clock register for maximum (20 MHz) driving frequency
+ /*
+ * set clock register for maximum (20 MHz) driving frequency
* ICR should be set to clock in megahertz (1-15) and to zero
* for clocks faster than 15 MHz (max 20MHz)
*/
@@ -926,7 +927,7 @@ static int cb7210_init(struct cb7210_priv *cb_priv, struct gpib_board *board)
return 0;
}
-static int cb_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int cb_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct cb7210_priv *cb_priv;
struct nec7210_priv *nec_priv;
@@ -1031,7 +1032,7 @@ static void cb_pci_detach(struct gpib_board *board)
cb7210_generic_detach(board);
}
-static int cb_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int cb_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int isr_flags = 0;
struct cb7210_priv *cb_priv;
@@ -1133,7 +1134,7 @@ static struct pci_driver cb7210_pci_driver = {
static int cb_gpib_config(struct pcmcia_device *link);
static void cb_gpib_release(struct pcmcia_device *link);
-static int cb_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int cb_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void cb_pcmcia_detach(struct gpib_board *board);
/*
@@ -1246,13 +1247,8 @@ static int cb_gpib_config_iteration(struct pcmcia_device *link, void *priv_data)
static int cb_gpib_config(struct pcmcia_device *link)
{
- struct pcmcia_device *handle;
- struct local_info *dev;
int retval;
- handle = link;
- dev = link->priv;
-
retval = pcmcia_loop_config(link, &cb_gpib_config_iteration, NULL);
if (retval) {
dev_warn(&link->dev, "no configuration found\n");
@@ -1275,9 +1271,9 @@ static int cb_gpib_config(struct pcmcia_device *link)
} /* gpib_config */
/*
- * After a card is removed, gpib_release() will unregister the net
- * device, and release the PCMCIA configuration. If the device is
- * still open, this will be postponed until it is closed.
+ * After a card is removed, gpib_release() will unregister the net
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
*/
static void cb_gpib_release(struct pcmcia_device *link)
@@ -1333,7 +1329,7 @@ static void cb_pcmcia_cleanup_module(void)
pcmcia_unregister_driver(&cb_gpib_cs_driver);
}
-static gpib_interface_t cb_pcmcia_unaccel_interface = {
+static struct gpib_interface cb_pcmcia_unaccel_interface = {
.name = "cbi_pcmcia_unaccel",
.attach = cb_pcmcia_attach,
.detach = cb_pcmcia_detach,
@@ -1361,7 +1357,7 @@ static gpib_interface_t cb_pcmcia_unaccel_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_pcmcia_interface = {
+static struct gpib_interface cb_pcmcia_interface = {
.name = "cbi_pcmcia",
.attach = cb_pcmcia_attach,
.detach = cb_pcmcia_detach,
@@ -1389,7 +1385,7 @@ static gpib_interface_t cb_pcmcia_interface = {
.return_to_local = cb7210_return_to_local,
};
-static gpib_interface_t cb_pcmcia_accel_interface = {
+static struct gpib_interface cb_pcmcia_accel_interface = {
.name = "cbi_pcmcia_accel",
.attach = cb_pcmcia_attach,
.detach = cb_pcmcia_detach,
@@ -1417,7 +1413,7 @@ static gpib_interface_t cb_pcmcia_accel_interface = {
.return_to_local = cb7210_return_to_local,
};
-static int cb_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int cb_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct cb7210_priv *cb_priv;
struct nec7210_priv *nec_priv;
diff --git a/drivers/staging/gpib/cb7210/cb7210.h b/drivers/staging/gpib/cb7210/cb7210.h
index 2108fe7a8ce5..13f127563ab3 100644
--- a/drivers/staging/gpib/cb7210/cb7210.h
+++ b/drivers/staging/gpib/cb7210/cb7210.h
@@ -73,8 +73,8 @@ static inline int cb7210_page_in_bits(unsigned int page)
return 0x50 | (page & 0xf);
}
-static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv,
- unsigned int register_num, unsigned int page)
+static inline u8 cb7210_paged_read_byte(struct cb7210_priv *cb_priv,
+ unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
u8 retval;
@@ -89,8 +89,8 @@ static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv,
}
// don't use for register_num < 8, since it doesn't lock
-static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv,
- enum hs_regs register_num)
+static inline u8 cb7210_read_byte(const struct cb7210_priv *cb_priv,
+ enum hs_regs register_num)
{
const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
u8 retval;
@@ -99,7 +99,7 @@ static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv,
return retval;
}
-static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t data,
+static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, u8 data,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
@@ -113,7 +113,7 @@ static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t
}
// don't use for register_num < 8, since it doesn't lock
-static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, uint8_t data,
+static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, u8 data,
enum hs_regs register_num)
{
const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv;
@@ -134,7 +134,8 @@ enum bus_status_bits {
/* CBI 488.2 HS control */
-/* when both bit 0 and 1 are set, it
+/*
+ * when both bit 0 and 1 are set, it
* 1 clears the transmit state machine to an initial condition
* 2 clears any residual interrupts left latched on cbi488.2
* 3 resets all control bits in HS_MODE to zero
@@ -189,11 +190,12 @@ static inline unsigned int irq_bits(unsigned int irq)
}
enum cb7210_aux_cmds {
-/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
- * (and keep asserted) local rtl message. This is used in conjunction
- * with the (stupid) cb7210 implementation
- * of the normal nec7210 AUX_RTL aux command, which
- * causes the rtl message to toggle between on and off.
+/*
+ * AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
+ * (and keep asserted) local rtl message. This is used in conjunction
+ * with the (stupid) cb7210 implementation
+ * of the normal nec7210 AUX_RTL aux command, which
+ * causes the rtl message to toggle between on and off.
*/
AUX_RTL2 = 0xd,
AUX_LO_SPEED = 0x40,
diff --git a/drivers/staging/gpib/cec/cec_gpib.c b/drivers/staging/gpib/cec/cec_gpib.c
index a822fa428cd0..e8736cbf50e3 100644
--- a/drivers/staging/gpib/cec/cec_gpib.c
+++ b/drivers/staging/gpib/cec/cec_gpib.c
@@ -40,12 +40,12 @@ static irqreturn_t cec_interrupt(int irq, void *arg)
#define CEC_DEV_ID 0x5cec
#define CEC_SUBID 0x9050
-static int cec_pci_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void cec_pci_detach(struct gpib_board *board);
// wrappers for interface functions
-static int cec_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int cec_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct cec_priv *priv = board->private_data;
@@ -53,7 +53,7 @@ static int cec_read(struct gpib_board *board, uint8_t *buffer, size_t length, in
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
-static int cec_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int cec_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct cec_priv *priv = board->private_data;
@@ -61,7 +61,7 @@ static int cec_write(struct gpib_board *board, uint8_t *buffer, size_t length, i
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int cec_command(struct gpib_board *board, uint8_t *buffer,
+static int cec_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct cec_priv *priv = board->private_data;
@@ -83,11 +83,11 @@ static int cec_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void cec_request_system_control(struct gpib_board *board, int request_control)
+static int cec_request_system_control(struct gpib_board *board, int request_control)
{
struct cec_priv *priv = board->private_data;
- nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
+ return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
}
static void cec_interface_clear(struct gpib_board *board, int assert)
@@ -104,7 +104,7 @@ static void cec_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int cec_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int cec_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct cec_priv *priv = board->private_data;
@@ -139,14 +139,14 @@ static int cec_secondary_address(struct gpib_board *board, unsigned int address,
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int cec_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int cec_parallel_poll(struct gpib_board *board, u8 *result)
{
struct cec_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-static void cec_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void cec_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct cec_priv *priv = board->private_data;
@@ -160,14 +160,14 @@ static void cec_parallel_poll_response(struct gpib_board *board, int ist)
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-static void cec_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void cec_serial_poll_response(struct gpib_board *board, u8 status)
{
struct cec_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-static uint8_t cec_serial_poll_status(struct gpib_board *board)
+static u8 cec_serial_poll_status(struct gpib_board *board)
{
struct cec_priv *priv = board->private_data;
@@ -188,7 +188,7 @@ static void cec_return_to_local(struct gpib_board *board)
nec7210_return_to_local(board, &priv->nec7210_priv);
}
-static gpib_interface_t cec_pci_interface = {
+static struct gpib_interface cec_pci_interface = {
.name = "cec_pci",
.attach = cec_pci_attach,
.detach = cec_pci_detach,
@@ -265,7 +265,7 @@ static void cec_init(struct cec_priv *cec_priv, const struct gpib_board *board)
nec7210_board_online(nec_priv, board);
}
-static int cec_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct cec_priv *cec_priv;
struct nec7210_priv *nec_priv;
diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c
index 8456b97290b8..0678829ad14f 100644
--- a/drivers/staging/gpib/common/gpib_os.c
+++ b/drivers/staging/gpib/common/gpib_os.c
@@ -26,35 +26,37 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB base support");
MODULE_ALIAS_CHARDEV_MAJOR(GPIB_CODE);
-static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg);
-static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int board_type_ioctl(struct gpib_file_private *file_priv,
+ struct gpib_board *board, unsigned long arg);
+static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg);
-static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg);
-static int command_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int command_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg);
static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg);
static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg);
static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg);
-static int wait_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg);
+static int wait_ioctl(struct gpib_file_private *file_priv,
+ struct gpib_board *board, unsigned long arg);
static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg);
static int online_ioctl(struct gpib_board *board, unsigned long arg);
static int remote_enable_ioctl(struct gpib_board *board, unsigned long arg);
static int take_control_ioctl(struct gpib_board *board, unsigned long arg);
static int line_status_ioctl(struct gpib_board *board, unsigned long arg);
-static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg);
-static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg);
static int eos_ioctl(struct gpib_board *board, unsigned long arg);
static int request_service_ioctl(struct gpib_board *board, unsigned long arg);
static int request_service2_ioctl(struct gpib_board *board, unsigned long arg);
-static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg);
-static int irq_ioctl(gpib_board_config_t *config, unsigned long arg);
-static int dma_ioctl(gpib_board_config_t *config, unsigned long arg);
-static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg);
+static int irq_ioctl(struct gpib_board_config *config, unsigned long arg);
+static int dma_ioctl(struct gpib_board_config *config, unsigned long arg);
+static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg);
-static int mutex_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg);
static int timeout_ioctl(struct gpib_board *board, unsigned long arg);
static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg);
@@ -64,15 +66,16 @@ static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long ar
static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg);
static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg);
static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg);
-static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg);
-static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg);
+static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg);
+static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg);
static int event_ioctl(struct gpib_board *board, unsigned long arg);
static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg);
static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg);
-static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_board *board);
+static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board);
-static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type);
+static int pop_gpib_event_nolock(struct gpib_board *board,
+ struct gpib_event_queue *queue, short *event_type);
/*
* Timer functions
@@ -119,7 +122,8 @@ int io_timed_out(struct gpib_board *board)
return 0;
}
-/* this is a function instead of a constant because of Suse
+/*
+ * this is a function instead of a constant because of Suse
* defining HZ to be a function call to get_hz()
*/
static inline int pseudo_irq_period(void)
@@ -170,7 +174,7 @@ EXPORT_SYMBOL(gpib_free_pseudo_irq);
static const unsigned int serial_timeout = 1000000;
-unsigned int num_status_bytes(const gpib_status_queue_t *dev)
+unsigned int num_status_bytes(const struct gpib_status_queue *dev)
{
if (!dev)
return 0;
@@ -178,10 +182,10 @@ unsigned int num_status_bytes(const gpib_status_queue_t *dev)
}
// push status byte onto back of status byte fifo
-int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 poll_byte)
+int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 poll_byte)
{
struct list_head *head = &device->status_bytes;
- status_byte_t *status;
+ struct gpib_status_byte *status;
static const unsigned int max_num_status_bytes = 1024;
int retval;
@@ -194,7 +198,7 @@ int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 p
return retval;
}
- status = kmalloc(sizeof(status_byte_t), GFP_KERNEL);
+ status = kmalloc(sizeof(*status), GFP_KERNEL);
if (!status)
return -ENOMEM;
@@ -212,11 +216,11 @@ int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 p
}
// pop status byte from front of status byte fifo
-int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *poll_byte)
+int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device, u8 *poll_byte)
{
struct list_head *head = &device->status_bytes;
struct list_head *front = head->next;
- status_byte_t *status;
+ struct gpib_status_byte *status;
if (num_status_bytes(device) == 0)
return -EIO;
@@ -229,7 +233,7 @@ int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *p
return -EPIPE;
}
- status = list_entry(front, status_byte_t, list);
+ status = list_entry(front, struct gpib_status_byte, list);
*poll_byte = status->poll_byte;
list_del(front);
@@ -243,14 +247,14 @@ int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, u8 *p
return 0;
}
-gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad)
+struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad)
{
- gpib_status_queue_t *device;
+ struct gpib_status_queue *device;
struct list_head *list_ptr;
const struct list_head *head = &board->device_list;
for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, gpib_status_queue_t, list);
+ device = list_entry(list_ptr, struct gpib_status_queue, list);
if (gpib_address_equal(device->pad, device->sad, pad, sad))
return device;
}
@@ -258,10 +262,10 @@ gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned in
return NULL;
}
-int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad, unsigned int usec_timeout,
- uint8_t *poll_byte)
+int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad,
+ unsigned int usec_timeout, u8 *poll_byte)
{
- gpib_status_queue_t *device;
+ struct gpib_status_queue *device;
device = get_gpib_status_queue(board, pad, sad);
if (num_status_bytes(device))
@@ -291,7 +295,8 @@ int autopoll_all_devices(struct gpib_board *board)
}
dev_dbg(board->gpib_dev, "complete\n");
- /* need to wake wait queue in case someone is
+ /*
+ * need to wake wait queue in case someone is
* waiting on RQS
*/
wake_up_interruptible(&board->wait);
@@ -334,7 +339,7 @@ static int setup_serial_poll(struct gpib_board *board, unsigned int usec_timeout
}
static int read_serial_poll_byte(struct gpib_board *board, unsigned int pad,
- int sad, unsigned int usec_timeout, uint8_t *result)
+ int sad, unsigned int usec_timeout, u8 *result)
{
u8 cmd_string[8];
int end_flag;
@@ -405,7 +410,7 @@ static int cleanup_serial_poll(struct gpib_board *board, unsigned int usec_timeo
}
static int serial_poll_single(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, uint8_t *result)
+ unsigned int usec_timeout, u8 *result)
{
int retval, cleanup_retval;
@@ -427,7 +432,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout)
int retval = 0;
struct list_head *cur;
const struct list_head *head = NULL;
- gpib_status_queue_t *device;
+ struct gpib_status_queue *device;
u8 result;
unsigned int num_bytes = 0;
@@ -440,7 +445,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout)
return retval;
for (cur = head->next; cur != head; cur = cur->next) {
- device = list_entry(cur, gpib_status_queue_t, list);
+ device = list_entry(cur, struct gpib_status_queue, list);
retval = read_serial_poll_byte(board,
device->pad, device->sad, usec_timeout, &result);
if (retval < 0)
@@ -470,7 +475,7 @@ int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout)
*/
int dvrsp(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, uint8_t *result)
+ unsigned int usec_timeout, u8 *result)
{
int status = ibstatus(board);
int retval;
@@ -492,8 +497,8 @@ int dvrsp(struct gpib_board *board, unsigned int pad, int sad,
return retval;
}
-static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_priv,
- int handle)
+static struct gpib_descriptor *handle_to_descriptor(const struct gpib_file_private *file_priv,
+ int handle)
{
if (handle < 0 || handle >= GPIB_MAX_NUM_DESCRIPTORS) {
pr_err("gpib: invalid handle %i\n", handle);
@@ -503,11 +508,11 @@ static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_p
return file_priv->descriptors[handle];
}
-static int init_gpib_file_private(gpib_file_private_t *priv)
+static int init_gpib_file_private(struct gpib_file_private *priv)
{
memset(priv, 0, sizeof(*priv));
atomic_set(&priv->holding_mutex, 0);
- priv->descriptors[0] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL);
+ priv->descriptors[0] = kmalloc(sizeof(struct gpib_descriptor), GFP_KERNEL);
if (!priv->descriptors[0]) {
pr_err("gpib: failed to allocate default board descriptor\n");
return -ENOMEM;
@@ -522,7 +527,7 @@ int ibopen(struct inode *inode, struct file *filep)
{
unsigned int minor = iminor(inode);
struct gpib_board *board;
- gpib_file_private_t *priv;
+ struct gpib_file_private *priv;
if (minor >= GPIB_MAX_NUM_BOARDS) {
pr_err("gpib: invalid minor number of device file\n");
@@ -531,12 +536,12 @@ int ibopen(struct inode *inode, struct file *filep)
board = &board_array[minor];
- filep->private_data = kmalloc(sizeof(gpib_file_private_t), GFP_KERNEL);
+ filep->private_data = kmalloc(sizeof(struct gpib_file_private), GFP_KERNEL);
if (!filep->private_data)
return -ENOMEM;
priv = filep->private_data;
- init_gpib_file_private((gpib_file_private_t *)filep->private_data);
+ init_gpib_file_private((struct gpib_file_private *)filep->private_data);
if (board->use_count == 0) {
int retval;
@@ -560,8 +565,8 @@ int ibclose(struct inode *inode, struct file *filep)
{
unsigned int minor = iminor(inode);
struct gpib_board *board;
- gpib_file_private_t *priv = filep->private_data;
- gpib_descriptor_t *desc;
+ struct gpib_file_private *priv = filep->private_data;
+ struct gpib_descriptor *desc;
if (minor >= GPIB_MAX_NUM_BOARDS) {
pr_err("gpib: invalid minor number of device file\n");
@@ -606,7 +611,7 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
unsigned int minor = iminor(filep->f_path.dentry->d_inode);
struct gpib_board *board;
- gpib_file_private_t *file_priv = filep->private_data;
+ struct gpib_file_private *file_priv = filep->private_data;
long retval = -ENOTTY;
if (minor >= GPIB_MAX_NUM_BOARDS) {
@@ -665,8 +670,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
retval = board_info_ioctl(board, arg);
goto done;
case IBMUTEX:
- /* Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex
- * to maintain consistent locking order
+ /*
+ * Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex
+ * to maintain consistent locking order
*/
mutex_unlock(&board->big_gpib_mutex);
return mutex_ioctl(board, file_priv, arg);
@@ -736,8 +742,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
retval = take_control_ioctl(board, arg);
goto done;
case IBCMD:
- /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
+ /*
+ * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+ * before we call them.
*/
mutex_unlock(&board->big_gpib_mutex);
return command_ioctl(file_priv, board, arg);
@@ -760,8 +767,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
retval = query_board_rsv_ioctl(board, arg);
goto done;
case IBRD:
- /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
+ /*
+ * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+ * before we call them.
*/
mutex_unlock(&board->big_gpib_mutex);
return read_ioctl(file_priv, board, arg);
@@ -790,8 +798,9 @@ long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg)
retval = timeout_ioctl(board, arg);
goto done;
case IBWRT:
- /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
- * before we call them.
+ /*
+ * IO ioctls can take a long time, we need to unlock board->big_gpib_mutex
+ * before we call them.
*/
mutex_unlock(&board->big_gpib_mutex);
return write_ioctl(file_priv, board, arg);
@@ -806,10 +815,11 @@ done:
return retval;
}
-static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board, unsigned long arg)
+static int board_type_ioctl(struct gpib_file_private *file_priv,
+ struct gpib_board *board, unsigned long arg)
{
struct list_head *list_ptr;
- board_type_ioctl_t cmd;
+ struct gpib_board_type_ioctl cmd;
int retval;
if (!capable(CAP_SYS_ADMIN))
@@ -817,15 +827,16 @@ static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *b
if (board->online)
return -EBUSY;
- retval = copy_from_user(&cmd, (void __user *)arg, sizeof(board_type_ioctl_t));
+ retval = copy_from_user(&cmd, (void __user *)arg,
+ sizeof(struct gpib_board_type_ioctl));
if (retval)
return retval;
for (list_ptr = registered_drivers.next; list_ptr != &registered_drivers;
list_ptr = list_ptr->next) {
- gpib_interface_list_t *entry;
+ struct gpib_interface_list *entry;
- entry = list_entry(list_ptr, gpib_interface_list_t, list);
+ entry = list_entry(list_ptr, struct gpib_interface_list, list);
if (strcmp(entry->interface->name, cmd.name) == 0) {
int i;
int had_module = file_priv->got_module;
@@ -857,16 +868,16 @@ static int board_type_ioctl(gpib_file_private_t *file_priv, struct gpib_board *b
return -EINVAL;
}
-static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg)
{
- read_write_ioctl_t read_cmd;
+ struct gpib_read_write_ioctl read_cmd;
u8 __user *userbuf;
unsigned long remain;
int end_flag = 0;
int retval;
ssize_t read_ret = 0;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
size_t nbytes;
retval = copy_from_user(&read_cmd, (void __user *)arg, sizeof(read_cmd));
@@ -913,7 +924,8 @@ static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
}
read_cmd.completed_transfer_count = read_cmd.requested_transfer_count - remain;
read_cmd.end = end_flag;
- /* suppress errors (for example due to timeout or interruption by device clear)
+ /*
+ * suppress errors (for example due to timeout or interruption by device clear)
* if all bytes got sent. This prevents races that can occur in the various drivers
* if a device receives a device clear immediately after a transfer completes and
* the driver code wasn't careful enough to handle that case.
@@ -932,15 +944,15 @@ static int read_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
return read_ret;
}
-static int command_ioctl(gpib_file_private_t *file_priv,
+static int command_ioctl(struct gpib_file_private *file_priv,
struct gpib_board *board, unsigned long arg)
{
- read_write_ioctl_t cmd;
+ struct gpib_read_write_ioctl cmd;
u8 __user *userbuf;
unsigned long remain;
int retval;
int fault = 0;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
size_t bytes_written;
int no_clear_io_in_prog;
@@ -967,10 +979,11 @@ static int command_ioctl(gpib_file_private_t *file_priv,
if (!access_ok(userbuf, remain))
return -EFAULT;
- /* Write buffer loads till we empty the user supplied buffer.
- * Call drivers at least once, even if remain is zero, in
- * order to allow them to insure previous commands were
- * completely finished, in the case of a restarted ioctl.
+ /*
+ * Write buffer loads till we empty the user supplied buffer.
+ * Call drivers at least once, even if remain is zero, in
+ * order to allow them to insure previous commands were
+ * completely finished, in the case of a restarted ioctl.
*/
atomic_set(&desc->io_in_progress, 1);
@@ -1016,15 +1029,15 @@ static int command_ioctl(gpib_file_private_t *file_priv,
return retval;
}
-static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg)
{
- read_write_ioctl_t write_cmd;
+ struct gpib_read_write_ioctl write_cmd;
u8 __user *userbuf;
unsigned long remain;
int retval = 0;
int fault;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
fault = copy_from_user(&write_cmd, (void __user *)arg, sizeof(write_cmd));
if (fault)
@@ -1068,7 +1081,8 @@ static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
break;
}
write_cmd.completed_transfer_count = write_cmd.requested_transfer_count - remain;
- /* suppress errors (for example due to timeout or interruption by device clear)
+ /*
+ * suppress errors (for example due to timeout or interruption by device clear)
* if all bytes got sent. This prevents races that can occur in the various drivers
* if a device receives a device clear immediately after a transfer completes and
* the driver code wasn't careful enough to handle that case.
@@ -1089,8 +1103,8 @@ static int write_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
static int status_bytes_ioctl(struct gpib_board *board, unsigned long arg)
{
- gpib_status_queue_t *device;
- spoll_bytes_ioctl_t cmd;
+ struct gpib_status_queue *device;
+ struct gpib_spoll_bytes_ioctl cmd;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
@@ -1114,13 +1128,14 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea
unsigned int pad, int sad)
{
struct list_head *list_ptr;
- gpib_status_queue_t *device;
+ struct gpib_status_queue *device;
- /* first see if address has already been opened, then increment
+ /*
+ * first see if address has already been opened, then increment
* open count
*/
for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, gpib_status_queue_t, list);
+ device = list_entry(list_ptr, struct gpib_status_queue, list);
if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
dev_dbg(board->gpib_dev, "incrementing open count for pad %i, sad %i\n",
device->pad, device->sad);
@@ -1129,8 +1144,8 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea
}
}
- /* otherwise we need to allocate a new gpib_status_queue_t */
- device = kmalloc(sizeof(gpib_status_queue_t), GFP_ATOMIC);
+ /* otherwise we need to allocate a new struct gpib_status_queue */
+ device = kmalloc(sizeof(struct gpib_status_queue), GFP_ATOMIC);
if (!device)
return -ENOMEM;
init_gpib_status_queue(device);
@@ -1148,11 +1163,11 @@ static int increment_open_device_count(struct gpib_board *board, struct list_hea
static int subtract_open_device_count(struct gpib_board *board, struct list_head *head,
unsigned int pad, int sad, unsigned int count)
{
- gpib_status_queue_t *device;
+ struct gpib_status_queue *device;
struct list_head *list_ptr;
for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) {
- device = list_entry(list_ptr, gpib_status_queue_t, list);
+ device = list_entry(list_ptr, struct gpib_status_queue, list);
if (gpib_address_equal(device->pad, device->sad, pad, sad)) {
dev_dbg(board->gpib_dev, "decrementing open count for pad %i, sad %i\n",
device->pad, device->sad);
@@ -1180,13 +1195,13 @@ static inline int decrement_open_device_count(struct gpib_board *board, struct l
return subtract_open_device_count(board, head, pad, sad, 1);
}
-static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_board *board)
+static int cleanup_open_devices(struct gpib_file_private *file_priv, struct gpib_board *board)
{
int retval = 0;
int i;
for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) {
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
desc = file_priv->descriptors[i];
if (!desc)
@@ -1207,9 +1222,9 @@ static int cleanup_open_devices(gpib_file_private_t *file_priv, struct gpib_boar
static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg)
{
- open_dev_ioctl_t open_dev_cmd;
+ struct gpib_open_dev_ioctl open_dev_cmd;
int retval;
- gpib_file_private_t *file_priv = filep->private_data;
+ struct gpib_file_private *file_priv = filep->private_data;
int i;
retval = copy_from_user(&open_dev_cmd, (void __user *)arg, sizeof(open_dev_cmd));
@@ -1225,7 +1240,7 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned
mutex_unlock(&file_priv->descriptors_mutex);
return -ERANGE;
}
- file_priv->descriptors[i] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL);
+ file_priv->descriptors[i] = kmalloc(sizeof(struct gpib_descriptor), GFP_KERNEL);
if (!file_priv->descriptors[i]) {
mutex_unlock(&file_priv->descriptors_mutex);
return -ENOMEM;
@@ -1242,7 +1257,8 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned
if (retval < 0)
return retval;
- /* clear stuck srq state, since we may be able to find service request on
+ /*
+ * clear stuck srq state, since we may be able to find service request on
* the new device
*/
atomic_set(&board->stuck_srq, 0);
@@ -1257,8 +1273,8 @@ static int open_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned
static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigned long arg)
{
- close_dev_ioctl_t cmd;
- gpib_file_private_t *file_priv = filep->private_data;
+ struct gpib_close_dev_ioctl cmd;
+ struct gpib_file_private *file_priv = filep->private_data;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
@@ -1284,7 +1300,7 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne
static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg)
{
- serial_poll_ioctl_t serial_cmd;
+ struct gpib_serial_poll_ioctl serial_cmd;
int retval;
retval = copy_from_user(&serial_cmd, (void __user *)arg, sizeof(serial_cmd));
@@ -1303,12 +1319,12 @@ static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg)
return 0;
}
-static int wait_ioctl(gpib_file_private_t *file_priv, struct gpib_board *board,
+static int wait_ioctl(struct gpib_file_private *file_priv, struct gpib_board *board,
unsigned long arg)
{
- wait_ioctl_t wait_cmd;
+ struct gpib_wait_ioctl wait_cmd;
int retval;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
retval = copy_from_user(&wait_cmd, (void __user *)arg, sizeof(wait_cmd));
if (retval)
@@ -1348,7 +1364,7 @@ static int parallel_poll_ioctl(struct gpib_board *board, unsigned long arg)
static int online_ioctl(struct gpib_board *board, unsigned long arg)
{
- online_ioctl_t online_cmd;
+ struct gpib_online_ioctl online_cmd;
int retval;
void __user *init_data = NULL;
@@ -1430,12 +1446,12 @@ static int line_status_ioctl(struct gpib_board *board, unsigned long arg)
return 0;
}
-static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int pad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg)
{
- pad_ioctl_t cmd;
+ struct gpib_pad_ioctl cmd;
int retval;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
if (retval)
@@ -1466,12 +1482,12 @@ static int pad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
return 0;
}
-static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int sad_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg)
{
- sad_ioctl_t cmd;
+ struct gpib_sad_ioctl cmd;
int retval;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
if (retval)
@@ -1503,7 +1519,7 @@ static int sad_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
static int eos_ioctl(struct gpib_board *board, unsigned long arg)
{
- eos_ioctl_t eos_cmd;
+ struct gpib_eos_ioctl eos_cmd;
int retval;
retval = copy_from_user(&eos_cmd, (void __user *)arg, sizeof(eos_cmd));
@@ -1527,11 +1543,11 @@ static int request_service_ioctl(struct gpib_board *board, unsigned long arg)
static int request_service2_ioctl(struct gpib_board *board, unsigned long arg)
{
- request_service2_t request_service2_cmd;
+ struct gpib_request_service2 request_service2_cmd;
int retval;
retval = copy_from_user(&request_service2_cmd, (void __user *)arg,
- sizeof(request_service2_t));
+ sizeof(struct gpib_request_service2));
if (retval)
return -EFAULT;
@@ -1539,7 +1555,7 @@ static int request_service2_ioctl(struct gpib_board *board, unsigned long arg)
request_service2_cmd.new_reason_for_service);
}
-static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg)
+static int iobase_ioctl(struct gpib_board_config *config, unsigned long arg)
{
u64 base_addr;
int retval;
@@ -1558,7 +1574,7 @@ static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg)
return 0;
}
-static int irq_ioctl(gpib_board_config_t *config, unsigned long arg)
+static int irq_ioctl(struct gpib_board_config *config, unsigned long arg)
{
unsigned int irq;
int retval;
@@ -1575,7 +1591,7 @@ static int irq_ioctl(gpib_board_config_t *config, unsigned long arg)
return 0;
}
-static int dma_ioctl(gpib_board_config_t *config, unsigned long arg)
+static int dma_ioctl(struct gpib_board_config *config, unsigned long arg)
{
unsigned int dma_channel;
int retval;
@@ -1592,12 +1608,12 @@ static int dma_ioctl(gpib_board_config_t *config, unsigned long arg)
return 0;
}
-static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int autospoll_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg)
{
- autospoll_ioctl_t enable;
+ short enable;
int retval;
- gpib_descriptor_t *desc;
+ struct gpib_descriptor *desc;
retval = copy_from_user(&enable, (void __user *)arg, sizeof(enable));
if (retval)
@@ -1630,7 +1646,7 @@ static int autospoll_ioctl(struct gpib_board *board, gpib_file_private_t *file_p
return retval;
}
-static int mutex_ioctl(struct gpib_board *board, gpib_file_private_t *file_priv,
+static int mutex_ioctl(struct gpib_board *board, struct gpib_file_private *file_priv,
unsigned long arg)
{
int retval, lock_mutex;
@@ -1687,7 +1703,7 @@ static int timeout_ioctl(struct gpib_board *board, unsigned long arg)
static int ppc_ioctl(struct gpib_board *board, unsigned long arg)
{
- ppoll_config_ioctl_t cmd;
+ struct gpib_ppoll_config_ioctl cmd;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
@@ -1713,7 +1729,7 @@ static int ppc_ioctl(struct gpib_board *board, unsigned long arg)
static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg)
{
- local_ppoll_mode_ioctl_t cmd;
+ short cmd;
int retval;
retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd));
@@ -1730,7 +1746,7 @@ static int set_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long ar
static int get_local_ppoll_mode_ioctl(struct gpib_board *board, unsigned long arg)
{
- local_ppoll_mode_ioctl_t cmd;
+ short cmd;
int retval;
cmd = board->local_ppoll_mode;
@@ -1757,7 +1773,7 @@ static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg)
static int board_info_ioctl(const struct gpib_board *board, unsigned long arg)
{
- board_info_ioctl_t info;
+ struct gpib_board_info_ioctl info;
int retval;
info.pad = board->pad;
@@ -1790,9 +1806,9 @@ static int interface_clear_ioctl(struct gpib_board *board, unsigned long arg)
return ibsic(board, usec_duration);
}
-static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg)
+static int select_pci_ioctl(struct gpib_board_config *config, unsigned long arg)
{
- select_pci_ioctl_t selection;
+ struct gpib_select_pci_ioctl selection;
int retval;
if (!capable(CAP_SYS_ADMIN))
@@ -1808,19 +1824,20 @@ static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg)
return 0;
}
-static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg)
+static int select_device_path_ioctl(struct gpib_board_config *config, unsigned long arg)
{
- select_device_path_ioctl_t *selection;
+ struct gpib_select_device_path_ioctl *selection;
int retval;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- selection = vmalloc(sizeof(select_device_path_ioctl_t));
+ selection = vmalloc(sizeof(struct gpib_select_device_path_ioctl));
if (!selection)
return -ENOMEM;
- retval = copy_from_user(selection, (void __user *)arg, sizeof(select_device_path_ioctl_t));
+ retval = copy_from_user(selection, (void __user *)arg,
+ sizeof(struct gpib_select_device_path_ioctl));
if (retval) {
vfree(selection);
return -EFAULT;
@@ -1836,16 +1853,16 @@ static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long a
return 0;
}
-unsigned int num_gpib_events(const gpib_event_queue_t *queue)
+unsigned int num_gpib_events(const struct gpib_event_queue *queue)
{
return queue->num_events;
}
static int push_gpib_event_nolock(struct gpib_board *board, short event_type)
{
- gpib_event_queue_t *queue = &board->event_queue;
+ struct gpib_event_queue *queue = &board->event_queue;
struct list_head *head = &queue->event_head;
- gpib_event_t *event;
+ struct gpib_event *event;
static const unsigned int max_num_events = 1024;
int retval;
@@ -1858,7 +1875,7 @@ static int push_gpib_event_nolock(struct gpib_board *board, short event_type)
return retval;
}
- event = kmalloc(sizeof(gpib_event_t), GFP_ATOMIC);
+ event = kmalloc(sizeof(struct gpib_event), GFP_ATOMIC);
if (!event) {
queue->dropped_event = 1;
dev_err(board->gpib_dev, "failed to allocate memory for event\n");
@@ -1888,23 +1905,24 @@ int push_gpib_event(struct gpib_board *board, short event_type)
retval = push_gpib_event_nolock(board, event_type);
spin_unlock_irqrestore(&board->event_queue.lock, flags);
- if (event_type == EventDevTrg)
+ if (event_type == EVENT_DEV_TRG)
board->status |= DTAS;
- if (event_type == EventDevClr)
+ if (event_type == EVENT_DEV_CLR)
board->status |= DCAS;
return retval;
}
EXPORT_SYMBOL(push_gpib_event);
-static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type)
+static int pop_gpib_event_nolock(struct gpib_board *board,
+ struct gpib_event_queue *queue, short *event_type)
{
struct list_head *head = &queue->event_head;
struct list_head *front = head->next;
- gpib_event_t *event;
+ struct gpib_event *event;
if (num_gpib_events(queue) == 0) {
- *event_type = EventNone;
+ *event_type = EVENT_NONE;
return 0;
}
@@ -1916,7 +1934,7 @@ static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *q
return -EPIPE;
}
- event = list_entry(front, gpib_event_t, list);
+ event = list_entry(front, struct gpib_event, list);
*event_type = event->event_type;
list_del(front);
@@ -1931,7 +1949,7 @@ static int pop_gpib_event_nolock(struct gpib_board *board, gpib_event_queue_t *q
}
// pop event from front of event queue
-int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type)
+int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type)
{
unsigned long flags;
int retval;
@@ -1944,7 +1962,7 @@ int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *e
static int event_ioctl(struct gpib_board *board, unsigned long arg)
{
- event_ioctl_t user_event;
+ short user_event;
int retval;
short event;
@@ -1963,21 +1981,19 @@ static int event_ioctl(struct gpib_board *board, unsigned long arg)
static int request_system_control_ioctl(struct gpib_board *board, unsigned long arg)
{
- rsc_ioctl_t request_control;
+ int request_control;
int retval;
retval = copy_from_user(&request_control, (void __user *)arg, sizeof(request_control));
if (retval)
return -EFAULT;
- ibrsc(board, request_control);
-
- return 0;
+ return ibrsc(board, request_control);
}
static int t1_delay_ioctl(struct gpib_board *board, unsigned long arg)
{
- t1_delay_ioctl_t cmd;
+ unsigned int cmd;
unsigned int delay;
int retval;
@@ -2011,7 +2027,7 @@ struct gpib_board board_array[GPIB_MAX_NUM_BOARDS];
LIST_HEAD(registered_drivers);
-void init_gpib_descriptor(gpib_descriptor_t *desc)
+void init_gpib_descriptor(struct gpib_descriptor *desc)
{
desc->pad = 0;
desc->sad = -1;
@@ -2020,9 +2036,9 @@ void init_gpib_descriptor(gpib_descriptor_t *desc)
atomic_set(&desc->io_in_progress, 0);
}
-int gpib_register_driver(gpib_interface_t *interface, struct module *provider_module)
+int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module)
{
- struct gpib_interface_list_struct *entry;
+ struct gpib_interface_list *entry;
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
@@ -2036,7 +2052,7 @@ int gpib_register_driver(gpib_interface_t *interface, struct module *provider_mo
}
EXPORT_SYMBOL(gpib_register_driver);
-void gpib_unregister_driver(gpib_interface_t *interface)
+void gpib_unregister_driver(struct gpib_interface *interface)
{
int i;
struct list_head *list_ptr;
@@ -2053,9 +2069,9 @@ void gpib_unregister_driver(gpib_interface_t *interface)
}
}
for (list_ptr = registered_drivers.next; list_ptr != &registered_drivers;) {
- gpib_interface_list_t *entry;
+ struct gpib_interface_list *entry;
- entry = list_entry(list_ptr, gpib_interface_list_t, list);
+ entry = list_entry(list_ptr, struct gpib_interface_list, list);
list_ptr = list_ptr->next;
if (entry->interface == interface) {
list_del(&entry->list);
@@ -2065,9 +2081,9 @@ void gpib_unregister_driver(gpib_interface_t *interface)
}
EXPORT_SYMBOL(gpib_unregister_driver);
-static void init_gpib_board_config(gpib_board_config_t *config)
+static void init_gpib_board_config(struct gpib_board_config *config)
{
- memset(config, 0, sizeof(gpib_board_config_t));
+ memset(config, 0, sizeof(struct gpib_board_config));
config->pci_bus = -1;
config->pci_slot = -1;
}
@@ -2143,7 +2159,7 @@ static void init_board_array(struct gpib_board *board_array, unsigned int length
}
}
-void init_gpib_status_queue(gpib_status_queue_t *device)
+void init_gpib_status_queue(struct gpib_status_queue *device)
{
INIT_LIST_HEAD(&device->list);
INIT_LIST_HEAD(&device->status_bytes);
@@ -2208,7 +2224,7 @@ int gpib_match_device_path(struct device *dev, const char *device_path_in)
}
EXPORT_SYMBOL(gpib_match_device_path);
-struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id,
+struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, struct pci_dev *from)
{
struct pci_dev *pci_device = from;
@@ -2227,7 +2243,7 @@ struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned
}
EXPORT_SYMBOL(gpib_pci_get_device);
-struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id,
+struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, unsigned int ss_vendor,
unsigned int ss_device,
struct pci_dev *from)
diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c
index 432540e1bc9a..512bd75900ec 100644
--- a/drivers/staging/gpib/common/iblib.c
+++ b/drivers/staging/gpib/common/iblib.c
@@ -33,9 +33,10 @@ int ibcac(struct gpib_board *board, int sync, int fallback_to_async)
return 0;
if (sync && (status & LACS) == 0)
- /* tcs (take control synchronously) can only possibly work when
- * controller is listener. Error code also needs to be -ETIMEDOUT
- * or it will giveout without doing fallback.
+ /*
+ * tcs (take control synchronously) can only possibly work when
+ * controller is listener. Error code also needs to be -ETIMEDOUT
+ * or it will giveout without doing fallback.
*/
retval = -ETIMEDOUT;
else
@@ -50,7 +51,8 @@ int ibcac(struct gpib_board *board, int sync, int fallback_to_async)
return retval;
}
-/* After ATN is asserted, it should cause any connected devices
+/*
+ * After ATN is asserted, it should cause any connected devices
* to start listening for command bytes and leave acceptor idle state.
* So if ATN is asserted and neither NDAC or NRFD are asserted,
* then there are no devices and ibcmd should error out immediately.
@@ -96,7 +98,7 @@ static int check_for_command_acceptors(struct gpib_board *board)
* must be called to initialize the GPIB and enable
* the interface to leave the controller idle state.
*/
-int ibcmd(struct gpib_board *board, uint8_t *buf, size_t length, size_t *bytes_written)
+int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written)
{
ssize_t ret = 0;
int status;
@@ -218,7 +220,8 @@ int ibonline(struct gpib_board *board)
board->interface->detach(board);
return retval;
}
- /* nios2nommu on 2.6.11 uclinux kernel has weird problems
+ /*
+ * nios2nommu on 2.6.11 uclinux kernel has weird problems
* with autospoll thread causing huge slowdowns
*/
#ifndef CONFIG_NIOS2
@@ -297,7 +300,7 @@ int iblines(const struct gpib_board *board, short *lines)
* calling ibcmd.
*/
-int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, size_t *nbytes)
+int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *nbytes)
{
ssize_t ret = 0;
int retval;
@@ -313,7 +316,8 @@ int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, s
if (retval < 0)
return retval;
}
- /* XXX resetting timer here could cause timeouts take longer than they should,
+ /*
+ * XXX resetting timer here could cause timeouts take longer than they should,
* since read_ioctl calls this
* function in a loop, there is probably a similar problem with writes/commands
*/
@@ -343,7 +347,7 @@ ibrd_out:
* 1. Prior to conducting the poll the interface is placed
* in the controller active state.
*/
-int ibrpp(struct gpib_board *board, uint8_t *result)
+int ibrpp(struct gpib_board *board, u8 *result)
{
int retval = 0;
@@ -358,7 +362,7 @@ int ibrpp(struct gpib_board *board, uint8_t *result)
return retval;
}
-int ibppc(struct gpib_board *board, uint8_t configuration)
+int ibppc(struct gpib_board *board, u8 configuration)
{
configuration &= 0x1f;
board->interface->parallel_poll_configure(board, configuration);
@@ -367,7 +371,7 @@ int ibppc(struct gpib_board *board, uint8_t configuration)
return 0;
}
-int ibrsv2(struct gpib_board *board, uint8_t status_byte, int new_reason_for_service)
+int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service)
{
int board_status = ibstatus(board);
const unsigned int MSS = status_byte & request_service_bit;
@@ -418,12 +422,21 @@ int ibsic(struct gpib_board *board, unsigned int usec_duration)
return 0;
}
- /* FIXME make int */
-void ibrsc(struct gpib_board *board, int request_control)
+int ibrsc(struct gpib_board *board, int request_control)
{
+ int retval;
+
+ if (!board->interface->request_system_control)
+ return -EPERM;
+
+ retval = board->interface->request_system_control(board, request_control);
+
+ if (retval)
+ return retval;
+
board->master = request_control != 0;
- if (board->interface->request_system_control)
- board->interface->request_system_control(board, request_control);
+
+ return 0;
}
/*
@@ -506,15 +519,16 @@ int ibstatus(struct gpib_board *board)
return general_ibstatus(board, NULL, 0, 0, NULL);
}
-int general_ibstatus(struct gpib_board *board, const gpib_status_queue_t *device,
- int clear_mask, int set_mask, gpib_descriptor_t *desc)
+int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device,
+ int clear_mask, int set_mask, struct gpib_descriptor *desc)
{
int status = 0;
short line_status;
if (board->private_data) {
status = board->interface->update_status(board, clear_mask);
- /* XXX should probably stop having drivers use TIMO bit in
+ /*
+ * XXX should probably stop having drivers use TIMO bit in
* board->status to avoid confusion
*/
status &= ~TIMO;
@@ -573,8 +587,8 @@ static void init_wait_info(struct wait_info *winfo)
timer_setup_on_stack(&winfo->timer, wait_timeout, 0);
}
-static int wait_satisfied(struct wait_info *winfo, gpib_status_queue_t *status_queue,
- int wait_mask, int *status, gpib_descriptor_t *desc)
+static int wait_satisfied(struct wait_info *winfo, struct gpib_status_queue *status_queue,
+ int wait_mask, int *status, struct gpib_descriptor *desc)
{
struct gpib_board *board = winfo->board;
int temp_status;
@@ -623,10 +637,10 @@ static void remove_wait_timer(struct wait_info *winfo)
* no condition is waited for.
*/
int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask,
- int *status, unsigned long usec_timeout, gpib_descriptor_t *desc)
+ int *status, unsigned long usec_timeout, struct gpib_descriptor *desc)
{
int retval = 0;
- gpib_status_queue_t *status_queue;
+ struct gpib_status_queue *status_queue;
struct wait_info winfo;
if (desc->is_board)
@@ -677,7 +691,7 @@ int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask
* well as the interface board itself must be
* addressed by calling ibcmd.
*/
-int ibwrt(struct gpib_board *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written)
+int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written)
{
int ret = 0;
int retval;
diff --git a/drivers/staging/gpib/common/ibsys.h b/drivers/staging/gpib/common/ibsys.h
index 19960af809c2..e5a148f513a8 100644
--- a/drivers/staging/gpib/common/ibsys.h
+++ b/drivers/staging/gpib/common/ibsys.h
@@ -22,10 +22,13 @@
int gpib_allocate_board(struct gpib_board *board);
void gpib_deallocate_board(struct gpib_board *board);
-unsigned int num_status_bytes(const gpib_status_queue_t *dev);
-int push_status_byte(struct gpib_board *board, gpib_status_queue_t *device, uint8_t poll_byte);
-int pop_status_byte(struct gpib_board *board, gpib_status_queue_t *device, uint8_t *poll_byte);
-gpib_status_queue_t *get_gpib_status_queue(struct gpib_board *board, unsigned int pad, int sad);
+unsigned int num_status_bytes(const struct gpib_status_queue *dev);
+int push_status_byte(struct gpib_board *board, struct gpib_status_queue *device,
+ u8 poll_byte);
+int pop_status_byte(struct gpib_board *board, struct gpib_status_queue *device,
+ u8 *poll_byte);
+struct gpib_status_queue *get_gpib_status_queue(struct gpib_board *board,
+ unsigned int pad, int sad);
int get_serial_poll_byte(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, uint8_t *poll_byte);
+ unsigned int usec_timeout, u8 *poll_byte);
int autopoll_all_devices(struct gpib_board *board);
diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.c b/drivers/staging/gpib/eastwood/fluke_gpib.c
index a6b1ac169f94..491356433249 100644
--- a/drivers/staging/gpib/eastwood/fluke_gpib.c
+++ b/drivers/staging/gpib/eastwood/fluke_gpib.c
@@ -24,15 +24,17 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB Driver for Fluke cda devices");
-static int fluke_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config);
-static int fluke_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config);
+static int fluke_attach_holdoff_all(struct gpib_board *board,
+ const struct gpib_board_config *config);
+static int fluke_attach_holdoff_end(struct gpib_board *board,
+ const struct gpib_board_config *config);
static void fluke_detach(struct gpib_board *board);
static int fluke_config_dma(struct gpib_board *board, int output);
static irqreturn_t fluke_gpib_internal_interrupt(struct gpib_board *board);
static struct platform_device *fluke_gpib_pdev;
-static uint8_t fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned int register_number)
+static u8 fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned int register_number)
{
u8 retval;
unsigned long flags;
@@ -43,7 +45,7 @@ static uint8_t fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned i
return retval;
}
-static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, uint8_t byte,
+static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, u8 byte,
unsigned int register_number)
{
unsigned long flags;
@@ -54,7 +56,7 @@ static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, uint8_t byte
}
// wrappers for interface functions
-static int fluke_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int fluke_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct fluke_priv *priv = board->private_data;
@@ -62,7 +64,7 @@ static int fluke_read(struct gpib_board *board, uint8_t *buffer, size_t length,
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
-static int fluke_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fluke_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct fluke_priv *priv = board->private_data;
@@ -70,7 +72,7 @@ static int fluke_write(struct gpib_board *board, uint8_t *buffer, size_t length,
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int fluke_command(struct gpib_board *board, uint8_t *buffer,
+static int fluke_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct fluke_priv *priv = board->private_data;
@@ -92,12 +94,12 @@ static int fluke_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void fluke_request_system_control(struct gpib_board *board, int request_control)
+static int fluke_request_system_control(struct gpib_board *board, int request_control)
{
struct fluke_priv *priv = board->private_data;
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
- nec7210_request_system_control(board, nec_priv, request_control);
+ return nec7210_request_system_control(board, nec_priv, request_control);
}
static void fluke_interface_clear(struct gpib_board *board, int assert)
@@ -114,7 +116,7 @@ static void fluke_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int fluke_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int fluke_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct fluke_priv *priv = board->private_data;
@@ -149,14 +151,14 @@ static int fluke_secondary_address(struct gpib_board *board, unsigned int addres
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int fluke_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int fluke_parallel_poll(struct gpib_board *board, u8 *result)
{
struct fluke_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-static void fluke_parallel_poll_configure(struct gpib_board *board, uint8_t configuration)
+static void fluke_parallel_poll_configure(struct gpib_board *board, u8 configuration)
{
struct fluke_priv *priv = board->private_data;
@@ -170,14 +172,14 @@ static void fluke_parallel_poll_response(struct gpib_board *board, int ist)
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-static void fluke_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void fluke_serial_poll_response(struct gpib_board *board, u8 status)
{
struct fluke_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-static uint8_t fluke_serial_poll_status(struct gpib_board *board)
+static u8 fluke_serial_poll_status(struct gpib_board *board)
{
struct fluke_priv *priv = board->private_data;
@@ -254,7 +256,8 @@ static int lacs_or_read_ready(struct gpib_board *board)
return retval;
}
-/* Wait until it is possible for a read to do something useful. This
+/*
+ * Wait until it is possible for a read to do something useful. This
* is not essential, it only exists to prevent RFD holdoff from being released pointlessly.
*/
static int wait_for_read(struct gpib_board *board)
@@ -276,7 +279,8 @@ static int wait_for_read(struct gpib_board *board)
return retval;
}
-/* Check if the SH state machine is in SGNS. We check twice since there is a very small chance
+/*
+ * Check if the SH state machine is in SGNS. We check twice since there is a very small chance
* we could be blowing through SGNS from SIDS to SDYS if there is already a
* byte available in the handshake state machine. We are interested
* in the case where the handshake is stuck in SGNS due to no byte being
@@ -310,7 +314,8 @@ static int source_handshake_is_sids_or_sgns(struct fluke_priv *e_priv)
(source_handshake_bits == SOURCE_HANDSHAKE_SIDS_BITS);
}
-/* Wait until the gpib chip is ready to accept a data out byte.
+/*
+ * Wait until the gpib chip is ready to accept a data out byte.
* If the chip is SGNS it is probably waiting for a a byte to
* be written to it.
*/
@@ -371,7 +376,7 @@ static void fluke_dma_callback(void *arg)
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static int fluke_dma_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fluke_dma_write(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct fluke_priv *e_priv = board->private_data;
@@ -441,7 +446,8 @@ static int fluke_dma_write(struct gpib_board *board, uint8_t *buffer, size_t len
if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state))
fluke_dma_callback(board);
- /* if everything went fine, try to wait until last byte is actually
+ /*
+ * if everything went fine, try to wait until last byte is actually
* transmitted across gpib (but don't try _too_ hard)
*/
if (retval == 0)
@@ -456,7 +462,7 @@ cleanup:
return retval;
}
-static int fluke_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fluke_accel_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct fluke_priv *e_priv = board->private_data;
@@ -508,7 +514,8 @@ static int fluke_accel_write(struct gpib_board *board, uint8_t *buffer, size_t l
if (WARN_ON_ONCE(remainder != 1))
return -EFAULT;
- /* wait until we are sure we will be able to write the data byte
+ /*
+ * wait until we are sure we will be able to write the data byte
* into the chip before we send AUX_SEOI. This prevents a timeout
* scenerio where we send AUX_SEOI but then timeout without getting
* any bytes into the gpib chip. This will result in the first byte
@@ -539,12 +546,14 @@ static int fluke_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie)
return result;
}
dmaengine_tx_status(chan, cookie, &state);
- // hardware doesn't support resume, so dont call this
- // method unless the dma transfer is done.
+ /*
+ * hardware doesn't support resume, so dont call this
+ * method unless the dma transfer is done.
+ */
return state.residue;
}
-static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer,
+static int fluke_dma_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct fluke_priv *e_priv = board->private_data;
@@ -608,7 +617,8 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer,
if (test_bit(DEV_CLEAR_BN, &nec_priv->state))
retval = -EINTR;
- /* If we woke up because of end, wait until the dma transfer has pulled
+ /*
+ * If we woke up because of end, wait until the dma transfer has pulled
* the data byte associated with the end before we cancel the dma transfer.
*/
if (test_bit(RECEIVED_END_BN, &nec_priv->state)) {
@@ -625,7 +635,8 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer,
// stop the dma transfer
nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0);
- /* delay a little just to make sure any bytes in dma controller's fifo get
+ /*
+ * delay a little just to make sure any bytes in dma controller's fifo get
* written to memory before we disable it
*/
usleep_range(10, 15);
@@ -641,14 +652,17 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer,
dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE);
memcpy(buffer, e_priv->dma_buffer, *bytes_read);
- /* If we got an end interrupt, figure out if it was
+ /*
+ * If we got an end interrupt, figure out if it was
* associated with the last byte we dma'd or with a
* byte still sitting on the cb7210.
*/
spin_lock_irqsave(&board->spinlock, flags);
if (test_bit(READ_READY_BN, &nec_priv->state) == 0) {
- // There is no byte sitting on the cb7210. If we
- // saw an end interrupt, we need to deal with it now
+ /*
+ * There is no byte sitting on the cb7210. If we
+ * saw an end interrupt, we need to deal with it now
+ */
if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state))
*end = 1;
}
@@ -657,7 +671,7 @@ static int fluke_dma_read(struct gpib_board *board, uint8_t *buffer,
return retval;
}
-static int fluke_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fluke_accel_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct fluke_priv *e_priv = board->private_data;
@@ -698,7 +712,7 @@ static int fluke_accel_read(struct gpib_board *board, uint8_t *buffer, size_t le
return retval;
}
-static gpib_interface_t fluke_unaccel_interface = {
+static struct gpib_interface fluke_unaccel_interface = {
.name = "fluke_unaccel",
.attach = fluke_attach_holdoff_all,
.detach = fluke_detach,
@@ -725,7 +739,8 @@ static gpib_interface_t fluke_unaccel_interface = {
.return_to_local = fluke_return_to_local,
};
-/* fluke_hybrid uses dma for writes but not for reads. Added
+/*
+ * fluke_hybrid uses dma for writes but not for reads. Added
* to deal with occasional corruption of bytes seen when doing dma
* reads. From looking at the cb7210 vhdl, I believe the corruption
* is due to a hardware bug triggered by the cpu reading a cb7210
@@ -733,7 +748,7 @@ static gpib_interface_t fluke_unaccel_interface = {
* register just as the dma controller is also doing a read.
*/
-static gpib_interface_t fluke_hybrid_interface = {
+static struct gpib_interface fluke_hybrid_interface = {
.name = "fluke_hybrid",
.attach = fluke_attach_holdoff_all,
.detach = fluke_detach,
@@ -760,7 +775,7 @@ static gpib_interface_t fluke_hybrid_interface = {
.return_to_local = fluke_return_to_local,
};
-static gpib_interface_t fluke_interface = {
+static struct gpib_interface fluke_interface = {
.name = "fluke",
.attach = fluke_attach_holdoff_end,
.detach = fluke_detach,
@@ -802,7 +817,7 @@ irqreturn_t fluke_gpib_internal_interrupt(struct gpib_board *board)
status2 = read_byte(nec_priv, ISR2);
if (status0 & FLUKE_IFCI_BIT) {
- push_gpib_event(board, EventIFC);
+ push_gpib_event(board, EVENT_IFC);
retval = IRQ_HANDLED;
}
@@ -914,7 +929,8 @@ static int fluke_init(struct fluke_priv *e_priv, struct gpib_board *board, int h
nec7210_board_reset(nec_priv, board);
write_byte(nec_priv, AUX_LO_SPEED, AUXMR);
- /* set clock register for driving frequency
+ /*
+ * set clock register for driving frequency
* ICR should be set to clock in megahertz (1-15) and to zero
* for clocks faster than 15 MHz (max 20MHz)
*/
@@ -933,7 +949,8 @@ static int fluke_init(struct fluke_priv *e_priv, struct gpib_board *board, int h
return 0;
}
-/* This function is passed to dma_request_channel() in order to
+/*
+ * This function is passed to dma_request_channel() in order to
* select the pl330 dma channel which has been hardwired to
* the gpib controller.
*/
@@ -943,7 +960,7 @@ static bool gpib_dma_channel_filter(struct dma_chan *chan, void *filter_param)
return chan->chan_id == 0;
}
-static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t *config,
+static int fluke_attach_impl(struct gpib_board *board, const struct gpib_board_config *config,
unsigned int handshake_mode)
{
struct fluke_priv *e_priv;
@@ -1024,10 +1041,8 @@ static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t
}
irq = platform_get_irq(fluke_gpib_pdev, 0);
- if (irq < 0) {
- dev_err(&fluke_gpib_pdev->dev, "failed to obtain IRQ\n");
+ if (irq < 0)
return -EBUSY;
- }
retval = request_irq(irq, fluke_gpib_interrupt, isr_flags, fluke_gpib_pdev->name, board);
if (retval) {
dev_err(&fluke_gpib_pdev->dev,
@@ -1042,19 +1057,21 @@ static int fluke_attach_impl(struct gpib_board *board, const gpib_board_config_t
e_priv->dma_channel = dma_request_channel(dma_cap, gpib_dma_channel_filter, NULL);
if (!e_priv->dma_channel) {
dev_err(board->gpib_dev, "failed to allocate a dma channel.\n");
- // we don't error out here because unaccel interface will still
- // work without dma
+ /*
+ * we don't error out here because unaccel interface will still
+ * work without dma
+ */
}
return fluke_init(e_priv, board, handshake_mode);
}
-int fluke_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config)
+int fluke_attach_holdoff_all(struct gpib_board *board, const struct gpib_board_config *config)
{
return fluke_attach_impl(board, config, HR_HLDA);
}
-int fluke_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config)
+int fluke_attach_holdoff_end(struct gpib_board *board, const struct gpib_board_config *config)
{
return fluke_attach_impl(board, config, HR_HLDE);
}
diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.h b/drivers/staging/gpib/eastwood/fluke_gpib.h
index 3e4348196b42..493c200d0bbf 100644
--- a/drivers/staging/gpib/eastwood/fluke_gpib.h
+++ b/drivers/staging/gpib/eastwood/fluke_gpib.h
@@ -55,8 +55,10 @@ enum state1_bits {
SOURCE_HANDSHAKE_MASK = 0x7
};
-// we customized the cb7210 vhdl to give the "data in" status
-// on the unused bit 7 of the address0 register.
+/*
+ * we customized the cb7210 vhdl to give the "data in" status
+ * on the unused bit 7 of the address0 register.
+ */
enum cb7210_address0 {
DATA_IN_STATUS = 0x80
};
@@ -67,8 +69,8 @@ static inline int cb7210_page_in_bits(unsigned int page)
}
// don't use without locking nec_priv->register_page_lock
-static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
- int register_num)
+static inline u8 fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
+ int register_num)
{
u8 retval;
@@ -77,14 +79,14 @@ static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv,
}
// don't use without locking nec_priv->register_page_lock
-static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, uint8_t data,
+static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, u8 data,
int register_num)
{
writel(data, nec_priv->mmiobase + register_num * nec_priv->offset);
}
-static inline uint8_t fluke_paged_read_byte(struct fluke_priv *e_priv,
- unsigned int register_num, unsigned int page)
+static inline u8 fluke_paged_read_byte(struct fluke_priv *e_priv,
+ unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
u8 retval;
@@ -99,7 +101,7 @@ static inline uint8_t fluke_paged_read_byte(struct fluke_priv *e_priv,
return retval;
}
-static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, uint8_t data,
+static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, u8 data,
unsigned int register_num, unsigned int page)
{
struct nec7210_priv *nec_priv = &e_priv->nec7210_priv;
@@ -124,11 +126,12 @@ enum bus_status_bits {
};
enum cb7210_aux_cmds {
-/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
- * (and keep asserted) local rtl message. This is used in conjunction
- * with the (stupid) cb7210 implementation
- * of the normal nec7210 AUX_RTL aux command, which
- * causes the rtl message to toggle between on and off.
+/*
+ * AUX_RTL2 is an undocumented aux command which causes cb7210 to assert
+ * (and keep asserted) local rtl message. This is used in conjunction
+ * with the (stupid) cb7210 implementation
+ * of the normal nec7210 AUX_RTL aux command, which
+ * causes the rtl message to toggle between on and off.
*/
AUX_RTL2 = 0xd,
AUX_NBAF = 0xe, // new byte available false (also clears seoi)
diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c
index 53f4b3fccc3c..4138f3d2bae7 100644
--- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c
+++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c
@@ -32,13 +32,15 @@ MODULE_DESCRIPTION("GPIB Driver for fmh_gpib_core");
MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>");
static irqreturn_t fmh_gpib_interrupt(int irq, void *arg);
-static int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config);
-static int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config);
+static int fmh_gpib_attach_holdoff_all(struct gpib_board *board,
+ const struct gpib_board_config *config);
+static int fmh_gpib_attach_holdoff_end(struct gpib_board *board,
+ const struct gpib_board_config *config);
static void fmh_gpib_detach(struct gpib_board *board);
static int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board,
- const gpib_board_config_t *config);
+ const struct gpib_board_config *config);
static int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board,
- const gpib_board_config_t *config);
+ const struct gpib_board_config *config);
static void fmh_gpib_pci_detach(struct gpib_board *board);
static int fmh_gpib_config_dma(struct gpib_board *board, int output);
static irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board);
@@ -46,7 +48,7 @@ static struct platform_driver fmh_gpib_platform_driver;
static struct pci_driver fmh_gpib_pci_driver;
// wrappers for interface functions
-static int fmh_gpib_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct fmh_priv *priv = board->private_data;
@@ -54,7 +56,7 @@ static int fmh_gpib_read(struct gpib_board *board, uint8_t *buffer, size_t lengt
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
-static int fmh_gpib_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct fmh_priv *priv = board->private_data;
@@ -62,7 +64,7 @@ static int fmh_gpib_write(struct gpib_board *board, uint8_t *buffer, size_t leng
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int fmh_gpib_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct fmh_priv *priv = board->private_data;
@@ -84,12 +86,12 @@ static int fmh_gpib_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void fmh_gpib_request_system_control(struct gpib_board *board, int request_control)
+static int fmh_gpib_request_system_control(struct gpib_board *board, int request_control)
{
struct fmh_priv *priv = board->private_data;
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
- nec7210_request_system_control(board, nec_priv, request_control);
+ return nec7210_request_system_control(board, nec_priv, request_control);
}
static void fmh_gpib_interface_clear(struct gpib_board *board, int assert)
@@ -106,7 +108,7 @@ static void fmh_gpib_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int fmh_gpib_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int fmh_gpib_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct fmh_priv *priv = board->private_data;
@@ -141,14 +143,14 @@ static int fmh_gpib_secondary_address(struct gpib_board *board, unsigned int add
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int fmh_gpib_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int fmh_gpib_parallel_poll(struct gpib_board *board, u8 *result)
{
struct fmh_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-static void fmh_gpib_parallel_poll_configure(struct gpib_board *board, uint8_t configuration)
+static void fmh_gpib_parallel_poll_configure(struct gpib_board *board, u8 configuration)
{
struct fmh_priv *priv = board->private_data;
@@ -169,7 +171,8 @@ static void fmh_gpib_local_parallel_poll_mode(struct gpib_board *board, int loca
if (local) {
write_byte(&priv->nec7210_priv, AUX_I_REG | LOCAL_PPOLL_MODE_BIT, AUXMR);
} else {
- /* For fmh_gpib_core, remote parallel poll config mode is unaffected by the
+ /*
+ * For fmh_gpib_core, remote parallel poll config mode is unaffected by the
* state of the disable bit of the parallel poll register (unlike the tnt4882).
* So, we don't need to worry about that.
*/
@@ -177,7 +180,7 @@ static void fmh_gpib_local_parallel_poll_mode(struct gpib_board *board, int loca
}
}
-static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t status,
+static void fmh_gpib_serial_poll_response2(struct gpib_board *board, u8 status,
int new_reason_for_service)
{
struct fmh_priv *priv = board->private_data;
@@ -195,7 +198,8 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta
}
if (reqt) {
- /* It may seem like a race to issue reqt before updating
+ /*
+ * It may seem like a race to issue reqt before updating
* the status byte, but it is not. The chip does not
* issue the reqt until the SPMR is written to at
* a later time.
@@ -204,7 +208,8 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta
} else if (reqf) {
write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR);
}
- /* We need to always zero bit 6 of the status byte before writing it to
+ /*
+ * We need to always zero bit 6 of the status byte before writing it to
* the SPMR to insure we are using
* serial poll mode SP1, and not accidentally triggering mode SP3.
*/
@@ -212,7 +217,7 @@ static void fmh_gpib_serial_poll_response2(struct gpib_board *board, uint8_t sta
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static uint8_t fmh_gpib_serial_poll_status(struct gpib_board *board)
+static u8 fmh_gpib_serial_poll_status(struct gpib_board *board)
{
struct fmh_priv *priv = board->private_data;
@@ -333,7 +338,8 @@ static int wait_for_rx_fifo_half_full_or_end(struct gpib_board *board)
return retval;
}
-/* Wait until the gpib chip is ready to accept a data out byte.
+/*
+ * Wait until the gpib chip is ready to accept a data out byte.
*/
static int wait_for_data_out_ready(struct gpib_board *board)
{
@@ -377,7 +383,8 @@ static void fmh_gpib_dma_callback(void *arg)
spin_unlock_irqrestore(&board->spinlock, flags);
}
-/* returns true when all the bytes of a write have been transferred to
+/*
+ * returns true when all the bytes of a write have been transferred to
* the chip and successfully transferred out over the gpib bus.
*/
static int fmh_gpib_all_bytes_are_sent(struct fmh_priv *e_priv)
@@ -391,7 +398,7 @@ static int fmh_gpib_all_bytes_are_sent(struct fmh_priv *e_priv)
return 1;
}
-static int fmh_gpib_dma_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_dma_write(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct fmh_priv *e_priv = board->private_data;
@@ -469,7 +476,7 @@ cleanup:
return retval;
}
-static int fmh_gpib_accel_write(struct gpib_board *board, uint8_t *buffer,
+static int fmh_gpib_accel_write(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
struct fmh_priv *e_priv = board->private_data;
@@ -523,7 +530,8 @@ static int fmh_gpib_accel_write(struct gpib_board *board, uint8_t *buffer,
if (WARN_ON_ONCE(remainder != 1))
return -EFAULT;
- /* wait until we are sure we will be able to write the data byte
+ /*
+ * wait until we are sure we will be able to write the data byte
* into the chip before we send AUX_SEOI. This prevents a timeout
* scenario where we send AUX_SEOI but then timeout without getting
* any bytes into the gpib chip. This will result in the first byte
@@ -554,8 +562,10 @@ static int fmh_gpib_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie)
return result;
}
dmaengine_tx_status(chan, cookie, &state);
- // dma330 hardware doesn't support resume, so dont call this
- // method unless the dma transfer is done.
+ /*
+ * dma330 hardware doesn't support resume, so dont call this
+ * method unless the dma transfer is done.
+ */
return state.residue;
}
@@ -581,10 +591,11 @@ static int wait_for_tx_fifo_half_empty(struct gpib_board *board)
return retval;
}
-/* supports writing a chunk of data whose length must fit into the hardware'd xfer counter,
+/*
+ * supports writing a chunk of data whose length must fit into the hardware'd xfer counter,
* called in a loop by fmh_gpib_fifo_write()
*/
-static int fmh_gpib_fifo_write_countable(struct gpib_board *board, uint8_t *buffer,
+static int fmh_gpib_fifo_write_countable(struct gpib_board *board, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written)
{
struct fmh_priv *e_priv = board->private_data;
@@ -650,7 +661,7 @@ cleanup:
return retval;
}
-static int fmh_gpib_fifo_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_fifo_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct fmh_priv *e_priv = board->private_data;
@@ -697,7 +708,7 @@ static int fmh_gpib_fifo_write(struct gpib_board *board, uint8_t *buffer, size_t
return retval;
}
-static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer,
+static int fmh_gpib_dma_read(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct fmh_priv *e_priv = board->private_data;
@@ -768,8 +779,10 @@ static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer,
// stop the dma transfer
nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0);
fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG);
- // give time for pl330 to transfer any in-flight data, since
- // pl330 will throw it away when dmaengine_pause is called.
+ /*
+ * give time for pl330 to transfer any in-flight data, since
+ * pl330 will throw it away when dmaengine_pause is called.
+ */
usleep_range(10, 15);
residue = fmh_gpib_get_dma_residue(e_priv->dma_channel, dma_cookie);
if (WARN_ON_ONCE(residue > length || residue < 0))
@@ -793,14 +806,17 @@ static int fmh_gpib_dma_read(struct gpib_board *board, uint8_t *buffer,
buffer[(*bytes_read)++] = fifos_read(e_priv, FIFO_DATA_REG) & fifo_data_mask;
}
- /* If we got an end interrupt, figure out if it was
+ /*
+ * If we got an end interrupt, figure out if it was
* associated with the last byte we dma'd or with a
* byte still sitting on the cb7210.
*/
spin_lock_irqsave(&board->spinlock, flags);
if (*bytes_read > 0 && test_bit(READ_READY_BN, &nec_priv->state) == 0) {
- // If there is no byte sitting on the cb7210 and we
- // saw an end, we need to deal with it now
+ /*
+ * If there is no byte sitting on the cb7210 and we
+ * saw an end, we need to deal with it now
+ */
if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state))
*end = 1;
}
@@ -819,7 +835,8 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr
ext_status_1 = read_byte(nec_priv, EXT_STATUS_1_REG);
- /* if there is an end byte sitting on the chip, don't release
+ /*
+ * if there is an end byte sitting on the chip, don't release
* holdoff. We want it left set after we read out the end
* byte.
*/
@@ -828,7 +845,8 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr
if (ext_status_1 & RFD_HOLDOFF_STATUS_BIT)
write_byte(nec_priv, AUX_FH, AUXMR);
- /* Check if an end byte raced in before we executed the AUX_FH command.
+ /*
+ * Check if an end byte raced in before we executed the AUX_FH command.
* If it did, we want to make sure the rfd holdoff is in effect. The end
* byte can arrive since
* AUX_RFD_HOLDOFF_ASAP doesn't immediately force the acceptor handshake
@@ -846,7 +864,7 @@ static void fmh_gpib_release_rfd_holdoff(struct gpib_board *board, struct fmh_pr
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static int fmh_gpib_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_accel_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct fmh_priv *e_priv = board->private_data;
@@ -893,10 +911,11 @@ static int fmh_gpib_accel_read(struct gpib_board *board, uint8_t *buffer, size_t
return retval;
}
-/* Read a chunk of data whose length is within the limits of the hardware's
+/*
+ * Read a chunk of data whose length is within the limits of the hardware's
* xfer counter. Called in a loop from fmh_gpib_fifo_read().
*/
-static int fmh_gpib_fifo_read_countable(struct gpib_board *board, uint8_t *buffer,
+static int fmh_gpib_fifo_read_countable(struct gpib_board *board, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
struct fmh_priv *e_priv = board->private_data;
@@ -954,7 +973,7 @@ cleanup:
return retval;
}
-static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int fmh_gpib_fifo_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct fmh_priv *e_priv = board->private_data;
@@ -969,7 +988,8 @@ static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t
*end = 0;
*bytes_read = 0;
- /* Do a little prep with data in interrupt so that following wait_for_read()
+ /*
+ * Do a little prep with data in interrupt so that following wait_for_read()
* will wake up if a data byte is received.
*/
nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, HR_DIIE);
@@ -1011,7 +1031,7 @@ static int fmh_gpib_fifo_read(struct gpib_board *board, uint8_t *buffer, size_t
return retval;
}
-static gpib_interface_t fmh_gpib_unaccel_interface = {
+static struct gpib_interface fmh_gpib_unaccel_interface = {
.name = "fmh_gpib_unaccel",
.attach = fmh_gpib_attach_holdoff_all,
.detach = fmh_gpib_detach,
@@ -1039,7 +1059,7 @@ static gpib_interface_t fmh_gpib_unaccel_interface = {
.return_to_local = fmh_gpib_return_to_local,
};
-static gpib_interface_t fmh_gpib_interface = {
+static struct gpib_interface fmh_gpib_interface = {
.name = "fmh_gpib",
.attach = fmh_gpib_attach_holdoff_end,
.detach = fmh_gpib_detach,
@@ -1067,7 +1087,7 @@ static gpib_interface_t fmh_gpib_interface = {
.return_to_local = fmh_gpib_return_to_local,
};
-static gpib_interface_t fmh_gpib_pci_interface = {
+static struct gpib_interface fmh_gpib_pci_interface = {
.name = "fmh_gpib_pci",
.attach = fmh_gpib_pci_attach_holdoff_end,
.detach = fmh_gpib_pci_detach,
@@ -1095,7 +1115,7 @@ static gpib_interface_t fmh_gpib_pci_interface = {
.return_to_local = fmh_gpib_return_to_local,
};
-static gpib_interface_t fmh_gpib_pci_unaccel_interface = {
+static struct gpib_interface fmh_gpib_pci_unaccel_interface = {
.name = "fmh_gpib_pci_unaccel",
.attach = fmh_gpib_pci_attach_holdoff_all,
.detach = fmh_gpib_pci_detach,
@@ -1136,7 +1156,7 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board)
fifo_status = fifos_read(priv, FIFO_CONTROL_STATUS_REG);
if (status0 & IFC_INTERRUPT_BIT) {
- push_gpib_event(board, EventIFC);
+ push_gpib_event(board, EVENT_IFC);
retval = IRQ_HANDLED;
}
@@ -1166,7 +1186,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board)
clear_bit(RFD_HOLDOFF_BN, &nec_priv->state);
if (ext_status_1 & END_STATUS_BIT) {
- /* only set RECEIVED_END while there is still a data
+ /*
+ * only set RECEIVED_END while there is still a data
* byte sitting in the chip, to avoid spuriously
* setting it multiple times after it has been cleared
* during a read.
@@ -1179,7 +1200,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board)
if ((fifo_status & TX_FIFO_HALF_EMPTY_INTERRUPT_IS_ENABLED) &&
(fifo_status & TX_FIFO_HALF_EMPTY)) {
- /* We really only want to clear the
+ /*
+ * We really only want to clear the
* TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE bit in the
* FIFO_CONTROL_STATUS_REG. Since we are not being
* careful, this also has a side effect of disabling
@@ -1193,7 +1215,8 @@ irqreturn_t fmh_gpib_internal_interrupt(struct gpib_board *board)
if ((fifo_status & RX_FIFO_HALF_FULL_INTERRUPT_IS_ENABLED) &&
(fifo_status & RX_FIFO_HALF_FULL)) {
- /* We really only want to clear the
+ /*
+ * We really only want to clear the
* RX_FIFO_HALF_FULL_INTERRUPT_ENABLE bit in the
* FIFO_CONTROL_STATUS_REG. Since we are not being
* careful, this also has a side effect of disabling
@@ -1335,7 +1358,7 @@ static int fmh_gpib_init(struct fmh_priv *e_priv, struct gpib_board *board, int
/* Match callback for driver_find_device */
static int fmh_gpib_device_match(struct device *dev, const void *data)
{
- const gpib_board_config_t *config = data;
+ const struct gpib_board_config *config = data;
if (dev_get_drvdata(dev))
return 0;
@@ -1351,7 +1374,7 @@ static int fmh_gpib_device_match(struct device *dev, const void *data)
return 1;
}
-static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_config_t *config,
+static int fmh_gpib_attach_impl(struct gpib_board *board, const struct gpib_board_config *config,
unsigned int handshake_mode, int acquire_dma)
{
struct fmh_priv *e_priv;
@@ -1424,10 +1447,8 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi
(unsigned long)resource_size(e_priv->dma_port_res));
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(board->dev, "request for IRQ failed\n");
+ if (irq < 0)
return -EBUSY;
- }
retval = request_irq(irq, fmh_gpib_interrupt, IRQF_SHARED, pdev->name, board);
if (retval) {
dev_err(board->dev,
@@ -1444,7 +1465,8 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi
return -EIO;
}
}
- /* in the future we might want to know the half-fifo size
+ /*
+ * in the future we might want to know the half-fifo size
* (dma_burst_length) even when not using dma, so go ahead an
* initialize it unconditionally.
*/
@@ -1454,12 +1476,12 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const gpib_board_confi
return fmh_gpib_init(e_priv, board, handshake_mode);
}
-int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config)
+int fmh_gpib_attach_holdoff_all(struct gpib_board *board, const struct gpib_board_config *config)
{
return fmh_gpib_attach_impl(board, config, HR_HLDA, 0);
}
-int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config)
+int fmh_gpib_attach_holdoff_end(struct gpib_board *board, const struct gpib_board_config *config)
{
return fmh_gpib_attach_impl(board, config, HR_HLDE, 1);
}
@@ -1497,7 +1519,8 @@ void fmh_gpib_detach(struct gpib_board *board)
fmh_gpib_generic_detach(board);
}
-static int fmh_gpib_pci_attach_impl(struct gpib_board *board, const gpib_board_config_t *config,
+static int fmh_gpib_pci_attach_impl(struct gpib_board *board,
+ const struct gpib_board_config *config,
unsigned int handshake_mode)
{
struct fmh_priv *e_priv;
@@ -1570,12 +1593,14 @@ static int fmh_gpib_pci_attach_impl(struct gpib_board *board, const gpib_board_c
return fmh_gpib_init(e_priv, board, handshake_mode);
}
-int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board, const gpib_board_config_t *config)
+int fmh_gpib_pci_attach_holdoff_all(struct gpib_board *board,
+ const struct gpib_board_config *config)
{
return fmh_gpib_pci_attach_impl(board, config, HR_HLDA);
}
-int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board, const gpib_board_config_t *config)
+int fmh_gpib_pci_attach_holdoff_end(struct gpib_board *board,
+ const struct gpib_board_config *config)
{
int retval;
struct fmh_priv *e_priv;
@@ -1631,7 +1656,6 @@ MODULE_DEVICE_TABLE(of, fmh_gpib_of_match);
static struct platform_driver fmh_gpib_platform_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE,
.of_match_table = fmh_gpib_of_match,
},
.probe = &fmh_gpib_platform_probe
diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.h b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h
index de6fd2164414..e7602d7e1401 100644
--- a/drivers/staging/gpib/fmh_gpib/fmh_gpib.h
+++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h
@@ -124,13 +124,13 @@ static const unsigned int fifo_data_mask = 0x00ff;
static const unsigned int fifo_xfer_counter_mask = 0x0fff;
static const unsigned int fifo_max_burst_length_mask = 0x00ff;
-static inline uint8_t gpib_cs_read_byte(struct nec7210_priv *nec_priv,
- unsigned int register_num)
+static inline u8 gpib_cs_read_byte(struct nec7210_priv *nec_priv,
+ unsigned int register_num)
{
return readb(nec_priv->mmiobase + register_num * nec_priv->offset);
}
-static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, uint8_t data,
+static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, u8 data,
unsigned int register_num)
{
writeb(data, nec_priv->mmiobase + register_num * nec_priv->offset);
diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c
index 86bdd381472a..625fef24a0bf 100644
--- a/drivers/staging/gpib/gpio/gpib_bitbang.c
+++ b/drivers/staging/gpib/gpio/gpib_bitbang.c
@@ -32,7 +32,8 @@
#define ENABLE_IRQ(IRQ, TYPE) irq_set_irq_type(IRQ, TYPE)
#define DISABLE_IRQ(IRQ) irq_set_irq_type(IRQ, IRQ_TYPE_NONE)
-/* Debug print levels:
+/*
+ * Debug print levels:
* 0 = load/unload info and errors that make the driver fail;
* 1 = + warnings for unforeseen events that may break the current
* operation and lead to a timeout, but do not affect the
@@ -65,7 +66,6 @@
#include <linux/gpio/machine.h>
#include <linux/gpio.h>
#include <linux/irq.h>
-#include <linux/leds.h>
static int sn7516x_used = 1, sn7516x;
module_param(sn7516x_used, int, 0660);
@@ -135,19 +135,14 @@ enum lines_t {
#define SN7516X_PINS 4
#define NUM_PINS (GPIB_PINS + SN7516X_PINS)
-DEFINE_LED_TRIGGER(ledtrig_gpib);
-#define ACT_LED_ON do { \
+#define ACT_LED_ON do { \
if (ACT_LED) \
- gpiod_direction_output(ACT_LED, 1); \
- else \
- led_trigger_event(ledtrig_gpib, LED_FULL); } \
- while (0)
-#define ACT_LED_OFF do { \
+ gpiod_direction_output(ACT_LED, 1); \
+ } while (0)
+#define ACT_LED_OFF do { \
if (ACT_LED) \
- gpiod_direction_output(ACT_LED, 0); \
- else \
- led_trigger_event(ledtrig_gpib, LED_OFF); } \
- while (0)
+ gpiod_direction_output(ACT_LED, 0); \
+ } while (0)
static struct gpio_desc *all_descriptors[GPIB_PINS + SN7516X_PINS];
@@ -311,7 +306,6 @@ struct bb_priv {
int dav_seq;
long all_irqs;
int dav_idle;
- int atn_asserted;
enum talker_function_state talker_state;
enum listener_function_state listener_state;
@@ -324,7 +318,7 @@ static void set_data_lines(u8 byte);
static u8 get_data_lines(void);
static void set_data_lines_input(void);
static void set_data_lines_output(void);
-static inline int check_for_eos(struct bb_priv *priv, uint8_t byte);
+static inline int check_for_eos(struct bb_priv *priv, u8 byte);
static void set_atn(struct gpib_board *board, int atn_asserted);
static inline void SET_DIR_WRITE(struct bb_priv *priv);
@@ -353,7 +347,7 @@ static char printable(char x)
* *
***************************************************************************/
-static int bb_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int bb_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct bb_priv *priv = board->private_data;
@@ -491,7 +485,7 @@ dav_exit:
* *
***************************************************************************/
-static int bb_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int bb_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
unsigned long flags;
@@ -522,7 +516,7 @@ static int bb_write(struct gpib_board *board, uint8_t *buffer, size_t length,
gpiod_get_value(NRFD), gpiod_get_value(NDAC));
if (gpiod_get_value(NRFD) && gpiod_get_value(NDAC)) { /* check for listener */
- retval = -ENODEV;
+ retval = -ENOTCONN;
goto write_end;
}
@@ -619,7 +613,8 @@ static irqreturn_t bb_NRFD_interrupt(int irq, void *arg)
goto nrfd_exit;
}
- if (priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer
+ if (priv->w_cnt >= priv->length) { // test for missed NDAC end of transfer
+ dev_err(board->gpib_dev, "Unexpected NRFD exit\n");
priv->write_done = 1;
priv->w_busy = 0;
wake_up_interruptible(&board->wait);
@@ -691,14 +686,14 @@ static irqreturn_t bb_NDAC_interrupt(int irq, void *arg)
dbg_printk(3, "accepted %zu\n", priv->w_cnt - 1);
- if (!priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer
+ gpiod_set_value(DAV, 1); // Data not available
+ priv->dav_tx = 1;
+ priv->phase = 510;
+
+ if (priv->w_cnt >= priv->length) { // test for end of transfer
priv->write_done = 1;
priv->w_busy = 0;
wake_up_interruptible(&board->wait);
- } else {
- gpiod_set_value(DAV, 1); // Data not available
- priv->dav_tx = 1;
- priv->phase = 510;
}
ndac_exit:
@@ -728,7 +723,7 @@ static irqreturn_t bb_SRQ_interrupt(int irq, void *arg)
return IRQ_HANDLED;
}
-static int bb_command(struct gpib_board *board, uint8_t *buffer,
+static int bb_command(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
size_t ret;
@@ -855,6 +850,7 @@ static void set_atn(struct gpib_board *board, int atn_asserted)
priv->listener_state = listener_addressed;
if (priv->talker_state == talker_active)
priv->talker_state = talker_addressed;
+ SET_DIR_WRITE(priv); // need to be able to read bus NRFD/NDAC
} else {
if (priv->listener_state == listener_addressed) {
priv->listener_state = listener_active;
@@ -864,14 +860,12 @@ static void set_atn(struct gpib_board *board, int atn_asserted)
priv->talker_state = talker_active;
}
gpiod_direction_output(_ATN, !atn_asserted);
- priv->atn_asserted = atn_asserted;
}
static int bb_take_control(struct gpib_board *board, int synchronous)
{
dbg_printk(2, "%d\n", synchronous);
set_atn(board, 1);
- set_bit(CIC_NUM, &board->status);
return 0;
}
@@ -882,16 +876,24 @@ static int bb_go_to_standby(struct gpib_board *board)
return 0;
}
-static void bb_request_system_control(struct gpib_board *board, int request_control)
+static int bb_request_system_control(struct gpib_board *board, int request_control)
{
+ struct bb_priv *priv = board->private_data;
+
dbg_printk(2, "%d\n", request_control);
- if (request_control) {
- set_bit(CIC_NUM, &board->status);
- // drive DAV & EOI false, enable NRFD & NDAC irqs
- SET_DIR_WRITE(board->private_data);
- } else {
- clear_bit(CIC_NUM, &board->status);
- }
+ if (!request_control)
+ return -EINVAL;
+
+ gpiod_direction_output(REN, 1); /* user space must enable REN if needed */
+ gpiod_direction_output(IFC, 1); /* user space must toggle IFC if needed */
+ if (sn7516x)
+ gpiod_direction_output(DC, 0); /* enable ATN as output on SN75161/2 */
+
+ gpiod_direction_input(SRQ);
+
+ ENABLE_IRQ(priv->irq_SRQ, IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
}
static void bb_interface_clear(struct gpib_board *board, int assert)
@@ -903,6 +905,7 @@ static void bb_interface_clear(struct gpib_board *board, int assert)
gpiod_direction_output(IFC, 0);
priv->talker_state = talker_idle;
priv->listener_state = listener_idle;
+ set_bit(CIC_NUM, &board->status);
} else {
gpiod_direction_output(IFC, 1);
}
@@ -920,7 +923,7 @@ static void bb_remote_enable(struct gpib_board *board, int enable)
}
}
-static int bb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int bb_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct bb_priv *priv = board->private_data;
@@ -987,12 +990,12 @@ static int bb_secondary_address(struct gpib_board *board, unsigned int address,
return 0;
}
-static int bb_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int bb_parallel_poll(struct gpib_board *board, u8 *result)
{
return -ENOENT;
}
-static void bb_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void bb_parallel_poll_configure(struct gpib_board *board, u8 config)
{
}
@@ -1000,11 +1003,11 @@ static void bb_parallel_poll_response(struct gpib_board *board, int ist)
{
}
-static void bb_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void bb_serial_poll_response(struct gpib_board *board, u8 status)
{
}
-static uint8_t bb_serial_poll_status(struct gpib_board *board)
+static u8 bb_serial_poll_status(struct gpib_board *board)
{
return 0; // -ENOENT;
}
@@ -1120,8 +1123,7 @@ static void release_gpios(void)
static int allocate_gpios(struct gpib_board *board)
{
- int j, retval = 0;
- bool error = false;
+ int j;
int table_index = 0;
char name[256];
struct gpio_desc *desc;
@@ -1132,8 +1134,8 @@ static int allocate_gpios(struct gpib_board *board)
return -ENOENT;
}
- lookup_table = lookup_tables[0];
- lookup_table->dev_id = dev_name(board->gpib_dev);
+ lookup_table = lookup_tables[table_index];
+ lookup_table->dev_id = dev_name(board->gpib_dev);
gpiod_add_lookup_table(lookup_table);
dbg_printk(1, "Allocating gpios using table index %d\n", table_index);
@@ -1150,30 +1152,26 @@ try_again:
gpiod_remove_lookup_table(lookup_table);
table_index++;
lookup_table = lookup_tables[table_index];
- if (lookup_table) {
- dbg_printk(1, "Allocation failed, now using table_index %d\n",
- table_index);
- lookup_table->dev_id = dev_name(board->gpib_dev);
- gpiod_add_lookup_table(lookup_table);
- goto try_again;
+ if (!lookup_table) {
+ dev_err(board->gpib_dev, "Unable to obtain gpio descriptor for pin %d error %ld\n",
+ gpios_vector[j], PTR_ERR(desc));
+ goto alloc_gpios_fail;
}
- dev_err(board->gpib_dev, "Unable to obtain gpio descriptor for pin %d error %ld\n",
- gpios_vector[j], PTR_ERR(desc));
- error = true;
- break;
+ dbg_printk(1, "Allocation failed, now using table_index %d\n", table_index);
+ lookup_table->dev_id = dev_name(board->gpib_dev);
+ gpiod_add_lookup_table(lookup_table);
+ goto try_again;
}
all_descriptors[j] = desc;
}
- if (error) { /* undo what already done */
- release_gpios();
- retval = -1;
- }
- if (lookup_table)
- gpiod_remove_lookup_table(lookup_table);
- // Initialize LED trigger
- led_trigger_register_simple("gpib", &ledtrig_gpib);
- return retval;
+ gpiod_remove_lookup_table(lookup_table);
+
+ return 0;
+
+alloc_gpios_fail:
+ release_gpios();
+ return -1;
}
static void bb_detach(struct gpib_board *board)
@@ -1184,8 +1182,6 @@ static void bb_detach(struct gpib_board *board)
if (!board->private_data)
return;
- led_trigger_unregister_simple(ledtrig_gpib);
-
bb_free_irq(board, &priv->irq_DAV, NAME "_DAV");
bb_free_irq(board, &priv->irq_NRFD, NAME "_NRFD");
bb_free_irq(board, &priv->irq_NDAC, NAME "_NDAC");
@@ -1206,7 +1202,7 @@ static void bb_detach(struct gpib_board *board)
free_private(board);
}
-static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int bb_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct bb_priv *priv;
int retval = 0;
@@ -1245,7 +1241,6 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config
gpios_vector[&(D06) - &all_descriptors[0]] = YOGA_D06_pin_nr;
gpios_vector[&(PE) - &all_descriptors[0]] = -1;
gpios_vector[&(DC) - &all_descriptors[0]] = -1;
- gpios_vector[&(ACT_LED) - &all_descriptors[0]] = -1;
} else {
dev_err(board->gpib_dev, "Unrecognized pin map %s\n", pin_map);
goto bb_attach_fail;
@@ -1256,7 +1251,8 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config
if (allocate_gpios(board))
goto bb_attach_fail;
-/* Configure SN7516X control lines.
+/*
+ * Configure SN7516X control lines.
* drive ATN, IFC and REN as outputs only when master
* i.e. system controller. In this mode can only be the CIC
* When not master then enable device mode ATN, IFC & REN as inputs
@@ -1266,6 +1262,10 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config
gpiod_direction_output(TE, 1);
gpiod_direction_output(PE, 1);
}
+/* Set main control lines to a known state */
+ gpiod_direction_output(IFC, 1);
+ gpiod_direction_output(REN, 1);
+ gpiod_direction_output(_ATN, 1);
if (strcmp(PINMAP_2, pin_map) == 0) { /* YOGA: enable level shifters */
gpiod_direction_output(YOGA_ENABLE, 1);
@@ -1293,8 +1293,6 @@ static int bb_attach(struct gpib_board *board, const gpib_board_config_t *config
IRQF_TRIGGER_NONE))
goto bb_attach_fail_r;
- ENABLE_IRQ(priv->irq_SRQ, IRQ_TYPE_EDGE_FALLING);
-
dbg_printk(0, "attached board %d\n", board->minor);
goto bb_attach_out;
@@ -1306,7 +1304,7 @@ bb_attach_out:
return retval;
}
-static gpib_interface_t bb_interface = {
+static struct gpib_interface bb_interface = {
.name = NAME,
.attach = bb_attach,
.detach = bb_detach,
@@ -1364,7 +1362,7 @@ inline long usec_diff(struct timespec64 *a, struct timespec64 *b)
(a->tv_nsec - b->tv_nsec) / 1000);
}
-static inline int check_for_eos(struct bb_priv *priv, uint8_t byte)
+static inline int check_for_eos(struct bb_priv *priv, u8 byte)
{
if (priv->eos_check)
return 0;
diff --git a/drivers/staging/gpib/hp_82335/hp82335.c b/drivers/staging/gpib/hp_82335/hp82335.c
index fd23b1cb80f9..d0e47ef77c87 100644
--- a/drivers/staging/gpib/hp_82335/hp82335.c
+++ b/drivers/staging/gpib/hp_82335/hp82335.c
@@ -4,8 +4,9 @@
* copyright : (C) 2002 by Frank Mori Hess *
***************************************************************************/
-/*should enable ATN interrupts (and update board->status on occurrence),
- * implement recovery from bus errors (if necessary)
+/*
+ * should enable ATN interrupts (and update board->status on occurrence),
+ * implement recovery from bus errors (if necessary)
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -24,12 +25,12 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for HP 82335 interface cards");
-static int hp82335_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void hp82335_detach(struct gpib_board *board);
static irqreturn_t hp82335_interrupt(int irq, void *arg);
// wrappers for interface functions
-static int hp82335_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int hp82335_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
struct hp82335_priv *priv = board->private_data;
@@ -37,7 +38,7 @@ static int hp82335_read(struct gpib_board *board, uint8_t *buffer, size_t length
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
-static int hp82335_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int hp82335_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct hp82335_priv *priv = board->private_data;
@@ -45,7 +46,7 @@ static int hp82335_write(struct gpib_board *board, uint8_t *buffer, size_t lengt
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
-static int hp82335_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int hp82335_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct hp82335_priv *priv = board->private_data;
@@ -67,11 +68,11 @@ static int hp82335_go_to_standby(struct gpib_board *board)
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
-static void hp82335_request_system_control(struct gpib_board *board, int request_control)
+static int hp82335_request_system_control(struct gpib_board *board, int request_control)
{
struct hp82335_priv *priv = board->private_data;
- tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
+ return tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
}
static void hp82335_interface_clear(struct gpib_board *board, int assert)
@@ -88,7 +89,7 @@ static void hp82335_remote_enable(struct gpib_board *board, int enable)
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
-static int hp82335_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int hp82335_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct hp82335_priv *priv = board->private_data;
@@ -123,14 +124,14 @@ static int hp82335_secondary_address(struct gpib_board *board, unsigned int addr
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
-static int hp82335_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int hp82335_parallel_poll(struct gpib_board *board, u8 *result)
{
struct hp82335_priv *priv = board->private_data;
return tms9914_parallel_poll(board, &priv->tms9914_priv, result);
}
-static void hp82335_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void hp82335_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct hp82335_priv *priv = board->private_data;
@@ -144,14 +145,14 @@ static void hp82335_parallel_poll_response(struct gpib_board *board, int ist)
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
-static void hp82335_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void hp82335_serial_poll_response(struct gpib_board *board, u8 status)
{
struct hp82335_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
-static uint8_t hp82335_serial_poll_status(struct gpib_board *board)
+static u8 hp82335_serial_poll_status(struct gpib_board *board)
{
struct hp82335_priv *priv = board->private_data;
@@ -179,7 +180,7 @@ static void hp82335_return_to_local(struct gpib_board *board)
tms9914_return_to_local(board, &priv->tms9914_priv);
}
-static gpib_interface_t hp82335_interface = {
+static struct gpib_interface hp82335_interface = {
.name = "hp82335",
.attach = hp82335_attach,
.detach = hp82335_detach,
@@ -226,12 +227,12 @@ static inline unsigned int tms9914_to_hp82335_offset(unsigned int register_num)
return 0x1ff8 + register_num;
}
-static uint8_t hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num)
+static u8 hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return tms9914_iomem_read_byte(priv, tms9914_to_hp82335_offset(register_num));
}
-static void hp82335_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num)
+static void hp82335_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
tms9914_iomem_write_byte(priv, data, tms9914_to_hp82335_offset(register_num));
}
@@ -243,7 +244,7 @@ static void hp82335_clear_interrupt(struct hp82335_priv *hp_priv)
writeb(0, tms_priv->mmiobase + HPREG_INTR_CLEAR);
}
-static int hp82335_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int hp82335_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct hp82335_priv *hp_priv;
struct tms9914_priv *tms_priv;
diff --git a/drivers/staging/gpib/hp_82341/hp_82341.c b/drivers/staging/gpib/hp_82341/hp_82341.c
index f52e673dc869..1b0822b2a3b8 100644
--- a/drivers/staging/gpib/hp_82341/hp_82341.c
+++ b/drivers/staging/gpib/hp_82341/hp_82341.c
@@ -25,11 +25,11 @@ MODULE_DESCRIPTION("GPIB driver for hp 82341a/b/c/d boards");
static unsigned short read_and_clear_event_status(struct gpib_board *board);
static void set_transfer_counter(struct hp_82341_priv *hp_priv, int count);
static int read_transfer_counter(struct hp_82341_priv *hp_priv);
-static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written);
static irqreturn_t hp_82341_interrupt(int irq, void *arg);
-static int hp_82341_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct hp_82341_priv *hp_priv = board->private_data;
@@ -51,11 +51,12 @@ static int hp_82341_accel_read(struct gpib_board *board, uint8_t *buffer, size_t
return 0;
//disable fifo for the moment
outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG);
- // Handle corner case of board not in holdoff and one byte has slipped in already.
- // Also, board sometimes has problems (spurious 1 byte reads) when read fifo is
- // started up with board in
- // TACS under certain data holdoff conditions. Doing a 1 byte tms9914-style
- // read avoids these problems.
+ /*
+ * Handle corner case of board not in holdoff and one byte has slipped in already.
+ * Also, board sometimes has problems (spurious 1 byte reads) when read fifo is
+ * started up with board in TACS under certain data holdoff conditions.
+ * Doing a 1 byte tms9914-style read avoids these problems.
+ */
if (/*tms_priv->holdoff_active == 0 && */length > 1) {
size_t num_bytes;
@@ -172,7 +173,7 @@ static int restart_write_fifo(struct gpib_board *board, struct hp_82341_priv *hp
return 0;
}
-static int hp_82341_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int hp_82341_accel_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
struct hp_82341_priv *hp_priv = board->private_data;
@@ -250,12 +251,12 @@ static int hp_82341_accel_write(struct gpib_board *board, uint8_t *buffer, size_
return 0;
}
-static int hp_82341_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void hp_82341_detach(struct gpib_board *board);
// wrappers for interface functions
-static int hp_82341_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int hp_82341_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct hp_82341_priv *priv = board->private_data;
@@ -263,7 +264,7 @@ static int hp_82341_read(struct gpib_board *board, uint8_t *buffer, size_t lengt
return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read);
}
-static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int hp_82341_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct hp_82341_priv *priv = board->private_data;
@@ -271,7 +272,7 @@ static int hp_82341_write(struct gpib_board *board, uint8_t *buffer, size_t leng
return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written);
}
-static int hp_82341_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int hp_82341_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
struct hp_82341_priv *priv = board->private_data;
@@ -293,7 +294,7 @@ static int hp_82341_go_to_standby(struct gpib_board *board)
return tms9914_go_to_standby(board, &priv->tms9914_priv);
}
-static void hp_82341_request_system_control(struct gpib_board *board, int request_control)
+static int hp_82341_request_system_control(struct gpib_board *board, int request_control)
{
struct hp_82341_priv *priv = board->private_data;
@@ -302,7 +303,7 @@ static void hp_82341_request_system_control(struct gpib_board *board, int reques
else
priv->mode_control_bits &= ~SYSTEM_CONTROLLER_BIT;
outb(priv->mode_control_bits, priv->iobase[0] + MODE_CONTROL_STATUS_REG);
- tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
+ return tms9914_request_system_control(board, &priv->tms9914_priv, request_control);
}
static void hp_82341_interface_clear(struct gpib_board *board, int assert)
@@ -319,7 +320,7 @@ static void hp_82341_remote_enable(struct gpib_board *board, int enable)
tms9914_remote_enable(board, &priv->tms9914_priv, enable);
}
-static int hp_82341_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int hp_82341_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct hp_82341_priv *priv = board->private_data;
@@ -354,14 +355,14 @@ static int hp_82341_secondary_address(struct gpib_board *board, unsigned int add
return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable);
}
-static int hp_82341_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int hp_82341_parallel_poll(struct gpib_board *board, u8 *result)
{
struct hp_82341_priv *priv = board->private_data;
return tms9914_parallel_poll(board, &priv->tms9914_priv, result);
}
-static void hp_82341_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void hp_82341_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct hp_82341_priv *priv = board->private_data;
@@ -375,14 +376,14 @@ static void hp_82341_parallel_poll_response(struct gpib_board *board, int ist)
tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist);
}
-static void hp_82341_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void hp_82341_serial_poll_response(struct gpib_board *board, u8 status)
{
struct hp_82341_priv *priv = board->private_data;
tms9914_serial_poll_response(board, &priv->tms9914_priv, status);
}
-static uint8_t hp_82341_serial_poll_status(struct gpib_board *board)
+static u8 hp_82341_serial_poll_status(struct gpib_board *board)
{
struct hp_82341_priv *priv = board->private_data;
@@ -410,7 +411,7 @@ static void hp_82341_return_to_local(struct gpib_board *board)
tms9914_return_to_local(board, &priv->tms9914_priv);
}
-static gpib_interface_t hp_82341_unaccel_interface = {
+static struct gpib_interface hp_82341_unaccel_interface = {
.name = "hp_82341_unaccel",
.attach = hp_82341_attach,
.detach = hp_82341_detach,
@@ -438,7 +439,7 @@ static gpib_interface_t hp_82341_unaccel_interface = {
.return_to_local = hp_82341_return_to_local,
};
-static gpib_interface_t hp_82341_interface = {
+static struct gpib_interface hp_82341_interface = {
.name = "hp_82341",
.attach = hp_82341_attach,
.detach = hp_82341_detach,
@@ -479,12 +480,12 @@ static void hp_82341_free_private(struct gpib_board *board)
board->private_data = NULL;
}
-static uint8_t hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num)
+static u8 hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return inb(priv->iobase + register_num);
}
-static void hp_82341_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num)
+static void hp_82341_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
outb(data, priv->iobase + register_num);
}
@@ -619,7 +620,8 @@ static int hp_82341_load_firmware_array(struct hp_82341_priv *hp_priv,
return 0;
}
-static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv, const gpib_board_config_t *config)
+static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv,
+ const struct gpib_board_config *config)
{
if (config->init_data_length == 0) {
if (xilinx_done(hp_priv))
@@ -686,7 +688,7 @@ static int clear_xilinx(struct hp_82341_priv *hp_priv)
return 0;
}
-static int hp_82341_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int hp_82341_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct hp_82341_priv *hp_priv;
struct tms9914_priv *tms_priv;
diff --git a/drivers/staging/gpib/include/gpibP.h b/drivers/staging/gpib/include/gpibP.h
index 0c71a038e444..0af72934ce24 100644
--- a/drivers/staging/gpib/include/gpibP.h
+++ b/drivers/staging/gpib/include/gpibP.h
@@ -11,23 +11,23 @@
#include "gpib_types.h"
#include "gpib_proto.h"
-#include "gpib_user.h"
+#include "gpib.h"
#include "gpib_ioctl.h"
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-int gpib_register_driver(gpib_interface_t *interface, struct module *mod);
-void gpib_unregister_driver(gpib_interface_t *interface);
-struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id,
+int gpib_register_driver(struct gpib_interface *interface, struct module *mod);
+void gpib_unregister_driver(struct gpib_interface *interface);
+struct pci_dev *gpib_pci_get_device(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, struct pci_dev *from);
-struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id,
+struct pci_dev *gpib_pci_get_subsys(const struct gpib_board_config *config, unsigned int vendor_id,
unsigned int device_id, unsigned int ss_vendor,
unsigned int ss_device, struct pci_dev *from);
-unsigned int num_gpib_events(const gpib_event_queue_t *queue);
+unsigned int num_gpib_events(const struct gpib_event_queue *queue);
int push_gpib_event(struct gpib_board *board, short event_type);
-int pop_gpib_event(struct gpib_board *board, gpib_event_queue_t *queue, short *event_type);
+int pop_gpib_event(struct gpib_board *board, struct gpib_event_queue *queue, short *event_type);
int gpib_request_pseudo_irq(struct gpib_board *board, irqreturn_t (*handler)(int, void *));
void gpib_free_pseudo_irq(struct gpib_board *board);
int gpib_match_device_path(struct device *dev, const char *device_path_in);
diff --git a/drivers/staging/gpib/include/gpib_proto.h b/drivers/staging/gpib/include/gpib_proto.h
index 2c7dfc02f517..42e736e3b7cd 100644
--- a/drivers/staging/gpib/include/gpib_proto.h
+++ b/drivers/staging/gpib/include/gpib_proto.h
@@ -8,12 +8,8 @@
int ibopen(struct inode *inode, struct file *filep);
int ibclose(struct inode *inode, struct file *file);
long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg);
-int osInit(void);
-void osReset(void);
void os_start_timer(struct gpib_board *board, unsigned int usec_timeout);
void os_remove_timer(struct gpib_board *board);
-void osSendEOI(void);
-void osSendEOI(void);
void init_gpib_board(struct gpib_board *board);
static inline unsigned long usec_to_jiffies(unsigned int usec)
{
@@ -23,34 +19,31 @@ static inline unsigned long usec_to_jiffies(unsigned int usec)
};
int serial_poll_all(struct gpib_board *board, unsigned int usec_timeout);
-void init_gpib_descriptor(gpib_descriptor_t *desc);
+void init_gpib_descriptor(struct gpib_descriptor *desc);
int dvrsp(struct gpib_board *board, unsigned int pad, int sad,
- unsigned int usec_timeout, uint8_t *result);
-int ibAPWait(struct gpib_board *board, int pad);
-int ibAPrsp(struct gpib_board *board, int padsad, char *spb);
-void ibAPE(struct gpib_board *board, int pad, int v);
+ unsigned int usec_timeout, u8 *result);
int ibcac(struct gpib_board *board, int sync, int fallback_to_async);
-int ibcmd(struct gpib_board *board, uint8_t *buf, size_t length, size_t *bytes_written);
+int ibcmd(struct gpib_board *board, u8 *buf, size_t length, size_t *bytes_written);
int ibgts(struct gpib_board *board);
int ibonline(struct gpib_board *board);
int iboffline(struct gpib_board *board);
int iblines(const struct gpib_board *board, short *lines);
-int ibrd(struct gpib_board *board, uint8_t *buf, size_t length, int *end_flag, size_t *bytes_read);
-int ibrpp(struct gpib_board *board, uint8_t *buf);
-int ibrsv2(struct gpib_board *board, uint8_t status_byte, int new_reason_for_service);
-void ibrsc(struct gpib_board *board, int request_control);
+int ibrd(struct gpib_board *board, u8 *buf, size_t length, int *end_flag, size_t *bytes_read);
+int ibrpp(struct gpib_board *board, u8 *buf);
+int ibrsv2(struct gpib_board *board, u8 status_byte, int new_reason_for_service);
+int ibrsc(struct gpib_board *board, int request_control);
int ibsic(struct gpib_board *board, unsigned int usec_duration);
int ibsre(struct gpib_board *board, int enable);
int ibpad(struct gpib_board *board, unsigned int addr);
int ibsad(struct gpib_board *board, int addr);
int ibeos(struct gpib_board *board, int eos, int eosflags);
int ibwait(struct gpib_board *board, int wait_mask, int clear_mask, int set_mask,
- int *status, unsigned long usec_timeout, gpib_descriptor_t *desc);
-int ibwrt(struct gpib_board *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written);
+ int *status, unsigned long usec_timeout, struct gpib_descriptor *desc);
+int ibwrt(struct gpib_board *board, u8 *buf, size_t cnt, int send_eoi, size_t *bytes_written);
int ibstatus(struct gpib_board *board);
-int general_ibstatus(struct gpib_board *board, const gpib_status_queue_t *device,
- int clear_mask, int set_mask, gpib_descriptor_t *desc);
+int general_ibstatus(struct gpib_board *board, const struct gpib_status_queue *device,
+ int clear_mask, int set_mask, struct gpib_descriptor *desc);
int io_timed_out(struct gpib_board *board);
-int ibppc(struct gpib_board *board, uint8_t configuration);
+int ibppc(struct gpib_board *board, u8 configuration);
#endif /* GPIB_PROTO_INCLUDED */
diff --git a/drivers/staging/gpib/include/gpib_types.h b/drivers/staging/gpib/include/gpib_types.h
index 2d9b9be683f8..db040c80d778 100644
--- a/drivers/staging/gpib/include/gpib_types.h
+++ b/drivers/staging/gpib/include/gpib_types.h
@@ -8,12 +8,7 @@
#define _GPIB_TYPES_H
#ifdef __KERNEL__
-/* gpib_interface_t defines the interface
- * between the board-specific details dealt with in the drivers
- * and generic interface provided by gpib-common.
- * This really should be in a different header file.
- */
-#include "gpib_user.h"
+#include "gpib.h"
#include <linux/atomic.h>
#include <linux/device.h>
#include <linux/mutex.h>
@@ -22,11 +17,10 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
-typedef struct gpib_interface_struct gpib_interface_t;
struct gpib_board;
/* config parameters that are only used by driver attach functions */
-typedef struct {
+struct gpib_board_config {
/* firmware blob */
void *init_data;
int init_data_length;
@@ -37,11 +31,13 @@ typedef struct {
unsigned int ibirq;
/* dma channel to use for non-pnp cards (set by core, driver should make local copy) */
unsigned int ibdma;
- /* pci bus of card, useful for distinguishing multiple identical pci cards
+ /*
+ * pci bus of card, useful for distinguishing multiple identical pci cards
* (negative means don't care)
*/
int pci_bus;
- /* pci slot of card, useful for distinguishing multiple identical pci cards
+ /*
+ * pci slot of card, useful for distinguishing multiple identical pci cards
* (negative means don't care)
*/
int pci_slot;
@@ -49,16 +45,23 @@ typedef struct {
char *device_path;
/* serial number of hardware to attach */
char *serial_number;
-} gpib_board_config_t;
+};
-struct gpib_interface_struct {
+/*
+ * struct gpib_interface defines the interface
+ * between the board-specific details dealt with in the drivers
+ * and generic interface provided by gpib-common.
+ * This really should be in a different header file.
+ */
+struct gpib_interface {
/* name of board */
char *name;
/* attach() initializes board and allocates resources */
- int (*attach)(struct gpib_board *board, const gpib_board_config_t *config);
+ int (*attach)(struct gpib_board *board, const struct gpib_board_config *config);
/* detach() shuts down board and frees resources */
void (*detach)(struct gpib_board *board);
- /* read() should read at most 'length' bytes from the bus into
+ /*
+ * read() should read at most 'length' bytes from the bus into
* 'buffer'. It should return when it fills the buffer or
* encounters an END (EOI and or EOS if appropriate). It should set 'end'
* to be nonzero if the read was terminated by an END, otherwise 'end'
@@ -68,76 +71,88 @@ struct gpib_interface_struct {
* return indicates error.
* nbytes returns number of bytes read
*/
- int (*read)(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+ int (*read)(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read);
- /* write() should write 'length' bytes from buffer to the bus.
+ /*
+ * write() should write 'length' bytes from buffer to the bus.
* If the boolean value send_eoi is nonzero, then EOI should
* be sent along with the last byte. Returns number of bytes
* written or negative value on error.
*/
- int (*write)(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+ int (*write)(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written);
- /* command() writes the command bytes in 'buffer' to the bus
+ /*
+ * command() writes the command bytes in 'buffer' to the bus
* Returns zero on success or negative value on error.
*/
- int (*command)(struct gpib_board *board, uint8_t *buffer, size_t length,
+ int (*command)(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written);
- /* Take control (assert ATN). If 'asyncronous' is nonzero, take
+ /*
+ * Take control (assert ATN). If 'asyncronous' is nonzero, take
* control asyncronously (assert ATN immediately without waiting
* for other processes to complete first). Should not return
* until board becomes controller in charge. Returns zero no success,
* nonzero on error.
*/
int (*take_control)(struct gpib_board *board, int asyncronous);
- /* De-assert ATN. Returns zero on success, nonzer on error.
+ /*
+ * De-assert ATN. Returns zero on success, nonzer on error.
*/
int (*go_to_standby)(struct gpib_board *board);
/* request/release control of the IFC and REN lines (system controller) */
- void (*request_system_control)(struct gpib_board *board, int request_control);
- /* Asserts or de-asserts 'interface clear' (IFC) depending on
+ int (*request_system_control)(struct gpib_board *board, int request_control);
+ /*
+ * Asserts or de-asserts 'interface clear' (IFC) depending on
* boolean value of 'assert'
*/
void (*interface_clear)(struct gpib_board *board, int assert);
- /* Sends remote enable command if 'enable' is nonzero, disables remote mode
+ /*
+ * Sends remote enable command if 'enable' is nonzero, disables remote mode
* if 'enable' is zero
*/
void (*remote_enable)(struct gpib_board *board, int enable);
- /* enable END for reads, when byte 'eos' is received. If
+ /*
+ * enable END for reads, when byte 'eos' is received. If
* 'compare_8_bits' is nonzero, then all 8 bits are compared
* with the eos bytes. Otherwise only the 7 least significant
* bits are compared.
*/
- int (*enable_eos)(struct gpib_board *board, uint8_t eos, int compare_8_bits);
+ int (*enable_eos)(struct gpib_board *board, u8 eos, int compare_8_bits);
/* disable END on eos byte (END on EOI only)*/
void (*disable_eos)(struct gpib_board *board);
/* configure parallel poll */
- void (*parallel_poll_configure)(struct gpib_board *board, uint8_t configuration);
+ void (*parallel_poll_configure)(struct gpib_board *board, u8 configuration);
/* conduct parallel poll */
- int (*parallel_poll)(struct gpib_board *board, uint8_t *result);
+ int (*parallel_poll)(struct gpib_board *board, u8 *result);
/* set/clear ist (individual status bit) */
void (*parallel_poll_response)(struct gpib_board *board, int ist);
/* select local parallel poll configuration mode PP2 versus remote PP1 */
void (*local_parallel_poll_mode)(struct gpib_board *board, int local);
- /* Returns current status of the bus lines. Should be set to
+ /*
+ * Returns current status of the bus lines. Should be set to
* NULL if your board does not have the ability to query the
* state of the bus lines.
*/
int (*line_status)(const struct gpib_board *board);
- /* updates and returns the board's current status.
+ /*
+ * updates and returns the board's current status.
* The meaning of the bits are specified in gpib_user.h
* in the IBSTA section. The driver does not need to
* worry about setting the CMPL, END, TIMO, or ERR bits.
*/
unsigned int (*update_status)(struct gpib_board *board, unsigned int clear_mask);
- /* Sets primary address 0-30 for gpib interface card.
+ /*
+ * Sets primary address 0-30 for gpib interface card.
*/
int (*primary_address)(struct gpib_board *board, unsigned int address);
- /* Sets and enables, or disables secondary address 0-30
+ /*
+ * Sets and enables, or disables secondary address 0-30
* for gpib interface card.
*/
int (*secondary_address)(struct gpib_board *board, unsigned int address,
int enable);
- /* Sets the byte the board should send in response to a serial poll.
+ /*
+ * Sets the byte the board should send in response to a serial poll.
* This function should also start or stop requests for service via
* IEEE 488.2 reqt/reqf, based on MSS (bit 6 of the status_byte).
* If the more flexible serial_poll_response2 is implemented by the
@@ -149,8 +164,9 @@ struct gpib_interface_struct {
* by IEEE 488.2 section 11.3.3.4.3 "Allowed Coupled Control of
* STB, reqt, and reqf".
*/
- void (*serial_poll_response)(struct gpib_board *board, uint8_t status_byte);
- /* Sets the byte the board should send in response to a serial poll.
+ void (*serial_poll_response)(struct gpib_board *board, u8 status_byte);
+ /*
+ * Sets the byte the board should send in response to a serial poll.
* This function should also request service via IEEE 488.2 reqt/reqf
* based on MSS (bit 6 of the status_byte) and new_reason_for_service.
* reqt should be set true if new_reason_for_service is true,
@@ -164,11 +180,12 @@ struct gpib_interface_struct {
* If this method is left NULL by the driver, then the user library
* function ibrsv2 will not work.
*/
- void (*serial_poll_response2)(struct gpib_board *board, uint8_t status_byte,
+ void (*serial_poll_response2)(struct gpib_board *board, u8 status_byte,
int new_reason_for_service);
- /* returns the byte the board will send in response to a serial poll.
+ /*
+ * returns the byte the board will send in response to a serial poll.
*/
- uint8_t (*serial_poll_status)(struct gpib_board *board);
+ u8 (*serial_poll_status)(struct gpib_board *board);
/* adjust T1 delay */
int (*t1_delay)(struct gpib_board *board, unsigned int nano_sec);
/* go to local mode */
@@ -179,14 +196,14 @@ struct gpib_interface_struct {
unsigned skip_check_for_command_acceptors : 1;
};
-typedef struct {
+struct gpib_event_queue {
struct list_head event_head;
spinlock_t lock; // for access to event list
unsigned int num_events;
unsigned dropped_event : 1;
-} gpib_event_queue_t;
+};
-static inline void init_event_queue(gpib_event_queue_t *queue)
+static inline void init_event_queue(struct gpib_event_queue *queue)
{
INIT_LIST_HEAD(&queue->event_head);
queue->num_events = 0;
@@ -210,20 +227,22 @@ static inline void init_gpib_pseudo_irq(struct gpib_pseudo_irq *pseudo_irq)
}
/* list so we can make a linked list of drivers */
-typedef struct gpib_interface_list_struct {
+struct gpib_interface_list {
struct list_head list;
- gpib_interface_t *interface;
+ struct gpib_interface *interface;
struct module *module;
-} gpib_interface_list_t;
+};
-/* One struct gpib_board is allocated for each physical board in the computer.
+/*
+ * One struct gpib_board is allocated for each physical board in the computer.
* It provides storage for variables local to each board, and interface
* functions for performing operations on the board
*/
struct gpib_board {
/* functions used by this board */
- gpib_interface_t *interface;
- /* Pointer to module whose use count we should increment when
+ struct gpib_interface *interface;
+ /*
+ * Pointer to module whose use count we should increment when
* interface is in use
*/
struct module *provider_module;
@@ -231,20 +250,24 @@ struct gpib_board {
u8 *buffer;
/* length of buffer */
unsigned int buffer_length;
- /* Used to hold the board's current status (see update_status() above)
+ /*
+ * Used to hold the board's current status (see update_status() above)
*/
unsigned long status;
- /* Driver should only sleep on this wait queue. It is special in that the
+ /*
+ * Driver should only sleep on this wait queue. It is special in that the
* core will wake this queue and set the TIMO bit in 'status' when the
* watchdog timer times out.
*/
wait_queue_head_t wait;
- /* Lock that only allows one process to access this board at a time.
+ /*
+ * Lock that only allows one process to access this board at a time.
* Has to be first in any locking order, since it can be locked over
* multiple ioctls.
*/
struct mutex user_mutex;
- /* Mutex which compensates for removal of "big kernel lock" from kernel.
+ /*
+ * Mutex which compensates for removal of "big kernel lock" from kernel.
* Should not be held for extended waits.
*/
struct mutex big_gpib_mutex;
@@ -259,7 +282,8 @@ struct gpib_board {
struct device *dev;
/* gpib_common device gpibN */
struct device *gpib_dev;
- /* 'private_data' can be used as seen fit by the driver to
+ /*
+ * 'private_data' can be used as seen fit by the driver to
* store additional variables for this board
*/
void *private_data;
@@ -284,34 +308,36 @@ struct gpib_board {
/* autospoll kernel thread */
struct task_struct *autospoll_task;
/* queue for recording received trigger/clear/ifc events */
- gpib_event_queue_t event_queue;
+ struct gpib_event_queue event_queue;
/* minor number for this board's device file */
int minor;
/* struct to deal with polling mode*/
struct gpib_pseudo_irq pseudo_irq;
/* error dong autopoll */
atomic_t stuck_srq;
- gpib_board_config_t config;
+ struct gpib_board_config config;
/* Flag that indicates whether board is system controller of the bus */
unsigned master : 1;
/* individual status bit */
unsigned ist : 1;
- /* one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0),
+ /*
+ * one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0),
* zero means remote parallel poll configuration mode ieee 488.1 PP1
*/
unsigned local_ppoll_mode : 1;
};
/* element of event queue */
-typedef struct {
+struct gpib_event {
struct list_head list;
short event_type;
-} gpib_event_t;
+};
-/* Each board has a list of gpib_status_queue_t to keep track of all open devices
+/*
+ * Each board has a list of gpib_status_queue to keep track of all open devices
* on the bus, so we know what address to poll when we get a service request
*/
-typedef struct {
+struct gpib_status_queue {
/* list_head so we can make a linked list of devices */
struct list_head list;
unsigned int pad; /* primary gpib address */
@@ -323,31 +349,31 @@ typedef struct {
unsigned int reference_count;
/* flags loss of status byte error due to limit on size of queue */
unsigned dropped_byte : 1;
-} gpib_status_queue_t;
+};
-typedef struct {
+struct gpib_status_byte {
struct list_head list;
u8 poll_byte;
-} status_byte_t;
+};
-void init_gpib_status_queue(gpib_status_queue_t *device);
+void init_gpib_status_queue(struct gpib_status_queue *device);
/* Used to store device-descriptor-specific information */
-typedef struct {
+struct gpib_descriptor {
unsigned int pad; /* primary gpib address */
int sad; /* secondary gpib address (negative means disabled) */
atomic_t io_in_progress;
unsigned is_board : 1;
unsigned autopoll_enabled : 1;
-} gpib_descriptor_t;
+};
-typedef struct {
+struct gpib_file_private {
atomic_t holding_mutex;
- gpib_descriptor_t *descriptors[GPIB_MAX_NUM_DESCRIPTORS];
+ struct gpib_descriptor *descriptors[GPIB_MAX_NUM_DESCRIPTORS];
/* locked while descriptors are being allocated/deallocated */
struct mutex descriptors_mutex;
unsigned got_module : 1;
-} gpib_file_private_t;
+};
#endif /* __KERNEL__ */
diff --git a/drivers/staging/gpib/include/nec7210.h b/drivers/staging/gpib/include/nec7210.h
index 069896456230..312217b4580e 100644
--- a/drivers/staging/gpib/include/nec7210.h
+++ b/drivers/staging/gpib/include/nec7210.h
@@ -1,4 +1,4 @@
-//* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
@@ -78,19 +78,19 @@ enum {
};
// interface functions
-int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read);
-int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
-int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written);
int nec7210_take_control(struct gpib_board *board, struct nec7210_priv *priv, int syncronous);
int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv);
-void nec7210_request_system_control(struct gpib_board *board,
- struct nec7210_priv *priv, int request_control);
+int nec7210_request_system_control(struct gpib_board *board,
+ struct nec7210_priv *priv, int request_control);
void nec7210_interface_clear(struct gpib_board *board, struct nec7210_priv *priv, int assert);
void nec7210_remote_enable(struct gpib_board *board, struct nec7210_priv *priv, int enable);
-int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, uint8_t eos_bytes,
+int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_bytes,
int compare_8_bits);
void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv);
unsigned int nec7210_update_status(struct gpib_board *board, struct nec7210_priv *priv,
@@ -100,14 +100,14 @@ int nec7210_primary_address(const struct gpib_board *board,
struct nec7210_priv *priv, unsigned int address);
int nec7210_secondary_address(const struct gpib_board *board, struct nec7210_priv *priv,
unsigned int address, int enable);
-int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *result);
-void nec7210_serial_poll_response(struct gpib_board *board, struct nec7210_priv *priv, uint8_t status);
+int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result);
+void nec7210_serial_poll_response(struct gpib_board *board,
+ struct nec7210_priv *priv, u8 status);
void nec7210_parallel_poll_configure(struct gpib_board *board,
struct nec7210_priv *priv, unsigned int configuration);
void nec7210_parallel_poll_response(struct gpib_board *board,
struct nec7210_priv *priv, int ist);
-uint8_t nec7210_serial_poll_status(struct gpib_board *board,
- struct nec7210_priv *priv);
+u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv);
int nec7210_t1_delay(struct gpib_board *board,
struct nec7210_priv *priv, unsigned int nano_sec);
void nec7210_return_to_local(const struct gpib_board *board, struct nec7210_priv *priv);
@@ -119,18 +119,18 @@ unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg,
unsigned int mask, unsigned int bits);
void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *priv, int mode);
void nec7210_release_rfd_holdoff(struct gpib_board *board, struct nec7210_priv *priv);
-uint8_t nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end);
+u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end);
// wrappers for io functions
-uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
-void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num);
-uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
-void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num);
-uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
-void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data,
+u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
+void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num);
+u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
+void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num);
+u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num);
+void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num);
-uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
-void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data,
+u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num);
+void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num);
// interrupt service routine
diff --git a/drivers/staging/gpib/include/nec7210_registers.h b/drivers/staging/gpib/include/nec7210_registers.h
index 888803dd97f9..97c53ac8e805 100644
--- a/drivers/staging/gpib/include/nec7210_registers.h
+++ b/drivers/staging/gpib/include/nec7210_registers.h
@@ -17,7 +17,8 @@ enum nec7210_chipset {
TNT5004, // NI (minor differences to TNT4882)
};
-/* nec7210 register numbers (might need to be multiplied by
+/*
+ * nec7210 register numbers (might need to be multiplied by
* a board-dependent offset to get actually io address offset)
*/
// write registers
diff --git a/drivers/staging/gpib/include/tms9914.h b/drivers/staging/gpib/include/tms9914.h
index 424c95ad85c6..50a9d3b22619 100644
--- a/drivers/staging/gpib/include/tms9914.h
+++ b/drivers/staging/gpib/include/tms9914.h
@@ -1,4 +1,4 @@
-//* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************************
* copyright : (C) 2002 by Frank Mori Hess
@@ -79,24 +79,25 @@ enum {
};
// interface functions
-int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read);
-int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int send_eoi, size_t *bytes_written);
-int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written);
int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, int syncronous);
-/* alternate version of tms9914_take_control which works around buggy tcs
+/*
+ * alternate version of tms9914_take_control which works around buggy tcs
* implementation.
*/
int tms9914_take_control_workaround(struct gpib_board *board, struct tms9914_priv *priv,
int syncronous);
int tms9914_go_to_standby(struct gpib_board *board, struct tms9914_priv *priv);
-void tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
- int request_control);
+int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
+ int request_control);
void tms9914_interface_clear(struct gpib_board *board, struct tms9914_priv *priv, int assert);
void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv, int enable);
-int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, uint8_t eos_bytes,
+int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_bytes,
int compare_8_bits);
void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv);
unsigned int tms9914_update_status(struct gpib_board *board, struct tms9914_priv *priv,
@@ -105,13 +106,14 @@ int tms9914_primary_address(struct gpib_board *board,
struct tms9914_priv *priv, unsigned int address);
int tms9914_secondary_address(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int address, int enable);
-int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *result);
+int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result);
void tms9914_parallel_poll_configure(struct gpib_board *board,
- struct tms9914_priv *priv, uint8_t config);
+ struct tms9914_priv *priv, u8 config);
void tms9914_parallel_poll_response(struct gpib_board *board,
struct tms9914_priv *priv, int ist);
-void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv *priv, uint8_t status);
-uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv);
+void tms9914_serial_poll_response(struct gpib_board *board,
+ struct tms9914_priv *priv, u8 status);
+u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv);
int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *priv);
unsigned int tms9914_t1_delay(struct gpib_board *board, struct tms9914_priv *priv,
unsigned int nano_sec);
@@ -124,10 +126,10 @@ void tms9914_release_holdoff(struct tms9914_priv *priv);
void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode);
// wrappers for io functions
-uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num);
-void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num);
-uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num);
-void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num);
+u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num);
+void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num);
+u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num);
+void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num);
// interrupt service routine
irqreturn_t tms9914_interrupt(struct gpib_board *board, struct tms9914_priv *priv);
@@ -139,7 +141,8 @@ enum {
ms9914_num_registers = 8,
};
-/* tms9914 register numbers (might need to be multiplied by
+/*
+ * tms9914 register numbers (might need to be multiplied by
* a board-dependent offset to get actually io address offset)
*/
// write registers
diff --git a/drivers/staging/gpib/ines/ines.h b/drivers/staging/gpib/ines/ines.h
index ff27f055a0ff..f0210ce2470d 100644
--- a/drivers/staging/gpib/ines/ines.h
+++ b/drivers/staging/gpib/ines/ines.h
@@ -35,44 +35,6 @@ struct ines_priv {
u8 extend_mode_bits;
};
-// interface functions
-int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read);
-int ines_write(struct gpib_board *board, uint8_t *buffer, size_t length,
- int send_eoi, size_t *bytes_written);
-int ines_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length,
- int *end, size_t *bytes_read);
-int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length,
- int send_eoi, size_t *bytes_written);
-int ines_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written);
-int ines_take_control(struct gpib_board *board, int synchronous);
-int ines_go_to_standby(struct gpib_board *board);
-void ines_request_system_control(struct gpib_board *board, int request_control);
-void ines_interface_clear(struct gpib_board *board, int assert);
-void ines_remote_enable(struct gpib_board *board, int enable);
-int ines_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits);
-void ines_disable_eos(struct gpib_board *board);
-unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask);
-int ines_primary_address(struct gpib_board *board, unsigned int address);
-int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable);
-int ines_parallel_poll(struct gpib_board *board, uint8_t *result);
-void ines_parallel_poll_configure(struct gpib_board *board, uint8_t config);
-void ines_parallel_poll_response(struct gpib_board *board, int ist);
-void ines_serial_poll_response(struct gpib_board *board, uint8_t status);
-uint8_t ines_serial_poll_status(struct gpib_board *board);
-int ines_line_status(const struct gpib_board *board);
-int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec);
-void ines_return_to_local(struct gpib_board *board);
-
-// interrupt service routines
-irqreturn_t ines_pci_interrupt(int irq, void *arg);
-irqreturn_t ines_interrupt(struct gpib_board *board);
-
-// utility functions
-void ines_free_private(struct gpib_board *board);
-int ines_generic_attach(struct gpib_board *board);
-void ines_online(struct ines_priv *priv, const struct gpib_board *board, int use_accel);
-void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count);
-
/* inb/outb wrappers */
static inline unsigned int ines_inb(struct ines_priv *priv, unsigned int register_number)
{
@@ -87,11 +49,6 @@ static inline void ines_outb(struct ines_priv *priv, unsigned int value,
register_number * priv->nec7210_priv.offset);
}
-// pcmcia init/cleanup
-
-int ines_pcmcia_init_module(void);
-void ines_pcmcia_cleanup_module(void);
-
enum ines_regs {
// read
FIFO_STATUS = 0x8,
diff --git a/drivers/staging/gpib/ines/ines_gpib.c b/drivers/staging/gpib/ines/ines_gpib.c
index d93eb05dab90..c851fd014f48 100644
--- a/drivers/staging/gpib/ines/ines_gpib.c
+++ b/drivers/staging/gpib/ines/ines_gpib.c
@@ -25,7 +25,9 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for Ines iGPIB 72010");
-int ines_line_status(const struct gpib_board *board)
+static irqreturn_t ines_interrupt(struct gpib_board *board);
+
+static int ines_line_status(const struct gpib_board *board)
{
int status = VALID_ALL;
int bcm_bits;
@@ -55,7 +57,7 @@ int ines_line_status(const struct gpib_board *board)
return status;
}
-void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count)
+static void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count)
{
if (count > 0xffff) {
pr_err("bug! tried to set xfer counter > 0xffff\n");
@@ -65,7 +67,7 @@ void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count)
ines_outb(priv, count & 0xff, XFER_COUNT_LOWER);
}
-int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec)
+static int ines_t1_delay(struct gpib_board *board, unsigned int nano_sec)
{
struct ines_priv *ines_priv = board->private_data;
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
@@ -95,7 +97,7 @@ static inline unsigned short num_in_fifo_bytes(struct ines_priv *ines_priv)
return ines_inb(ines_priv, IN_FIFO_COUNT);
}
-static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, uint8_t *buffer,
+static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, u8 *buffer,
size_t length, size_t *nbytes)
{
ssize_t retval = 0;
@@ -133,8 +135,8 @@ static ssize_t pio_read(struct gpib_board *board, struct ines_priv *ines_priv, u
return retval;
}
-int ines_accel_read(struct gpib_board *board, uint8_t *buffer,
- size_t length, int *end, size_t *bytes_read)
+static int ines_accel_read(struct gpib_board *board, u8 *buffer,
+ size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
struct ines_priv *ines_priv = board->private_data;
@@ -213,8 +215,8 @@ static int ines_write_wait(struct gpib_board *board, struct ines_priv *ines_priv
return 0;
}
-int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length,
- int send_eoi, size_t *bytes_written)
+static int ines_accel_write(struct gpib_board *board, u8 *buffer, size_t length,
+ int send_eoi, size_t *bytes_written)
{
size_t count = 0;
ssize_t retval = 0;
@@ -264,7 +266,7 @@ int ines_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length,
return retval;
}
-irqreturn_t ines_pci_interrupt(int irq, void *arg)
+static irqreturn_t ines_pci_interrupt(int irq, void *arg)
{
struct gpib_board *board = arg;
struct ines_priv *priv = board->private_data;
@@ -281,7 +283,7 @@ irqreturn_t ines_pci_interrupt(int irq, void *arg)
return ines_interrupt(board);
}
-irqreturn_t ines_interrupt(struct gpib_board *board)
+static irqreturn_t ines_interrupt(struct gpib_board *board)
{
struct ines_priv *priv = board->private_data;
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
@@ -295,7 +297,7 @@ irqreturn_t ines_interrupt(struct gpib_board *board)
isr3_bits = ines_inb(priv, ISR3);
isr4_bits = ines_inb(priv, ISR4);
if (isr3_bits & IFC_ACTIVE_BIT) {
- push_gpib_event(board, EventIFC);
+ push_gpib_event(board, EVENT_IFC);
wake++;
}
if (isr3_bits & FIFO_ERROR_BIT)
@@ -313,9 +315,9 @@ irqreturn_t ines_interrupt(struct gpib_board *board)
return IRQ_HANDLED;
}
-static int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config);
-static int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *config);
-static int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config);
+static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config);
+static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config);
static void ines_pci_detach(struct gpib_board *board);
static void ines_isa_detach(struct gpib_board *board);
@@ -393,8 +395,8 @@ static struct ines_pci_id pci_ids[] = {
static const int num_pci_chips = ARRAY_SIZE(pci_ids);
// wrappers for interface functions
-int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length,
- int *end, size_t *bytes_read)
+static int ines_read(struct gpib_board *board, u8 *buffer, size_t length,
+ int *end, size_t *bytes_read)
{
struct ines_priv *priv = board->private_data;
struct nec7210_priv *nec_priv = &priv->nec7210_priv;
@@ -412,134 +414,134 @@ int ines_read(struct gpib_board *board, uint8_t *buffer, size_t length,
return retval;
}
-int ines_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
- size_t *bytes_written)
+static int ines_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
+ size_t *bytes_written)
{
struct ines_priv *priv = board->private_data;
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-int ines_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written)
+static int ines_command(struct gpib_board *board, u8 *buffer, size_t length, size_t *bytes_written)
{
struct ines_priv *priv = board->private_data;
return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written);
}
-int ines_take_control(struct gpib_board *board, int synchronous)
+static int ines_take_control(struct gpib_board *board, int synchronous)
{
struct ines_priv *priv = board->private_data;
return nec7210_take_control(board, &priv->nec7210_priv, synchronous);
}
-int ines_go_to_standby(struct gpib_board *board)
+static int ines_go_to_standby(struct gpib_board *board)
{
struct ines_priv *priv = board->private_data;
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-void ines_request_system_control(struct gpib_board *board, int request_control)
+static int ines_request_system_control(struct gpib_board *board, int request_control)
{
struct ines_priv *priv = board->private_data;
- nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
+ return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
}
-void ines_interface_clear(struct gpib_board *board, int assert)
+static void ines_interface_clear(struct gpib_board *board, int assert)
{
struct ines_priv *priv = board->private_data;
nec7210_interface_clear(board, &priv->nec7210_priv, assert);
}
-void ines_remote_enable(struct gpib_board *board, int enable)
+static void ines_remote_enable(struct gpib_board *board, int enable)
{
struct ines_priv *priv = board->private_data;
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-int ines_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int ines_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct ines_priv *priv = board->private_data;
return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits);
}
-void ines_disable_eos(struct gpib_board *board)
+static void ines_disable_eos(struct gpib_board *board)
{
struct ines_priv *priv = board->private_data;
nec7210_disable_eos(board, &priv->nec7210_priv);
}
-unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask)
+static unsigned int ines_update_status(struct gpib_board *board, unsigned int clear_mask)
{
struct ines_priv *priv = board->private_data;
return nec7210_update_status(board, &priv->nec7210_priv, clear_mask);
}
-int ines_primary_address(struct gpib_board *board, unsigned int address)
+static int ines_primary_address(struct gpib_board *board, unsigned int address)
{
struct ines_priv *priv = board->private_data;
return nec7210_primary_address(board, &priv->nec7210_priv, address);
}
-int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable)
+static int ines_secondary_address(struct gpib_board *board, unsigned int address, int enable)
{
struct ines_priv *priv = board->private_data;
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-int ines_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int ines_parallel_poll(struct gpib_board *board, u8 *result)
{
struct ines_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-void ines_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void ines_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct ines_priv *priv = board->private_data;
nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config);
}
-void ines_parallel_poll_response(struct gpib_board *board, int ist)
+static void ines_parallel_poll_response(struct gpib_board *board, int ist)
{
struct ines_priv *priv = board->private_data;
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-void ines_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void ines_serial_poll_response(struct gpib_board *board, u8 status)
{
struct ines_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-uint8_t ines_serial_poll_status(struct gpib_board *board)
+static u8 ines_serial_poll_status(struct gpib_board *board)
{
struct ines_priv *priv = board->private_data;
return nec7210_serial_poll_status(board, &priv->nec7210_priv);
}
-void ines_return_to_local(struct gpib_board *board)
+static void ines_return_to_local(struct gpib_board *board)
{
struct ines_priv *priv = board->private_data;
nec7210_return_to_local(board, &priv->nec7210_priv);
}
-static gpib_interface_t ines_pci_unaccel_interface = {
+static struct gpib_interface ines_pci_unaccel_interface = {
.name = "ines_pci_unaccel",
.attach = ines_pci_attach,
.detach = ines_pci_detach,
@@ -567,7 +569,7 @@ static gpib_interface_t ines_pci_unaccel_interface = {
.return_to_local = ines_return_to_local,
};
-static gpib_interface_t ines_pci_interface = {
+static struct gpib_interface ines_pci_interface = {
.name = "ines_pci",
.attach = ines_pci_accel_attach,
.detach = ines_pci_detach,
@@ -595,7 +597,7 @@ static gpib_interface_t ines_pci_interface = {
.return_to_local = ines_return_to_local,
};
-static gpib_interface_t ines_pci_accel_interface = {
+static struct gpib_interface ines_pci_accel_interface = {
.name = "ines_pci_accel",
.attach = ines_pci_accel_attach,
.detach = ines_pci_detach,
@@ -623,7 +625,7 @@ static gpib_interface_t ines_pci_accel_interface = {
.return_to_local = ines_return_to_local,
};
-static gpib_interface_t ines_isa_interface = {
+static struct gpib_interface ines_isa_interface = {
.name = "ines_isa",
.attach = ines_isa_attach,
.detach = ines_isa_detach,
@@ -664,13 +666,13 @@ static int ines_allocate_private(struct gpib_board *board)
return 0;
}
-void ines_free_private(struct gpib_board *board)
+static void ines_free_private(struct gpib_board *board)
{
kfree(board->private_data);
board->private_data = NULL;
}
-int ines_generic_attach(struct gpib_board *board)
+static int ines_generic_attach(struct gpib_board *board)
{
struct ines_priv *ines_priv;
struct nec7210_priv *nec_priv;
@@ -690,7 +692,7 @@ int ines_generic_attach(struct gpib_board *board)
return 0;
}
-void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, int use_accel)
+static void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, int use_accel)
{
struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv;
@@ -724,7 +726,7 @@ void ines_online(struct ines_priv *ines_priv, const struct gpib_board *board, in
nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, 0);
}
-static int ines_common_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_common_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
struct nec7210_priv *nec_priv;
@@ -852,7 +854,7 @@ static int ines_common_pci_attach(struct gpib_board *board, const gpib_board_con
return 0;
}
-int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
int retval;
@@ -867,7 +869,7 @@ int ines_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
return 0;
}
-int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_pci_accel_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
int retval;
@@ -884,7 +886,7 @@ int ines_pci_accel_attach(struct gpib_board *board, const gpib_board_config_t *c
static const int ines_isa_iosize = 0x20;
-int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
struct nec7210_priv *nec_priv;
@@ -915,7 +917,7 @@ int ines_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
return 0;
}
-void ines_pci_detach(struct gpib_board *board)
+static void ines_pci_detach(struct gpib_board *board)
{
struct ines_priv *ines_priv = board->private_data;
struct nec7210_priv *nec_priv;
@@ -949,7 +951,7 @@ void ines_pci_detach(struct gpib_board *board)
ines_free_private(board);
}
-void ines_isa_detach(struct gpib_board *board)
+static void ines_isa_detach(struct gpib_board *board)
{
struct ines_priv *ines_priv = board->private_data;
struct nec7210_priv *nec_priv;
@@ -990,48 +992,49 @@ static struct pci_driver ines_pci_driver = {
static const int ines_pcmcia_iosize = 0x20;
-/* The event() function is this driver's Card Services event handler.
- * It will be called by Card Services when an appropriate card status
- * event is received. The config() and release() entry points are
- * used to configure or release a socket, in response to card insertion
- * and ejection events. They are invoked from the gpib event
- * handler.
+/*
+ * The event() function is this driver's Card Services event handler.
+ * It will be called by Card Services when an appropriate card status
+ * event is received. The config() and release() entry points are
+ * used to configure or release a socket, in response to card insertion
+ * and ejection events. They are invoked from the gpib event
+ * handler.
*/
static int ines_gpib_config(struct pcmcia_device *link);
static void ines_gpib_release(struct pcmcia_device *link);
-static int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config);
-static int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t *config);
+static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config);
+static int ines_pcmcia_accel_attach(struct gpib_board *board,
+ const struct gpib_board_config *config);
static void ines_pcmcia_detach(struct gpib_board *board);
-static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg);
static int ines_common_pcmcia_attach(struct gpib_board *board);
/*
* A linked list of "instances" of the gpib device. Each actual
- * PCMCIA card corresponds to one device instance, and is described
- * by one dev_link_t structure (defined in ds.h).
+ * PCMCIA card corresponds to one device instance, and is described
+ * by one dev_link_t structure (defined in ds.h).
*
- * You may not want to use a linked list for this -- for example, the
- * memory card driver uses an array of dev_link_t pointers, where minor
- * device numbers are used to derive the corresponding array index.
+ * You may not want to use a linked list for this -- for example, the
+ * memory card driver uses an array of dev_link_t pointers, where minor
+ * device numbers are used to derive the corresponding array index.
*/
static struct pcmcia_device *curr_dev;
/*
- * A dev_link_t structure has fields for most things that are needed
- * to keep track of a socket, but there will usually be some device
- * specific information that also needs to be kept track of. The
- * 'priv' pointer in a dev_link_t structure can be used to point to
- * a device-specific private data structure, like this.
+ * A dev_link_t structure has fields for most things that are needed
+ * to keep track of a socket, but there will usually be some device
+ * specific information that also needs to be kept track of. The
+ * 'priv' pointer in a dev_link_t structure can be used to point to
+ * a device-specific private data structure, like this.
*
- * A driver needs to provide a dev_node_t structure for each device
- * on a card. In some cases, there is only one device per card (for
- * example, ethernet cards, modems). In other cases, there may be
- * many actual or logical devices (SCSI adapters, memory cards with
- * multiple partitions). The dev_node_t structures need to be kept
- * in a linked list starting at the 'dev' field of a dev_link_t
- * structure. We allocate them in the card's private data structure,
- * because they generally can't be allocated dynamically.
+ * A driver needs to provide a dev_node_t structure for each device
+ * on a card. In some cases, there is only one device per card (for
+ * example, ethernet cards, modems). In other cases, there may be
+ * many actual or logical devices (SCSI adapters, memory cards with
+ * multiple partitions). The dev_node_t structures need to be kept
+ * in a linked list starting at the 'dev' field of a dev_link_t
+ * structure. We allocate them in the card's private data structure,
+ * because they generally can't be allocated dynamically.
*/
struct local_info {
@@ -1042,13 +1045,13 @@ struct local_info {
};
/*
- * gpib_attach() creates an "instance" of the driver, allocating
- * local data structures for one device. The device is registered
- * with Card Services.
+ * gpib_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device. The device is registered
+ * with Card Services.
*
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a
- * card insertion event.
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
*/
static int ines_gpib_probe(struct pcmcia_device *link)
{
@@ -1079,10 +1082,10 @@ static int ines_gpib_probe(struct pcmcia_device *link)
}
/*
- * This deletes a driver "instance". The device is de-registered
- * with Card Services. If it has been released, all local data
- * structures are freed. Otherwise, the structures will be freed
- * when the device is released.
+ * This deletes a driver "instance". The device is de-registered
+ * with Card Services. If it has been released, all local data
+ * structures are freed. Otherwise, the structures will be freed
+ * when the device is released.
*/
static void ines_gpib_remove(struct pcmcia_device *link)
{
@@ -1103,18 +1106,15 @@ static int ines_gpib_config_iteration(struct pcmcia_device *link, void *priv_dat
}
/*
- * gpib_config() is scheduled to run after a CARD_INSERTION event
- * is received, to configure the PCMCIA socket, and to make the
- * device available to the system.
+ * gpib_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
*/
static int ines_gpib_config(struct pcmcia_device *link)
{
- struct local_info *dev;
int retval;
void __iomem *virt;
- dev = link->priv;
-
retval = pcmcia_loop_config(link, &ines_gpib_config_iteration, NULL);
if (retval) {
dev_warn(&link->dev, "no configuration found\n");
@@ -1125,8 +1125,9 @@ static int ines_gpib_config(struct pcmcia_device *link)
dev_dbg(&link->dev, "ines_cs: manufacturer: 0x%x card: 0x%x\n",
link->manf_id, link->card_id);
- /* for the ines card we have to setup the configuration registers in
- * attribute memory here
+ /*
+ * for the ines card we have to setup the configuration registers in
+ * attribute memory here
*/
link->resource[2]->flags |= WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8 | WIN_ENABLE;
link->resource[2]->end = 0x1000;
@@ -1159,9 +1160,9 @@ static int ines_gpib_config(struct pcmcia_device *link)
} /* gpib_config */
/*
- * After a card is removed, gpib_release() will unregister the net
- * device, and release the PCMCIA configuration. If the device is
- * still open, this will be postponed until it is closed.
+ * After a card is removed, gpib_release() will unregister the net
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
*/
static void ines_gpib_release(struct pcmcia_device *link)
@@ -1210,12 +1211,12 @@ static struct pcmcia_driver ines_gpib_cs_driver = {
.resume = ines_gpib_resume,
};
-void ines_pcmcia_cleanup_module(void)
+static void ines_pcmcia_cleanup_module(void)
{
pcmcia_unregister_driver(&ines_gpib_cs_driver);
}
-static gpib_interface_t ines_pcmcia_unaccel_interface = {
+static struct gpib_interface ines_pcmcia_unaccel_interface = {
.name = "ines_pcmcia_unaccel",
.attach = ines_pcmcia_attach,
.detach = ines_pcmcia_detach,
@@ -1243,7 +1244,7 @@ static gpib_interface_t ines_pcmcia_unaccel_interface = {
.return_to_local = ines_return_to_local,
};
-static gpib_interface_t ines_pcmcia_accel_interface = {
+static struct gpib_interface ines_pcmcia_accel_interface = {
.name = "ines_pcmcia_accel",
.attach = ines_pcmcia_accel_attach,
.detach = ines_pcmcia_detach,
@@ -1271,7 +1272,7 @@ static gpib_interface_t ines_pcmcia_accel_interface = {
.return_to_local = ines_return_to_local,
};
-static gpib_interface_t ines_pcmcia_interface = {
+static struct gpib_interface ines_pcmcia_interface = {
.name = "ines_pcmcia",
.attach = ines_pcmcia_accel_attach,
.detach = ines_pcmcia_detach,
@@ -1299,14 +1300,14 @@ static gpib_interface_t ines_pcmcia_interface = {
.return_to_local = ines_return_to_local,
};
-irqreturn_t ines_pcmcia_interrupt(int irq, void *arg)
+static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg)
{
struct gpib_board *board = arg;
return ines_interrupt(board);
}
-int ines_common_pcmcia_attach(struct gpib_board *board)
+static int ines_common_pcmcia_attach(struct gpib_board *board)
{
struct ines_priv *ines_priv;
struct nec7210_priv *nec_priv;
@@ -1345,7 +1346,7 @@ int ines_common_pcmcia_attach(struct gpib_board *board)
return 0;
}
-int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
int retval;
@@ -1360,7 +1361,8 @@ int ines_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *conf
return 0;
}
-int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ines_pcmcia_accel_attach(struct gpib_board *board,
+ const struct gpib_board_config *config)
{
struct ines_priv *ines_priv;
int retval;
@@ -1375,7 +1377,7 @@ int ines_pcmcia_accel_attach(struct gpib_board *board, const gpib_board_config_t
return 0;
}
-void ines_pcmcia_detach(struct gpib_board *board)
+static void ines_pcmcia_detach(struct gpib_board *board)
{
struct ines_priv *ines_priv = board->private_data;
struct nec7210_priv *nec_priv;
@@ -1484,7 +1486,7 @@ static void __exit ines_exit_module(void)
gpib_unregister_driver(&ines_pci_unaccel_interface);
gpib_unregister_driver(&ines_pci_accel_interface);
gpib_unregister_driver(&ines_isa_interface);
-#ifdef GPIB__PCMCIA
+#ifdef CONFIG_GPIB_PCMCIA
gpib_unregister_driver(&ines_pcmcia_interface);
gpib_unregister_driver(&ines_pcmcia_unaccel_interface);
gpib_unregister_driver(&ines_pcmcia_accel_interface);
diff --git a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
index faf96e9cc4a1..3cf5037c0cd2 100644
--- a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
+++ b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c
@@ -36,16 +36,16 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB driver for LPVO usb devices");
/*
- * Table of devices that work with this driver.
+ * Table of devices that work with this driver.
*
- * Currently, only one device is known to be used in the
- * lpvo_usb_gpib adapter (FTDI 0403:6001).
- * If your adapter uses a different chip, insert a line
- * in the following table with proper <Vendor-id>, <Product-id>.
+ * Currently, only one device is known to be used in the
+ * lpvo_usb_gpib adapter (FTDI 0403:6001).
+ * If your adapter uses a different chip, insert a line
+ * in the following table with proper <Vendor-id>, <Product-id>.
*
- * To have your chip automatically handled by the driver,
- * update files "/usr/local/etc/modprobe.d/lpvo_usb_gpib.conf"
- * and /usr/local/etc/udev/rules.d/99-lpvo_usb_gpib.rules.
+ * To have your chip automatically handled by the driver,
+ * update files "/usr/local/etc/modprobe.d/lpvo_usb_gpib.conf"
+ * and /usr/local/etc/udev/rules.d/99-lpvo_usb_gpib.rules.
*
*/
@@ -56,18 +56,18 @@ static const struct usb_device_id skel_table[] = {
MODULE_DEVICE_TABLE(usb, skel_table);
/*
- * *** Diagnostics and Debug ***
- * To enable the diagnostic and debug messages either compile with DEBUG set
- * or control via the dynamic debug mechanisms.
- * The module parameter "debug" controls the sending of debug messages to
- * syslog. By default it is set to 0
- * debug = 0: only attach/detach messages are sent
- * 1: every action is logged
- * 2: extended logging; each single exchanged byte is documented
- * (about twice the log volume of [1])
- * To switch debug level:
- * At module loading: modprobe lpvo_usb_gpib debug={0,1,2}
- * On the fly: echo {0,1,2} > /sys/modules/lpvo_usb_gpib/parameters/debug
+ * *** Diagnostics and Debug ***
+ * To enable the diagnostic and debug messages either compile with DEBUG set
+ * or control via the dynamic debug mechanisms.
+ * The module parameter "debug" controls the sending of debug messages to
+ * syslog. By default it is set to 0
+ * debug = 0: only attach/detach messages are sent
+ * 1: every action is logged
+ * 2: extended logging; each single exchanged byte is documented
+ * (about twice the log volume of [1])
+ * To switch debug level:
+ * At module loading: modprobe lpvo_usb_gpib debug={0,1,2}
+ * On the fly: echo {0,1,2} > /sys/modules/lpvo_usb_gpib/parameters/debug
*/
static int debug;
@@ -169,10 +169,10 @@ static void show_status(struct gpib_board *board)
}
/*
- * GLOBAL VARIABLES: required for
- * pairing among gpib minor and usb minor.
- * MAX_DEV is the max number of usb-gpib adapters; free
- * to change as you like, but no more than 32
+ * GLOBAL VARIABLES: required for
+ * pairing among gpib minor and usb minor.
+ * MAX_DEV is the max number of usb-gpib adapters; free
+ * to change as you like, but no more than 32
*/
#define MAX_DEV 8
@@ -182,7 +182,7 @@ static int assigned_usb_minors; /* mask of filled slots */
static struct mutex minors_lock; /* operations on usb_minors are to be protected */
/*
- * usb-skeleton prototypes
+ * usb-skeleton prototypes
*/
struct usb_skel;
@@ -192,7 +192,7 @@ static int skel_do_open(struct gpib_board *, int);
static int skel_do_release(struct gpib_board *);
/*
- * usec_diff : take difference in MICROsec between two 'timespec'
+ * usec_diff : take difference in MICROsec between two 'timespec'
* (unix time in sec and NANOsec)
*/
@@ -203,7 +203,7 @@ static inline int usec_diff(struct timespec64 *a, struct timespec64 *b)
}
/*
- * *** these routines are specific to the usb-gpib adapter ***
+ * *** these routines are specific to the usb-gpib adapter ***
*/
/**
@@ -262,13 +262,11 @@ static int send_command(struct gpib_board *board, char *msg, int leng)
}
/*
- *
* set_control_line() - Set the value of a single gpib control line
*
* @board: the gpib_board_struct data area for this gpib interface
* @line: line mask
* @value: line new value (0/1)
- *
*/
static int set_control_line(struct gpib_board *board, int line, int value)
@@ -368,7 +366,7 @@ static void set_timeout(struct gpib_board *board)
}
/*
- * now the standard interface functions - attach and detach
+ * now the standard interface functions - attach and detach
*/
/**
@@ -384,7 +382,7 @@ static void set_timeout(struct gpib_board *board)
* detach() will be called. Always.
*/
-static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int retval, j;
u32 base = config->ibbase;
@@ -464,7 +462,8 @@ static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t *
if (retval != ACK)
return -EIO;
- /* We must setup debug mode because we need the extended instruction
+ /*
+ * We must setup debug mode because we need the extended instruction
* set to cope with the Core (gpib_common) point of view
*/
@@ -473,7 +472,8 @@ static int usb_gpib_attach(struct gpib_board *board, const gpib_board_config_t *
if (retval != ACK)
return -EIO;
- /* We must keep REN off after an IFC because so it is
+ /*
+ * We must keep REN off after an IFC because so it is
* assumed by the Core
*/
@@ -654,7 +654,8 @@ static int usb_gpib_line_status(const struct gpib_board *board)
DIA_LOG(1, "%s\n", "request");
- /* if we are on the wait queue (board->wait), do not hurry
+ /*
+ * if we are on the wait queue (board->wait), do not hurry
* reading status line; instead, pause a little
*/
@@ -705,9 +706,10 @@ static int usb_gpib_line_status(const struct gpib_board *board)
/* parallel_poll */
-static int usb_gpib_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int usb_gpib_parallel_poll(struct gpib_board *board, u8 *result)
{
- /* request parallel poll asserting ATN | EOI;
+ /*
+ * request parallel poll asserting ATN | EOI;
* we suppose ATN already asserted
*/
@@ -909,15 +911,13 @@ static void usb_gpib_remote_enable(struct gpib_board *board, int enable)
/* request_system_control */
-static void usb_gpib_request_system_control(struct gpib_board *board,
- int request_control)
+static int usb_gpib_request_system_control(struct gpib_board *board, int request_control)
{
- if (request_control)
- set_bit(CIC_NUM, &board->status);
- else
- clear_bit(CIC_NUM, &board->status);
+ if (!request_control)
+ return -EINVAL;
DIA_LOG(1, "done with %d -> %lx\n", request_control, board->status);
+ return 0;
}
/* take_control */
@@ -997,7 +997,7 @@ static int usb_gpib_write(struct gpib_board *board,
/* parallel_poll configure */
static void usb_gpib_parallel_poll_configure(struct gpib_board *board,
- uint8_t configuration)
+ u8 configuration)
{
}
@@ -1031,13 +1031,13 @@ static int usb_gpib_secondary_address(struct gpib_board *board,
/* serial_poll_response */
-static void usb_gpib_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void usb_gpib_serial_poll_response(struct gpib_board *board, u8 status)
{
}
/* serial_poll_status */
-static uint8_t usb_gpib_serial_poll_status(struct gpib_board *board)
+static u8 usb_gpib_serial_poll_status(struct gpib_board *board)
{
return 0;
}
@@ -1053,7 +1053,7 @@ static int usb_gpib_t1_delay(struct gpib_board *board, unsigned int nano_sec)
* *** module dispatch table and init/exit functions ***
*/
-static gpib_interface_t usb_gpib_interface = {
+static struct gpib_interface usb_gpib_interface = {
.name = NAME,
.attach = usb_gpib_attach,
.detach = usb_gpib_detach,
@@ -1083,13 +1083,13 @@ static gpib_interface_t usb_gpib_interface = {
};
/*
- * usb_gpib_init_module(), usb_gpib_exit_module()
+ * usb_gpib_init_module(), usb_gpib_exit_module()
*
- * This functions are called every time a new device is detected
- * and registered or is removed and unregistered.
- * We must take note of created and destroyed usb minors to be used
- * when usb_gpib_attach() and usb_gpib_detach() will be called on
- * request by gpib_config.
+ * This functions are called every time a new device is detected
+ * and registered or is removed and unregistered.
+ * We must take note of created and destroyed usb minors to be used
+ * when usb_gpib_attach() and usb_gpib_detach() will be called on
+ * request by gpib_config.
*/
static int usb_gpib_init_module(struct usb_interface *interface)
@@ -1107,8 +1107,9 @@ static int usb_gpib_init_module(struct usb_interface *interface)
goto exit;
}
} else {
- /* check if minor is already registered - maybe useless, but if
- * it happens the code is inconsistent somewhere
+ /*
+ * check if minor is already registered - maybe useless, but if
+ * it happens the code is inconsistent somewhere
*/
for (j = 0 ; j < MAX_DEV ; j++) {
@@ -1162,12 +1163,11 @@ exit:
}
/*
- * Default latency time (16 msec) is too long.
- * We must use 1 msec (best); anyhow, no more than 5 msec.
- *
- * Defines and function taken and modified from the kernel tree
- * (see ftdi_sio.h and ftdi_sio.c).
+ * Default latency time (16 msec) is too long.
+ * We must use 1 msec (best); anyhow, no more than 5 msec.
*
+ * Defines and function taken and modified from the kernel tree
+ * (see ftdi_sio.h and ftdi_sio.c).
*/
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
@@ -1235,7 +1235,8 @@ static int write_latency_timer(struct usb_device *udev)
/* private defines */
#define MAX_TRANSFER (PAGE_SIZE - 512)
-/* MAX_TRANSFER is chosen so that the VM is not stressed by
+/*
+ * MAX_TRANSFER is chosen so that the VM is not stressed by
* allocations > PAGE_SIZE and the number of packets in a page
* is an integer 512 is the largest possible packet on EHCI
*/
@@ -1280,7 +1281,7 @@ static void skel_delete(struct kref *kref)
}
/*
- * skel_do_open() - to be called by usb_gpib_attach
+ * skel_do_open() - to be called by usb_gpib_attach
*/
static int skel_do_open(struct gpib_board *board, int subminor)
@@ -1317,7 +1318,7 @@ exit:
}
/*
- * skel_do_release() - to be called by usb_gpib_detach
+ * skel_do_release() - to be called by usb_gpib_detach
*/
static int skel_do_release(struct gpib_board *board)
@@ -1340,7 +1341,7 @@ static int skel_do_release(struct gpib_board *board)
}
/*
- * read functions
+ * read functions
*/
static void skel_read_bulk_callback(struct urb *urb)
@@ -1405,7 +1406,7 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)
}
/*
- * skel_do_read() - read operations from lpvo_usb_gpib
+ * skel_do_read() - read operations from lpvo_usb_gpib
*/
static ssize_t skel_do_read(struct usb_skel *dev, char *buffer, size_t count)
@@ -1482,7 +1483,8 @@ retry:
* all data has been used
* actual IO needs to be done
*/
- /* it seems that requests for less than dev->bulk_in_size
+ /*
+ * it seems that requests for less than dev->bulk_in_size
* are not accepted
*/
rv = skel_do_read_io(dev, dev->bulk_in_size);
@@ -1496,7 +1498,8 @@ retry:
* data is available - chunk tells us how much shall be copied
*/
- /* Condition dev->bulk_in_copied > 0 maybe will never happen. In case,
+ /*
+ * Condition dev->bulk_in_copied > 0 maybe will never happen. In case,
* signal the event and copy using the original procedure, i.e., copy
* first two bytes also
*/
@@ -1551,7 +1554,7 @@ exit:
}
/*
- * write functions
+ * write functions
*/
static void skel_write_bulk_callback(struct urb *urb)
@@ -1581,7 +1584,7 @@ static void skel_write_bulk_callback(struct urb *urb)
}
/*
- * skel_do_write() - write operations from lpvo_usb_gpib
+ * skel_do_write() - write operations from lpvo_usb_gpib
*/
static ssize_t skel_do_write(struct usb_skel *dev, const char *buffer, size_t count)
@@ -1686,7 +1689,7 @@ exit:
}
/*
- * services for the user space devices
+ * services for the user space devices
*/
#if USER_DEVICE /* conditional compilation of user space device */
@@ -1771,7 +1774,7 @@ static int skel_release(struct inode *inode, struct file *file)
}
/*
- * user space access to read function
+ * user space access to read function
*/
static ssize_t skel_read(struct file *file, char __user *buffer, size_t count,
@@ -1800,7 +1803,7 @@ static ssize_t skel_read(struct file *file, char __user *buffer, size_t count,
}
/*
- * user space access to write function
+ * user space access to write function
*/
static ssize_t skel_write(struct file *file, const char __user *user_buffer,
diff --git a/drivers/staging/gpib/nec7210/nec7210.c b/drivers/staging/gpib/nec7210/nec7210.c
index 846c0a3fa1dc..34a1cae4f486 100644
--- a/drivers/staging/gpib/nec7210/nec7210.c
+++ b/drivers/staging/gpib/nec7210/nec7210.c
@@ -23,7 +23,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GPIB library code for NEC uPD7210");
-int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, uint8_t eos_byte,
+int nec7210_enable_eos(struct gpib_board *board, struct nec7210_priv *priv, u8 eos_byte,
int compare_8_bits)
{
write_byte(priv, eos_byte, EOSR);
@@ -44,7 +44,7 @@ void nec7210_disable_eos(struct gpib_board *board, struct nec7210_priv *priv)
}
EXPORT_SYMBOL(nec7210_disable_eos);
-int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *result)
+int nec7210_parallel_poll(struct gpib_board *board, struct nec7210_priv *priv, u8 *result)
{
int ret;
@@ -79,14 +79,15 @@ void nec7210_parallel_poll_response(struct gpib_board *board, struct nec7210_pri
write_byte(priv, AUX_CPPF, AUXMR);
}
EXPORT_SYMBOL(nec7210_parallel_poll_response);
-/* This is really only adequate for chips that do a 488.2 style reqt/reqf
+/*
+ * This is really only adequate for chips that do a 488.2 style reqt/reqf
* based on bit 6 of the SPMR (see chapter 11.3.3 of 488.2). For simpler chips that simply
* set rsv directly based on bit 6, we either need to do more hardware setup to expose
* the 488.2 capability (for example with NI chips), or we need to implement the
* 488.2 set srv state machine in the driver (if that is even viable).
*/
void nec7210_serial_poll_response(struct gpib_board *board,
- struct nec7210_priv *priv, uint8_t status)
+ struct nec7210_priv *priv, u8 status)
{
unsigned long flags;
@@ -103,7 +104,7 @@ void nec7210_serial_poll_response(struct gpib_board *board,
}
EXPORT_SYMBOL(nec7210_serial_poll_response);
-uint8_t nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv)
+u8 nec7210_serial_poll_status(struct gpib_board *board, struct nec7210_priv *priv)
{
return read_byte(priv, SPSR);
}
@@ -202,7 +203,8 @@ unsigned int nec7210_update_status_nolock(struct gpib_board *board, struct nec72
set_bit(SPOLL_NUM, &board->status);
}
- /* we rely on the interrupt handler to set the
+ /*
+ * we rely on the interrupt handler to set the
* rest of the status bits
*/
@@ -251,7 +253,7 @@ void nec7210_set_handshake_mode(struct gpib_board *board, struct nec7210_priv *p
}
EXPORT_SYMBOL(nec7210_set_handshake_mode);
-uint8_t nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end)
+u8 nec7210_read_data_in(struct gpib_board *board, struct nec7210_priv *priv, int *end)
{
unsigned long flags;
u8 data;
@@ -330,14 +332,15 @@ int nec7210_go_to_standby(struct gpib_board *board, struct nec7210_priv *priv)
}
EXPORT_SYMBOL(nec7210_go_to_standby);
-void nec7210_request_system_control(struct gpib_board *board, struct nec7210_priv *priv,
- int request_control)
+int nec7210_request_system_control(struct gpib_board *board, struct nec7210_priv *priv,
+ int request_control)
{
if (request_control == 0) {
write_byte(priv, AUX_CREN, AUXMR);
write_byte(priv, AUX_CIFC, AUXMR);
write_byte(priv, AUX_DSC, AUXMR);
}
+ return 0;
}
EXPORT_SYMBOL(nec7210_request_system_control);
@@ -415,7 +418,7 @@ static inline short nec7210_atn_has_changed(struct gpib_board *board, struct nec
return -1;
}
-int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t
+int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, u8
*buffer, size_t length, size_t *bytes_written)
{
int retval = 0;
@@ -464,7 +467,7 @@ int nec7210_command(struct gpib_board *board, struct nec7210_priv *priv, uint8_t
}
EXPORT_SYMBOL(nec7210_command);
-static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
@@ -482,7 +485,8 @@ static int pio_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t
}
if (test_bit(READ_READY_BN, &priv->state)) {
if (*bytes_read == 0) {
- /* We set the handshake mode here because we know
+ /*
+ * We set the handshake mode here because we know
* no new bytes will arrive (it has already arrived
* and is awaiting being read out of the chip) while we are changing
* modes. This ensures we can reliably keep track
@@ -568,7 +572,7 @@ static ssize_t __dma_read(struct gpib_board *board, struct nec7210_priv *priv, s
return retval ? retval : count;
}
-static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length)
{
size_t remain = length;
@@ -595,7 +599,7 @@ static ssize_t dma_read(struct gpib_board *board, struct nec7210_priv *priv, uin
}
#endif
-int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+int nec7210_read(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
@@ -642,7 +646,7 @@ static int pio_write_wait(struct gpib_board *board, struct nec7210_priv *priv,
return 0;
}
-static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written)
{
size_t last_count = 0;
@@ -662,7 +666,8 @@ static int pio_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_
if (retval == -EIO) {
/* resend last byte on bus error */
*bytes_written = last_count;
- /* we can get unrecoverable bus errors,
+ /*
+ * we can get unrecoverable bus errors,
* so give up after a while
*/
bus_error_count++;
@@ -742,7 +747,7 @@ static ssize_t __dma_write(struct gpib_board *board, struct nec7210_priv *priv,
return retval ? retval : length;
}
-static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, uint8_t *buffer,
+static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, u8 *buffer,
size_t length)
{
size_t remain = length;
@@ -767,7 +772,7 @@ static ssize_t dma_write(struct gpib_board *board, struct nec7210_priv *priv, ui
}
#endif
int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv,
- uint8_t *buffer, size_t length, int send_eoi,
+ u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
int retval = 0;
@@ -805,7 +810,8 @@ int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv,
if (send_eoi) {
size_t num_bytes;
- /* We need to wait to make sure we will immediately be able to write the data byte
+ /*
+ * We need to wait to make sure we will immediately be able to write the data byte
* into the chip before sending the associated AUX_SEOI command. This is really
* only needed for length==1 since otherwise the earlier calls to pio_write
* will have dont the wait already.
@@ -827,7 +833,7 @@ int nec7210_write(struct gpib_board *board, struct nec7210_priv *priv,
EXPORT_SYMBOL(nec7210_write);
/*
- * interrupt service routine
+ * interrupt service routine
*/
irqreturn_t nec7210_interrupt(struct gpib_board *board, struct nec7210_priv *priv)
{
@@ -932,13 +938,13 @@ irqreturn_t nec7210_interrupt_have_status(struct gpib_board *board,
// ignore device clear events if we are controller in charge
if ((address_status_bits & HR_CIC) == 0) {
- push_gpib_event(board, EventDevClr);
+ push_gpib_event(board, EVENT_DEV_CLR);
set_bit(DEV_CLEAR_BN, &priv->state);
}
}
if (status1 & HR_DET)
- push_gpib_event(board, EventDevTrg);
+ push_gpib_event(board, EVENT_DEV_TRG);
// Addressing status has changed
if (status2 & HR_ADSC)
@@ -1012,16 +1018,17 @@ EXPORT_SYMBOL(nec7210_board_online);
#ifdef CONFIG_HAS_IOPORT
/* wrappers for io */
-uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num)
+u8 nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num)
{
return inb(priv->iobase + register_num * priv->offset);
}
EXPORT_SYMBOL(nec7210_ioport_read_byte);
-void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num)
+void nec7210_ioport_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num)
{
if (register_num == AUXMR)
- /* locking makes absolutely sure noone accesses the
+ /*
+ * locking makes absolutely sure noone accesses the
* AUXMR register faster than once per microsecond
*/
nec7210_locking_ioport_write_byte(priv, data, register_num);
@@ -1031,7 +1038,7 @@ void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned
EXPORT_SYMBOL(nec7210_ioport_write_byte);
/* locking variants of io wrappers, for chips that page-in registers */
-uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num)
+u8 nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num)
{
u8 retval;
unsigned long flags;
@@ -1043,7 +1050,7 @@ uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int
}
EXPORT_SYMBOL(nec7210_locking_ioport_read_byte);
-void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data,
+void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num)
{
unsigned long flags;
@@ -1057,16 +1064,17 @@ void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data,
EXPORT_SYMBOL(nec7210_locking_ioport_write_byte);
#endif
-uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num)
+u8 nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num)
{
return readb(priv->mmiobase + register_num * priv->offset);
}
EXPORT_SYMBOL(nec7210_iomem_read_byte);
-void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num)
+void nec7210_iomem_write_byte(struct nec7210_priv *priv, u8 data, unsigned int register_num)
{
if (register_num == AUXMR)
- /* locking makes absolutely sure noone accesses the
+ /*
+ * locking makes absolutely sure noone accesses the
* AUXMR register faster than once per microsecond
*/
nec7210_locking_iomem_write_byte(priv, data, register_num);
@@ -1075,7 +1083,7 @@ void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned
}
EXPORT_SYMBOL(nec7210_iomem_write_byte);
-uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num)
+u8 nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num)
{
u8 retval;
unsigned long flags;
@@ -1087,7 +1095,7 @@ uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int
}
EXPORT_SYMBOL(nec7210_locking_iomem_read_byte);
-void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data,
+void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, u8 data,
unsigned int register_num)
{
unsigned long flags;
diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c
index 9f1b9927f025..9ec850c4749f 100644
--- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c
+++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c
@@ -74,7 +74,8 @@ static unsigned short ni_usb_timeout_code(unsigned int usec)
return 0xff;
else if (usec <= 300000000)
return 0x01;
- /* NI driver actually uses 0xff for timeout T1000s, which is a bug in their code.
+ /*
+ * NI driver actually uses 0xff for timeout T1000s, which is a bug in their code.
* I've verified on a usb-b that a code of 0x2 is correct for a 1000 sec timeout
*/
else if (usec <= 1000000000)
@@ -232,7 +233,8 @@ static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv,
mutex_unlock(&ni_priv->bulk_transfer_lock);
if (interruptible) {
if (wait_for_completion_interruptible(&context->complete)) {
- /* If we got interrupted by a signal while
+ /*
+ * If we got interrupted by a signal while
* waiting for the usb gpib to respond, we
* should send a stop command so it will
* finish up with whatever it was doing and
@@ -240,8 +242,9 @@ static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv,
*/
ni_usb_stop(ni_priv);
retval = -ERESTARTSYS;
- /* now do an uninterruptible wait, it shouldn't take long
- * for the board to respond now.
+ /*
+ * now do an uninterruptible wait, it shouldn't take long
+ * for the board to respond now.
*/
wait_for_completion(&context->complete);
}
@@ -586,7 +589,7 @@ static int ni_usb_write_registers(struct ni_usb_priv *ni_priv,
}
// interface functions
-static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int ni_usb_read(struct gpib_board *board, u8 *buffer, size_t length,
int *end, size_t *bytes_read)
{
int retval, parse_retval;
@@ -684,7 +687,8 @@ static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length,
retval = 0;
break;
case NIUSB_ABORTED_ERROR:
- /* this is expected if ni_usb_receive_bulk_msg got
+ /*
+ * this is expected if ni_usb_receive_bulk_msg got
* interrupted by a signal and returned -ERESTARTSYS
*/
break;
@@ -716,7 +720,7 @@ static int ni_usb_read(struct gpib_board *board, uint8_t *buffer, size_t length,
return retval;
}
-static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int ni_usb_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, size_t *bytes_written)
{
int retval;
@@ -794,7 +798,8 @@ static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length
retval = 0;
break;
case NIUSB_ABORTED_ERROR:
- /* this is expected if ni_usb_receive_bulk_msg got
+ /*
+ * this is expected if ni_usb_receive_bulk_msg got
* interrupted by a signal and returned -ERESTARTSYS
*/
break;
@@ -819,7 +824,7 @@ static int ni_usb_write(struct gpib_board *board, uint8_t *buffer, size_t length
return retval;
}
-static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int ni_usb_command_chunk(struct gpib_board *board, u8 *buffer, size_t length,
size_t *command_bytes_written)
{
int retval;
@@ -893,7 +898,8 @@ static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_
case NIUSB_NO_ERROR:
break;
case NIUSB_ABORTED_ERROR:
- /* this is expected if ni_usb_receive_bulk_msg got
+ /*
+ * this is expected if ni_usb_receive_bulk_msg got
* interrupted by a signal and returned -ERESTARTSYS
*/
break;
@@ -912,7 +918,7 @@ static int ni_usb_command_chunk(struct gpib_board *board, uint8_t *buffer, size_
return 0;
}
-static int ni_usb_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int ni_usb_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
size_t count;
@@ -1049,7 +1055,7 @@ static int ni_usb_go_to_standby(struct gpib_board *board)
return 0;
}
-static void ni_usb_request_system_control(struct gpib_board *board, int request_control)
+static int ni_usb_request_system_control(struct gpib_board *board, int request_control)
{
int retval;
struct ni_usb_priv *ni_priv = board->private_data;
@@ -1059,7 +1065,7 @@ static void ni_usb_request_system_control(struct gpib_board *board, int request_
unsigned int ibsta;
if (!ni_priv->bus_interface)
- return; // -ENODEV;
+ return -ENODEV;
usb_dev = interface_to_usbdev(ni_priv->bus_interface);
if (request_control) {
writes[i].device = NIUSB_SUBDEV_TNT4882;
@@ -1091,12 +1097,12 @@ static void ni_usb_request_system_control(struct gpib_board *board, int request_
retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta);
if (retval < 0) {
dev_err(&usb_dev->dev, "register write failed, retval=%i\n", retval);
- return; // retval;
+ return retval;
}
if (!request_control)
ni_priv->ren_state = 0;
ni_usb_soft_update_status(board, ibsta, 0);
- return; // 0;
+ return 0;
}
//FIXME maybe the interface should have a "pulse interface clear" function that can return an error?
@@ -1176,7 +1182,7 @@ static void ni_usb_remote_enable(struct gpib_board *board, int enable)
return;// 0;
}
-static int ni_usb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int ni_usb_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct ni_usb_priv *ni_priv = board->private_data;
@@ -1192,8 +1198,9 @@ static int ni_usb_enable_eos(struct gpib_board *board, uint8_t eos_byte, int com
static void ni_usb_disable_eos(struct gpib_board *board)
{
struct ni_usb_priv *ni_priv = board->private_data;
- /* adapter gets unhappy if you don't zero all the bits
- * for the eos mode and eos char (returns error 4 on reads).
+ /*
+ * adapter gets unhappy if you don't zero all the bits
+ * for the eos mode and eos char (returns error 4 on reads).
*/
ni_priv->eos_mode = 0;
ni_priv->eos_char = 0;
@@ -1334,7 +1341,7 @@ static int ni_usb_secondary_address(struct gpib_board *board, unsigned int addre
return 0;
}
-static int ni_usb_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int ni_usb_parallel_poll(struct gpib_board *board, u8 *result)
{
int retval;
struct ni_usb_priv *ni_priv = board->private_data;
@@ -1389,7 +1396,7 @@ static int ni_usb_parallel_poll(struct gpib_board *board, uint8_t *result)
return retval;
}
-static void ni_usb_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void ni_usb_parallel_poll_configure(struct gpib_board *board, u8 config)
{
int retval;
struct ni_usb_priv *ni_priv = board->private_data;
@@ -1467,7 +1474,7 @@ static void ni_usb_serial_poll_response(struct gpib_board *board, u8 status)
return;// 0;
}
-static uint8_t ni_usb_serial_poll_status(struct gpib_board *board)
+static u8 ni_usb_serial_poll_status(struct gpib_board *board)
{
return 0;
}
@@ -2045,8 +2052,10 @@ static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv)
unexpected = 1;
}
++j;
- // MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here
- // NI-USB-HS+ sends 0x0
+ /*
+ * MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here
+ * NI-USB-HS+ sends 0x0
+ */
if (buffer[j] != 0x1 && buffer[j] != 0x8 && buffer[j] != 0x7 && buffer[j] != 0x0) {
// [3]
dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x0, 0x1, 0x7 or 0x8\n",
@@ -2127,7 +2136,8 @@ ready_out:
return retval;
}
-/* This does some extra init for HS+ models, as observed on Windows. One of the
+/*
+ * This does some extra init for HS+ models, as observed on Windows. One of the
* control requests causes the LED to stop blinking.
* I'm not sure what the other 2 requests do. None of these requests are actually required
* for the adapter to work, maybe they do some init for the analyzer interface
@@ -2198,14 +2208,14 @@ static int ni_usb_hs_plus_extra_init(struct ni_usb_priv *ni_priv)
}
static inline int ni_usb_device_match(struct usb_interface *interface,
- const gpib_board_config_t *config)
+ const struct gpib_board_config *config)
{
if (gpib_match_device_path(&interface->dev, config->device_path) == 0)
return 0;
return 1;
}
-static int ni_usb_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_usb_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int retval;
int i, index;
@@ -2343,8 +2353,10 @@ static void ni_usb_detach(struct gpib_board *board)
struct ni_usb_priv *ni_priv;
mutex_lock(&ni_usb_hotplug_lock);
-// under windows, software unplug does chip_reset nec7210 aux command,
-// then writes 0x0 to address 0x10 of device 3
+ /*
+ * under windows, software unplug does chip_reset nec7210 aux command,
+ * then writes 0x0 to address 0x10 of device 3
+ */
ni_priv = board->private_data;
if (ni_priv) {
if (ni_priv->bus_interface) {
@@ -2361,7 +2373,7 @@ static void ni_usb_detach(struct gpib_board *board)
mutex_unlock(&ni_usb_hotplug_lock);
}
-static gpib_interface_t ni_usb_gpib_interface = {
+static struct gpib_interface ni_usb_gpib_interface = {
.name = "ni_usb_b",
.attach = ni_usb_attach,
.detach = ni_usb_detach,
diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h
index 4b297db09a9b..b011e131201c 100644
--- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h
+++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h
@@ -113,27 +113,37 @@ enum ni_usb_bulk_ids {
enum ni_usb_error_codes {
NIUSB_NO_ERROR = 0,
- /* NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by
- * doing a NI_USB_STOP_REQUEST on the control endpoint.
+ /*
+ * NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by
+ * doing a NI_USB_STOP_REQUEST on the control endpoint.
*/
NIUSB_ABORTED_ERROR = 1,
- // NIUSB_READ_ATN_ERROR occurs when you do a board read while
- // ATN is set
+ /*
+ * NIUSB_READ_ATN_ERROR occurs when you do a board read while
+ * ATN is set
+ */
NIUSB_ATN_STATE_ERROR = 2,
- // NIUSB_ADDRESSING_ERROR occurs when you do a board
- // read/write as CIC but are not in LACS/TACS
+ /*
+ * NIUSB_ADDRESSING_ERROR occurs when you do a board
+ * read/write as CIC but are not in LACS/TACS
+ */
NIUSB_ADDRESSING_ERROR = 3,
- /* NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char
+ /*
+ * NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char
* bits are set when REOS is not set.
* Have also seen error 4 if you try to send more than 16
* command bytes at once on a usb-b.
*/
NIUSB_EOSMODE_ERROR = 4,
- // NIUSB_NO_BUS_ERROR occurs when you try to write a command
- // byte but there are no devices connected to the gpib bus
+ /*
+ * NIUSB_NO_BUS_ERROR occurs when you try to write a command
+ * byte but there are no devices connected to the gpib bus
+ */
NIUSB_NO_BUS_ERROR = 5,
- // NIUSB_NO_LISTENER_ERROR occurs when you do a board write as
- // CIC with no listener
+ /*
+ * NIUSB_NO_LISTENER_ERROR occurs when you do a board write as
+ * CIC with no listener
+ */
NIUSB_NO_LISTENER_ERROR = 8,
// get NIUSB_TIMEOUT_ERROR on board read/write timeout
NIUSB_TIMEOUT_ERROR = 10,
diff --git a/drivers/staging/gpib/pc2/pc2_gpib.c b/drivers/staging/gpib/pc2/pc2_gpib.c
index 96d3c09f2273..2282492025b7 100644
--- a/drivers/staging/gpib/pc2/pc2_gpib.c
+++ b/drivers/staging/gpib/pc2/pc2_gpib.c
@@ -90,7 +90,7 @@ irqreturn_t pc2a_interrupt(int irq, void *arg)
}
// wrappers for interface functions
-static int pc2_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int pc2_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct pc2_priv *priv = board->private_data;
@@ -98,7 +98,7 @@ static int pc2_read(struct gpib_board *board, uint8_t *buffer, size_t length, in
return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read);
}
-static int pc2_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int pc2_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct pc2_priv *priv = board->private_data;
@@ -106,7 +106,8 @@ static int pc2_write(struct gpib_board *board, uint8_t *buffer, size_t length, i
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int pc2_command(struct gpib_board *board, uint8_t *buffer, size_t length, size_t *bytes_written)
+static int pc2_command(struct gpib_board *board, u8 *buffer,
+ size_t length, size_t *bytes_written)
{
struct pc2_priv *priv = board->private_data;
@@ -127,11 +128,11 @@ static int pc2_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void pc2_request_system_control(struct gpib_board *board, int request_control)
+static int pc2_request_system_control(struct gpib_board *board, int request_control)
{
struct pc2_priv *priv = board->private_data;
- nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
+ return nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
}
static void pc2_interface_clear(struct gpib_board *board, int assert)
@@ -148,7 +149,7 @@ static void pc2_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int pc2_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int pc2_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct pc2_priv *priv = board->private_data;
@@ -183,14 +184,14 @@ static int pc2_secondary_address(struct gpib_board *board, unsigned int address,
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int pc2_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int pc2_parallel_poll(struct gpib_board *board, u8 *result)
{
struct pc2_priv *priv = board->private_data;
return nec7210_parallel_poll(board, &priv->nec7210_priv, result);
}
-static void pc2_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void pc2_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct pc2_priv *priv = board->private_data;
@@ -204,14 +205,14 @@ static void pc2_parallel_poll_response(struct gpib_board *board, int ist)
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-static void pc2_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void pc2_serial_poll_response(struct gpib_board *board, u8 status)
{
struct pc2_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-static uint8_t pc2_serial_poll_status(struct gpib_board *board)
+static u8 pc2_serial_poll_status(struct gpib_board *board)
{
struct pc2_priv *priv = board->private_data;
@@ -251,7 +252,7 @@ static void free_private(struct gpib_board *board)
board->private_data = NULL;
}
-static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_t *config,
+static int pc2_generic_attach(struct gpib_board *board, const struct gpib_board_config *config,
enum nec7210_chipset chipset)
{
struct pc2_priv *pc2_priv;
@@ -267,8 +268,9 @@ static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_
nec_priv->type = chipset;
#ifndef PC2_DMA
- /* board->dev hasn't been initialized, so forget about DMA until this driver
- * is adapted to use isa_register_driver.
+ /*
+ * board->dev hasn't been initialized, so forget about DMA until this driver
+ * is adapted to use isa_register_driver.
*/
if (config->ibdma)
// driver needs to be adapted to use isa_register_driver to get a struct device*
@@ -294,7 +296,7 @@ static int pc2_generic_attach(struct gpib_board *board, const gpib_board_config_
return 0;
}
-static int pc2_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int pc2_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
int isr_flags = 0;
struct pc2_priv *pc2_priv;
@@ -365,7 +367,7 @@ static void pc2_detach(struct gpib_board *board)
free_private(board);
}
-static int pc2a_common_attach(struct gpib_board *board, const gpib_board_config_t *config,
+static int pc2a_common_attach(struct gpib_board *board, const struct gpib_board_config *config,
unsigned int num_registers, enum nec7210_chipset chipset)
{
unsigned int i, j;
@@ -459,17 +461,17 @@ static int pc2a_common_attach(struct gpib_board *board, const gpib_board_config_
return 0;
}
-static int pc2a_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int pc2a_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2a_iosize, NEC7210);
}
-static int pc2a_cb7210_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int pc2a_cb7210_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2a_iosize, CB7210);
}
-static int pc2_2a_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int pc2_2a_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return pc2a_common_attach(board, config, pc2_2a_iosize, NAT4882);
}
@@ -517,7 +519,7 @@ static void pc2_2a_detach(struct gpib_board *board)
pc2a_common_detach(board, pc2_2a_iosize);
}
-static gpib_interface_t pc2_interface = {
+static struct gpib_interface pc2_interface = {
.name = "pcII",
.attach = pc2_attach,
.detach = pc2_detach,
@@ -545,7 +547,7 @@ static gpib_interface_t pc2_interface = {
.return_to_local = pc2_return_to_local,
};
-static gpib_interface_t pc2a_interface = {
+static struct gpib_interface pc2a_interface = {
.name = "pcIIa",
.attach = pc2a_attach,
.detach = pc2a_detach,
@@ -573,7 +575,7 @@ static gpib_interface_t pc2a_interface = {
.return_to_local = pc2_return_to_local,
};
-static gpib_interface_t pc2a_cb7210_interface = {
+static struct gpib_interface pc2a_cb7210_interface = {
.name = "pcIIa_cb7210",
.attach = pc2a_cb7210_attach,
.detach = pc2a_detach,
@@ -601,7 +603,7 @@ static gpib_interface_t pc2a_cb7210_interface = {
.return_to_local = pc2_return_to_local,
};
-static gpib_interface_t pc2_2a_interface = {
+static struct gpib_interface pc2_2a_interface = {
.name = "pcII_IIa",
.attach = pc2_2a_attach,
.detach = pc2_2a_detach,
diff --git a/drivers/staging/gpib/tms9914/tms9914.c b/drivers/staging/gpib/tms9914/tms9914.c
index 2abda9d7dfcb..04d57108efc7 100644
--- a/drivers/staging/gpib/tms9914/tms9914.c
+++ b/drivers/staging/gpib/tms9914/tms9914.c
@@ -53,7 +53,8 @@ int tms9914_take_control(struct gpib_board *board, struct tms9914_priv *priv, in
}
EXPORT_SYMBOL_GPL(tms9914_take_control);
-/* The agilent 82350B has a buggy implementation of tcs which interferes with the
+/*
+ * The agilent 82350B has a buggy implementation of tcs which interferes with the
* operation of tca. It appears to be based on the controller state machine
* described in the TI 9900 TMS9914A data manual published in 1982. This
* manual describes tcs as putting the controller into a CWAS
@@ -66,7 +67,8 @@ EXPORT_SYMBOL_GPL(tms9914_take_control);
* The rest of the tms9914 based drivers still use tms9914_take_control
* directly (which does issue tcs).
*/
-int tms9914_take_control_workaround(struct gpib_board *board, struct tms9914_priv *priv, int synchronous)
+int tms9914_take_control_workaround(struct gpib_board *board,
+ struct tms9914_priv *priv, int synchronous)
{
if (synchronous)
return -ETIMEDOUT;
@@ -116,8 +118,8 @@ void tms9914_remote_enable(struct gpib_board *board, struct tms9914_priv *priv,
}
EXPORT_SYMBOL_GPL(tms9914_remote_enable);
-void tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
- int request_control)
+int tms9914_request_system_control(struct gpib_board *board, struct tms9914_priv *priv,
+ int request_control)
{
if (request_control) {
write_byte(priv, AUX_RQC, AUXCR);
@@ -125,6 +127,7 @@ void tms9914_request_system_control(struct gpib_board *board, struct tms9914_pri
clear_bit(CIC_NUM, &board->status);
write_byte(priv, AUX_RLC, AUXCR);
}
+ return 0;
}
EXPORT_SYMBOL_GPL(tms9914_request_system_control);
@@ -192,7 +195,7 @@ void tms9914_release_holdoff(struct tms9914_priv *priv)
}
EXPORT_SYMBOL_GPL(tms9914_release_holdoff);
-int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, uint8_t eos_byte,
+int tms9914_enable_eos(struct gpib_board *board, struct tms9914_priv *priv, u8 eos_byte,
int compare_8_bits)
{
priv->eos = eos_byte;
@@ -209,7 +212,7 @@ void tms9914_disable_eos(struct gpib_board *board, struct tms9914_priv *priv)
}
EXPORT_SYMBOL(tms9914_disable_eos);
-int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *result)
+int tms9914_parallel_poll(struct gpib_board *board, struct tms9914_priv *priv, u8 *result)
{
// execute parallel poll
write_byte(priv, AUX_CS | AUX_RPP, AUXCR);
@@ -235,7 +238,7 @@ static void set_ppoll_reg(struct tms9914_priv *priv, int enable,
}
void tms9914_parallel_poll_configure(struct gpib_board *board,
- struct tms9914_priv *priv, uint8_t config)
+ struct tms9914_priv *priv, u8 config)
{
priv->ppoll_enable = (config & PPC_DISABLE) == 0;
priv->ppoll_line = (config & PPC_DIO_MASK) + 1;
@@ -251,7 +254,8 @@ void tms9914_parallel_poll_response(struct gpib_board *board,
}
EXPORT_SYMBOL(tms9914_parallel_poll_response);
-void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv *priv, uint8_t status)
+void tms9914_serial_poll_response(struct gpib_board *board,
+ struct tms9914_priv *priv, u8 status)
{
unsigned long flags;
@@ -266,7 +270,7 @@ void tms9914_serial_poll_response(struct gpib_board *board, struct tms9914_priv
}
EXPORT_SYMBOL(tms9914_serial_poll_response);
-uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv)
+u8 tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv *priv)
{
u8 status;
unsigned long flags;
@@ -279,7 +283,8 @@ uint8_t tms9914_serial_poll_status(struct gpib_board *board, struct tms9914_priv
}
EXPORT_SYMBOL(tms9914_serial_poll_status);
-int tms9914_primary_address(struct gpib_board *board, struct tms9914_priv *priv, unsigned int address)
+int tms9914_primary_address(struct gpib_board *board,
+ struct tms9914_priv *priv, unsigned int address)
{
// put primary address in address0
write_byte(priv, address & ADDRESS_MASK, ADR);
@@ -321,7 +326,8 @@ static void update_talker_state(struct tms9914_priv *priv, unsigned int address_
if (address_status_bits & HR_ATN)
priv->talker_state = talker_addressed;
else
- /* this could also be serial_poll_active, but the tms9914 provides no
+ /*
+ * this could also be serial_poll_active, but the tms9914 provides no
* way to distinguish, so we'll assume talker_active
*/
priv->talker_state = talker_active;
@@ -416,7 +422,7 @@ int tms9914_line_status(const struct gpib_board *board, struct tms9914_priv *pri
}
EXPORT_SYMBOL(tms9914_line_status);
-static int check_for_eos(struct tms9914_priv *priv, uint8_t byte)
+static int check_for_eos(struct tms9914_priv *priv, u8 byte)
{
static const u8 seven_bit_compare_mask = 0x7f;
@@ -449,7 +455,8 @@ static int wait_for_read_byte(struct gpib_board *board, struct tms9914_priv *pri
return 0;
}
-static inline uint8_t tms9914_read_data_in(struct gpib_board *board, struct tms9914_priv *priv, int *end)
+static inline u8 tms9914_read_data_in(struct gpib_board *board,
+ struct tms9914_priv *priv, int *end)
{
unsigned long flags;
u8 data;
@@ -480,7 +487,7 @@ static inline uint8_t tms9914_read_data_in(struct gpib_board *board, struct tms9
return data;
}
-static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
@@ -501,7 +508,7 @@ static int pio_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t
return retval;
}
-int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+int tms9914_read(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, int *end, size_t *bytes_read)
{
ssize_t retval = 0;
@@ -561,7 +568,7 @@ static int pio_write_wait(struct gpib_board *board, struct tms9914_priv *priv)
return 0;
}
-static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written)
{
ssize_t retval = 0;
@@ -585,8 +592,8 @@ static int pio_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_
return length;
}
-int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer, size_t length,
- int send_eoi, size_t *bytes_written)
+int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv,
+ u8 *buffer, size_t length, int send_eoi, size_t *bytes_written)
{
ssize_t retval = 0;
@@ -620,7 +627,8 @@ int tms9914_write(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *
}
EXPORT_SYMBOL(tms9914_write);
-static void check_my_address_state(struct gpib_board *board, struct tms9914_priv *priv, int cmd_byte)
+static void check_my_address_state(struct gpib_board *board,
+ struct tms9914_priv *priv, int cmd_byte)
{
if (cmd_byte == MLA(board->pad)) {
priv->primary_listen_addressed = 1;
@@ -655,7 +663,7 @@ static void check_my_address_state(struct gpib_board *board, struct tms9914_priv
}
}
-int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, uint8_t *buffer,
+int tms9914_command(struct gpib_board *board, struct tms9914_priv *priv, u8 *buffer,
size_t length, size_t *bytes_written)
{
int retval = 0;
@@ -736,9 +744,10 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99
unsigned short command_byte = read_byte(priv, CPTR) & gpib_command_mask;
switch (command_byte) {
- case PPConfig:
+ case PP_CONFIG:
priv->ppoll_configure_state = 1;
- /* AUX_PTS generates another UNC interrupt on the next command byte
+ /*
+ * AUX_PTS generates another UNC interrupt on the next command byte
* if it is in the secondary address group (such as PPE and PPD).
*/
write_byte(priv, AUX_PTS, AUXCR);
@@ -764,7 +773,7 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99
break;
}
- if (in_primary_command_group(command_byte) && command_byte != PPConfig)
+ if (in_primary_command_group(command_byte) && command_byte != PP_CONFIG)
priv->ppoll_configure_state = 0;
}
@@ -774,18 +783,18 @@ irqreturn_t tms9914_interrupt_have_status(struct gpib_board *board, struct tms99
}
if (status1 & HR_IFC) {
- push_gpib_event(board, EventIFC);
+ push_gpib_event(board, EVENT_IFC);
clear_bit(CIC_NUM, &board->status);
}
if (status1 & HR_GET) {
- push_gpib_event(board, EventDevTrg);
+ push_gpib_event(board, EVENT_DEV_TRG);
// clear dac holdoff
write_byte(priv, AUX_VAL, AUXCR);
}
if (status1 & HR_DCAS) {
- push_gpib_event(board, EventDevClr);
+ push_gpib_event(board, EVENT_DEV_CLR);
// clear dac holdoff
write_byte(priv, AUX_VAL, AUXCR);
set_bit(DEV_CLEAR_BN, &priv->state);
@@ -859,14 +868,14 @@ EXPORT_SYMBOL_GPL(tms9914_online);
#ifdef CONFIG_HAS_IOPORT
// wrapper for inb
-uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num)
+u8 tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return inb(priv->iobase + register_num * priv->offset);
}
EXPORT_SYMBOL_GPL(tms9914_ioport_read_byte);
// wrapper for outb
-void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num)
+void tms9914_ioport_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
outb(data, priv->iobase + register_num * priv->offset);
if (register_num == AUXCR)
@@ -876,14 +885,14 @@ EXPORT_SYMBOL_GPL(tms9914_ioport_write_byte);
#endif
// wrapper for readb
-uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num)
+u8 tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num)
{
return readb(priv->mmiobase + register_num * priv->offset);
}
EXPORT_SYMBOL_GPL(tms9914_iomem_read_byte);
// wrapper for writeb
-void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num)
+void tms9914_iomem_write_byte(struct tms9914_priv *priv, u8 data, unsigned int register_num)
{
writeb(data, priv->mmiobase + register_num * priv->offset);
if (register_num == AUXCR)
diff --git a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c
index c35b084b6fd0..a17b69e34986 100644
--- a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c
+++ b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c
@@ -236,7 +236,7 @@ static int fifo_xfer_done(struct tnt4882_priv *tnt_priv)
return retval;
}
-static int drain_fifo_words(struct tnt4882_priv *tnt_priv, uint8_t *buffer, int num_bytes)
+static int drain_fifo_words(struct tnt4882_priv *tnt_priv, u8 *buffer, int num_bytes)
{
int count = 0;
struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv;
@@ -258,7 +258,8 @@ static void tnt4882_release_holdoff(struct gpib_board *board, struct tnt4882_pri
sasr_bits = tnt_readb(tnt_priv, SASR);
- /*tnt4882 not in one-chip mode won't always release holdoff unless we
+ /*
+ * tnt4882 not in one-chip mode won't always release holdoff unless we
* are in the right mode when release handshake command is given
*/
if (sasr_bits & AEHS_BIT) /* holding off due to holdoff on end mode*/ {
@@ -274,7 +275,7 @@ static void tnt4882_release_holdoff(struct gpib_board *board, struct tnt4882_pri
}
}
-static int tnt4882_accel_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int tnt4882_accel_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
size_t count = 0;
@@ -384,7 +385,8 @@ static int tnt4882_accel_read(struct gpib_board *board, uint8_t *buffer, size_t
nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, 0);
nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0);
- /* force handling of any pending interrupts (seems to be needed
+ /*
+ * force handling of any pending interrupts (seems to be needed
* to keep interrupts from getting hosed, plus for syncing
* with RECEIVED_END below)
*/
@@ -448,7 +450,7 @@ static int write_wait(struct gpib_board *board, struct tnt4882_priv *tnt_priv,
return 0;
}
-static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int generic_write(struct gpib_board *board, u8 *buffer, size_t length,
int send_eoi, int send_commands, size_t *bytes_written)
{
size_t count = 0;
@@ -531,7 +533,8 @@ static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t lengt
nec7210_set_reg_bits(nec_priv, IMR1, HR_ERR, 0x0);
nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0x0);
- /* force handling of any interrupts that happened
+ /*
+ * force handling of any interrupts that happened
* while they were masked (this appears to be needed)
*/
tnt4882_internal_interrupt(board);
@@ -539,13 +542,13 @@ static int generic_write(struct gpib_board *board, uint8_t *buffer, size_t lengt
return retval;
}
-static int tnt4882_accel_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
- size_t *bytes_written)
+static int tnt4882_accel_write(struct gpib_board *board, u8 *buffer,
+ size_t length, int send_eoi, size_t *bytes_written)
{
return generic_write(board, buffer, length, send_eoi, 0, bytes_written);
}
-static int tnt4882_command(struct gpib_board *board, uint8_t *buffer, size_t length,
+static int tnt4882_command(struct gpib_board *board, u8 *buffer, size_t length,
size_t *bytes_written)
{
return generic_write(board, buffer, length, 0, 1, bytes_written);
@@ -566,7 +569,7 @@ static irqreturn_t tnt4882_internal_interrupt(struct gpib_board *board)
imr3_bits = priv->imr3_bits;
if (isr0_bits & TNT_IFCI_BIT)
- push_gpib_event(board, EventIFC);
+ push_gpib_event(board, EVENT_IFC);
//XXX don't need this wakeup, one below should do?
// wake_up_interruptible(&board->wait);
@@ -592,7 +595,7 @@ static irqreturn_t tnt4882_interrupt(int irq, void *arg)
}
// wrappers for interface functions
-static int tnt4882_read(struct gpib_board *board, uint8_t *buffer, size_t length, int *end,
+static int tnt4882_read(struct gpib_board *board, u8 *buffer, size_t length, int *end,
size_t *bytes_read)
{
struct tnt4882_priv *priv = board->private_data;
@@ -612,7 +615,7 @@ static int tnt4882_read(struct gpib_board *board, uint8_t *buffer, size_t length
return retval;
}
-static int tnt4882_write(struct gpib_board *board, uint8_t *buffer, size_t length, int send_eoi,
+static int tnt4882_write(struct gpib_board *board, u8 *buffer, size_t length, int send_eoi,
size_t *bytes_written)
{
struct tnt4882_priv *priv = board->private_data;
@@ -620,7 +623,7 @@ static int tnt4882_write(struct gpib_board *board, uint8_t *buffer, size_t lengt
return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written);
}
-static int tnt4882_command_unaccel(struct gpib_board *board, uint8_t *buffer,
+static int tnt4882_command_unaccel(struct gpib_board *board, u8 *buffer,
size_t length, size_t *bytes_written)
{
struct tnt4882_priv *priv = board->private_data;
@@ -642,19 +645,21 @@ static int tnt4882_go_to_standby(struct gpib_board *board)
return nec7210_go_to_standby(board, &priv->nec7210_priv);
}
-static void tnt4882_request_system_control(struct gpib_board *board, int request_control)
+static int tnt4882_request_system_control(struct gpib_board *board, int request_control)
{
struct tnt4882_priv *priv = board->private_data;
+ int retval;
if (request_control) {
tnt_writeb(priv, SETSC, CMDR);
udelay(1);
}
- nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
+ retval = nec7210_request_system_control(board, &priv->nec7210_priv, request_control);
if (!request_control) {
tnt_writeb(priv, CLRSC, CMDR);
udelay(1);
}
+ return retval;
}
static void tnt4882_interface_clear(struct gpib_board *board, int assert)
@@ -671,7 +676,7 @@ static void tnt4882_remote_enable(struct gpib_board *board, int enable)
nec7210_remote_enable(board, &priv->nec7210_priv, enable);
}
-static int tnt4882_enable_eos(struct gpib_board *board, uint8_t eos_byte, int compare_8_bits)
+static int tnt4882_enable_eos(struct gpib_board *board, u8 eos_byte, int compare_8_bits)
{
struct tnt4882_priv *priv = board->private_data;
@@ -718,7 +723,7 @@ static int tnt4882_secondary_address(struct gpib_board *board, unsigned int addr
return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable);
}
-static int tnt4882_parallel_poll(struct gpib_board *board, uint8_t *result)
+static int tnt4882_parallel_poll(struct gpib_board *board, u8 *result)
{
struct tnt4882_priv *tnt_priv = board->private_data;
@@ -735,7 +740,7 @@ static int tnt4882_parallel_poll(struct gpib_board *board, uint8_t *result)
}
}
-static void tnt4882_parallel_poll_configure(struct gpib_board *board, uint8_t config)
+static void tnt4882_parallel_poll_configure(struct gpib_board *board, u8 config)
{
struct tnt4882_priv *priv = board->private_data;
@@ -760,17 +765,18 @@ static void tnt4882_parallel_poll_response(struct gpib_board *board, int ist)
nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist);
}
-/* this is just used by the old nec7210 isa interfaces, the newer
+/*
+ * this is just used by the old nec7210 isa interfaces, the newer
* boards use tnt4882_serial_poll_response2
*/
-static void tnt4882_serial_poll_response(struct gpib_board *board, uint8_t status)
+static void tnt4882_serial_poll_response(struct gpib_board *board, u8 status)
{
struct tnt4882_priv *priv = board->private_data;
nec7210_serial_poll_response(board, &priv->nec7210_priv, status);
}
-static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t status,
+static void tnt4882_serial_poll_response2(struct gpib_board *board, u8 status,
int new_reason_for_service)
{
struct tnt4882_priv *priv = board->private_data;
@@ -788,7 +794,8 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat
priv->nec7210_priv.srq_pending = 0;
}
if (reqt)
- /* It may seem like a race to issue reqt before updating
+ /*
+ * It may seem like a race to issue reqt before updating
* the status byte, but it is not. The chip does not
* issue the reqt until the SPMR is written to at
* a later time.
@@ -796,7 +803,8 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat
write_byte(&priv->nec7210_priv, AUX_REQT, AUXMR);
else if (reqf)
write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR);
- /* We need to always zero bit 6 of the status byte before writing it to
+ /*
+ * We need to always zero bit 6 of the status byte before writing it to
* the SPMR to insure we are using
* serial poll mode SP1, and not accidentally triggering mode SP3.
*/
@@ -804,7 +812,7 @@ static void tnt4882_serial_poll_response2(struct gpib_board *board, uint8_t stat
spin_unlock_irqrestore(&board->spinlock, flags);
}
-static uint8_t tnt4882_serial_poll_status(struct gpib_board *board)
+static u8 tnt4882_serial_poll_status(struct gpib_board *board)
{
struct tnt4882_priv *priv = board->private_data;
@@ -898,7 +906,7 @@ static void tnt4882_init(struct tnt4882_priv *tnt_priv, const struct gpib_board
tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0);
}
-static int ni_pci_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_pci_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct tnt4882_priv *tnt_priv;
struct nec7210_priv *nec_priv;
@@ -1019,7 +1027,7 @@ static int ni_isapnp_find(struct pnp_dev **dev)
return 0;
}
-static int ni_isa_attach_common(struct gpib_board *board, const gpib_board_config_t *config,
+static int ni_isa_attach_common(struct gpib_board *board, const struct gpib_board_config *config,
enum nec7210_chipset chipset)
{
struct tnt4882_priv *tnt_priv;
@@ -1075,17 +1083,17 @@ static int ni_isa_attach_common(struct gpib_board *board, const gpib_board_confi
return 0;
}
-static int ni_tnt_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_tnt_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return ni_isa_attach_common(board, config, TNT4882);
}
-static int ni_nat4882_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_nat4882_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return ni_isa_attach_common(board, config, NAT4882);
}
-static int ni_nec_isa_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_nec_isa_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
return ni_isa_attach_common(board, config, NEC7210);
}
@@ -1116,7 +1124,7 @@ static int tnt4882_pci_probe(struct pci_dev *dev, const struct pci_device_id *id
return 0;
}
-static gpib_interface_t ni_pci_interface = {
+static struct gpib_interface ni_pci_interface = {
.name = "ni_pci",
.attach = ni_pci_attach,
.detach = ni_pci_detach,
@@ -1144,7 +1152,7 @@ static gpib_interface_t ni_pci_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_pci_accel_interface = {
+static struct gpib_interface ni_pci_accel_interface = {
.name = "ni_pci_accel",
.attach = ni_pci_attach,
.detach = ni_pci_detach,
@@ -1172,7 +1180,7 @@ static gpib_interface_t ni_pci_accel_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_isa_interface = {
+static struct gpib_interface ni_isa_interface = {
.name = "ni_isa",
.attach = ni_tnt_isa_attach,
.detach = ni_isa_detach,
@@ -1200,7 +1208,7 @@ static gpib_interface_t ni_isa_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_nat4882_isa_interface = {
+static struct gpib_interface ni_nat4882_isa_interface = {
.name = "ni_nat4882_isa",
.attach = ni_nat4882_isa_attach,
.detach = ni_isa_detach,
@@ -1228,7 +1236,7 @@ static gpib_interface_t ni_nat4882_isa_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_nec_isa_interface = {
+static struct gpib_interface ni_nec_isa_interface = {
.name = "ni_nec_isa",
.attach = ni_nec_isa_attach,
.detach = ni_isa_detach,
@@ -1256,7 +1264,7 @@ static gpib_interface_t ni_nec_isa_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_isa_accel_interface = {
+static struct gpib_interface ni_isa_accel_interface = {
.name = "ni_isa_accel",
.attach = ni_tnt_isa_attach,
.detach = ni_isa_detach,
@@ -1284,7 +1292,7 @@ static gpib_interface_t ni_isa_accel_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_nat4882_isa_accel_interface = {
+static struct gpib_interface ni_nat4882_isa_accel_interface = {
.name = "ni_nat4882_isa_accel",
.attach = ni_nat4882_isa_attach,
.detach = ni_isa_detach,
@@ -1312,7 +1320,7 @@ static gpib_interface_t ni_nat4882_isa_accel_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_nec_isa_accel_interface = {
+static struct gpib_interface ni_nec_isa_accel_interface = {
.name = "ni_nec_isa_accel",
.attach = ni_nec_isa_attach,
.detach = ni_isa_detach,
@@ -1371,8 +1379,8 @@ MODULE_DEVICE_TABLE(pnp, tnt4882_pnp_table);
#endif
#ifdef CONFIG_GPIB_PCMCIA
-static gpib_interface_t ni_pcmcia_interface;
-static gpib_interface_t ni_pcmcia_accel_interface;
+static struct gpib_interface ni_pcmcia_interface;
+static struct gpib_interface ni_pcmcia_accel_interface;
static int __init init_ni_gpib_cs(void);
static void __exit exit_ni_gpib_cs(void);
#endif
@@ -1581,10 +1589,10 @@ static int ni_gpib_probe(struct pcmcia_device *link)
}
/*
- * This deletes a driver "instance". The device is de-registered
- * with Card Services. If it has been released, all local data
- * structures are freed. Otherwise, the structures will be freed
- * when the device is released.
+ * This deletes a driver "instance". The device is de-registered
+ * with Card Services. If it has been released, all local data
+ * structures are freed. Otherwise, the structures will be freed
+ * when the device is released.
*/
static void ni_gpib_remove(struct pcmcia_device *link)
{
@@ -1611,9 +1619,9 @@ static int ni_gpib_config_iteration(struct pcmcia_device *link, void *priv_data)
}
/*
- * ni_gpib_config() is scheduled to run after a CARD_INSERTION event
- * is received, to configure the PCMCIA socket, and to make the
- * device available to the system.
+ * ni_gpib_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
*/
static int ni_gpib_config(struct pcmcia_device *link)
{
@@ -1702,7 +1710,7 @@ static void __exit exit_ni_gpib_cs(void)
static const int pcmcia_gpib_iosize = 32;
-static int ni_pcmcia_attach(struct gpib_board *board, const gpib_board_config_t *config)
+static int ni_pcmcia_attach(struct gpib_board *board, const struct gpib_board_config *config)
{
struct local_info_t *info;
struct tnt4882_priv *tnt_priv;
@@ -1769,7 +1777,7 @@ static void ni_pcmcia_detach(struct gpib_board *board)
tnt4882_free_private(board);
}
-static gpib_interface_t ni_pcmcia_interface = {
+static struct gpib_interface ni_pcmcia_interface = {
.name = "ni_pcmcia",
.attach = ni_pcmcia_attach,
.detach = ni_pcmcia_detach,
@@ -1797,7 +1805,7 @@ static gpib_interface_t ni_pcmcia_interface = {
.return_to_local = tnt4882_return_to_local,
};
-static gpib_interface_t ni_pcmcia_accel_interface = {
+static struct gpib_interface ni_pcmcia_accel_interface = {
.name = "ni_pcmcia_accel",
.attach = ni_pcmcia_attach,
.detach = ni_pcmcia_detach,
diff --git a/drivers/staging/gpib/uapi/gpib_user.h b/drivers/staging/gpib/uapi/gpib.h
index 5ff4588686fd..41500cee4029 100644
--- a/drivers/staging/gpib/uapi/gpib_user.h
+++ b/drivers/staging/gpib/uapi/gpib.h
@@ -4,8 +4,8 @@
* copyright : (C) 2002 by Frank Mori Hess
***************************************************************************/
-#ifndef _GPIB_USER_H
-#define _GPIB_USER_H
+#ifndef _GPIB_H
+#define _GPIB_H
#define GPIB_MAX_NUM_BOARDS 16
#define GPIB_MAX_NUM_DESCRIPTORS 0x1000
@@ -53,48 +53,6 @@ enum ibsta_bits {
EVENT | LOK | REM | CIC | ATN | TACS | LACS | DTAS | DCAS | SRQI,
};
-/* IBERR error codes */
-enum iberr_code {
- EDVR = 0, /* system error */
- ECIC = 1, /* not CIC */
- ENOL = 2, /* no listeners */
- EADR = 3, /* CIC and not addressed before I/O */
- EARG = 4, /* bad argument to function call */
- ESAC = 5, /* not SAC */
- EABO = 6, /* I/O operation was aborted */
- ENEB = 7, /* non-existent board (GPIB interface offline) */
- EDMA = 8, /* DMA hardware error detected */
- EOIP = 10, /* new I/O attempted with old I/O in progress */
- ECAP = 11, /* no capability for intended opeation */
- EFSO = 12, /* file system operation error */
- EBUS = 14, /* bus error */
- ESTB = 15, /* lost serial poll bytes */
- ESRQ = 16, /* SRQ stuck on */
- ETAB = 20 /* Table Overflow */
-};
-
-/* Timeout values and meanings */
-enum gpib_timeout {
- TNONE = 0, /* Infinite timeout (disabled) */
- T10us = 1, /* Timeout of 10 usec (ideal) */
- T30us = 2, /* Timeout of 30 usec (ideal) */
- T100us = 3, /* Timeout of 100 usec (ideal) */
- T300us = 4, /* Timeout of 300 usec (ideal) */
- T1ms = 5, /* Timeout of 1 msec (ideal) */
- T3ms = 6, /* Timeout of 3 msec (ideal) */
- T10ms = 7, /* Timeout of 10 msec (ideal) */
- T30ms = 8, /* Timeout of 30 msec (ideal) */
- T100ms = 9, /* Timeout of 100 msec (ideal) */
- T300ms = 10, /* Timeout of 300 msec (ideal) */
- T1s = 11, /* Timeout of 1 sec (ideal) */
- T3s = 12, /* Timeout of 3 sec (ideal) */
- T10s = 13, /* Timeout of 10 sec (ideal) */
- T30s = 14, /* Timeout of 30 sec (ideal) */
- T100s = 15, /* Timeout of 100 sec (ideal) */
- T300s = 16, /* Timeout of 300 sec (ideal) */
- T1000s = 17 /* Timeout of 1000 sec (maximum) */
-};
-
/* End-of-string (EOS) modes for use with ibeos */
enum eos_flags {
@@ -130,9 +88,9 @@ enum bus_control_line {
enum cmd_byte {
GTL = 0x1, /* go to local */
SDC = 0x4, /* selected device clear */
- PPConfig = 0x5,
+ PP_CONFIG = 0x5,
#ifndef PPC
- PPC = PPConfig, /* parallel poll configure */
+ PPC = PP_CONFIG, /* parallel poll configure */
#endif
GET = 0x8, /* group execute trigger */
TCT = 0x9, /* take control */
@@ -166,24 +124,24 @@ static inline unsigned int gpib_address_restrict(unsigned int addr)
return addr;
}
-static inline uint8_t MLA(unsigned int addr)
+static inline __u8 MLA(unsigned int addr)
{
return gpib_address_restrict(addr) | LAD;
}
-static inline uint8_t MTA(unsigned int addr)
+static inline __u8 MTA(unsigned int addr)
{
return gpib_address_restrict(addr) | TAD;
}
-static inline uint8_t MSA(unsigned int addr)
+static inline __u8 MSA(unsigned int addr)
{
- return gpib_address_restrict(addr) | SAD;
+ return (addr & 0x1f) | SAD;
}
-static inline uint8_t PPE_byte(unsigned int dio_line, int sense)
+static inline __u8 PPE_byte(unsigned int dio_line, int sense)
{
- uint8_t cmd;
+ __u8 cmd;
cmd = PPE;
if (sense)
@@ -192,47 +150,42 @@ static inline uint8_t PPE_byte(unsigned int dio_line, int sense)
return cmd;
}
-static inline uint8_t CFGn(unsigned int meters)
-{
- return 0x6 | (meters & 0xf);
-}
-
/* mask of bits that actually matter in a command byte */
enum {
gpib_command_mask = 0x7f,
};
-static inline int is_PPE(uint8_t command)
+static inline int is_PPE(__u8 command)
{
return (command & 0x70) == 0x60;
}
-static inline int is_PPD(uint8_t command)
+static inline int is_PPD(__u8 command)
{
return (command & 0x70) == 0x70;
}
-static inline int in_addressed_command_group(uint8_t command)
+static inline int in_addressed_command_group(__u8 command)
{
return (command & 0x70) == 0x0;
}
-static inline int in_universal_command_group(uint8_t command)
+static inline int in_universal_command_group(__u8 command)
{
return (command & 0x70) == 0x10;
}
-static inline int in_listen_address_group(uint8_t command)
+static inline int in_listen_address_group(__u8 command)
{
return (command & 0x60) == 0x20;
}
-static inline int in_talk_address_group(uint8_t command)
+static inline int in_talk_address_group(__u8 command)
{
return (command & 0x60) == 0x40;
}
-static inline int in_primary_command_group(uint8_t command)
+static inline int in_primary_command_group(__u8 command)
{
return in_addressed_command_group(command) ||
in_universal_command_group(command) ||
@@ -253,75 +206,73 @@ static inline int gpib_address_equal(unsigned int pad1, int sad1, unsigned int p
}
enum ibask_option {
- IbaPAD = 0x1,
- IbaSAD = 0x2,
- IbaTMO = 0x3,
- IbaEOT = 0x4,
- IbaPPC = 0x5, /* board only */
- IbaREADDR = 0x6, /* device only */
- IbaAUTOPOLL = 0x7, /* board only */
- IbaCICPROT = 0x8, /* board only */
- IbaIRQ = 0x9, /* board only */
- IbaSC = 0xa, /* board only */
- IbaSRE = 0xb, /* board only */
- IbaEOSrd = 0xc,
- IbaEOSwrt = 0xd,
- IbaEOScmp = 0xe,
- IbaEOSchar = 0xf,
- IbaPP2 = 0x10, /* board only */
- IbaTIMING = 0x11, /* board only */
- IbaDMA = 0x12, /* board only */
- IbaReadAdjust = 0x13,
- IbaWriteAdjust = 0x14,
- IbaEventQueue = 0x15, /* board only */
- IbaSPollBit = 0x16, /* board only */
- IbaSpollBit = 0x16, /* board only */
- IbaSendLLO = 0x17, /* board only */
- IbaSPollTime = 0x18, /* device only */
- IbaPPollTime = 0x19, /* board only */
- IbaEndBitIsNormal = 0x1a,
- IbaUnAddr = 0x1b, /* device only */
- IbaHSCableLength = 0x1f, /* board only */
- IbaIst = 0x20, /* board only */
- IbaRsv = 0x21, /* board only */
- IbaBNA = 0x200, /* device only */
+ IBA_PAD = 0x1,
+ IBA_SAD = 0x2,
+ IBA_TMO = 0x3,
+ IBA_EOT = 0x4,
+ IBA_PPC = 0x5, /* board only */
+ IBA_READ_DR = 0x6, /* device only */
+ IBA_AUTOPOLL = 0x7, /* board only */
+ IBA_CICPROT = 0x8, /* board only */
+ IBA_IRQ = 0x9, /* board only */
+ IBA_SC = 0xa, /* board only */
+ IBA_SRE = 0xb, /* board only */
+ IBA_EOS_RD = 0xc,
+ IBA_EOS_WRT = 0xd,
+ IBA_EOS_CMP = 0xe,
+ IBA_EOS_CHAR = 0xf,
+ IBA_PP2 = 0x10, /* board only */
+ IBA_TIMING = 0x11, /* board only */
+ IBA_DMA = 0x12, /* board only */
+ IBA_READ_ADJUST = 0x13,
+ IBA_WRITE_ADJUST = 0x14,
+ IBA_EVENT_QUEUE = 0x15, /* board only */
+ IBA_SPOLL_BIT = 0x16, /* board only */
+ IBA_SEND_LLO = 0x17, /* board only */
+ IBA_SPOLL_TIME = 0x18, /* device only */
+ IBA_PPOLL_TIME = 0x19, /* board only */
+ IBA_END_BIT_IS_NORMAL = 0x1a,
+ IBA_UN_ADDR = 0x1b, /* device only */
+ IBA_HS_CABLE_LENGTH = 0x1f, /* board only */
+ IBA_IST = 0x20, /* board only */
+ IBA_RSV = 0x21, /* board only */
+ IBA_BNA = 0x200, /* device only */
/* linux-gpib extensions */
- Iba7BitEOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/
+ IBA_7_BIT_EOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/
};
enum ibconfig_option {
- IbcPAD = 0x1,
- IbcSAD = 0x2,
- IbcTMO = 0x3,
- IbcEOT = 0x4,
- IbcPPC = 0x5, /* board only */
- IbcREADDR = 0x6, /* device only */
- IbcAUTOPOLL = 0x7, /* board only */
- IbcCICPROT = 0x8, /* board only */
- IbcIRQ = 0x9, /* board only */
- IbcSC = 0xa, /* board only */
- IbcSRE = 0xb, /* board only */
- IbcEOSrd = 0xc,
- IbcEOSwrt = 0xd,
- IbcEOScmp = 0xe,
- IbcEOSchar = 0xf,
- IbcPP2 = 0x10, /* board only */
- IbcTIMING = 0x11, /* board only */
- IbcDMA = 0x12, /* board only */
- IbcReadAdjust = 0x13,
- IbcWriteAdjust = 0x14,
- IbcEventQueue = 0x15, /* board only */
- IbcSPollBit = 0x16, /* board only */
- IbcSpollBit = 0x16, /* board only */
- IbcSendLLO = 0x17, /* board only */
- IbcSPollTime = 0x18, /* device only */
- IbcPPollTime = 0x19, /* board only */
- IbcEndBitIsNormal = 0x1a,
- IbcUnAddr = 0x1b, /* device only */
- IbcHSCableLength = 0x1f, /* board only */
- IbcIst = 0x20, /* board only */
- IbcRsv = 0x21, /* board only */
- IbcBNA = 0x200 /* device only */
+ IBC_PAD = 0x1,
+ IBC_SAD = 0x2,
+ IBC_TMO = 0x3,
+ IBC_EOT = 0x4,
+ IBC_PPC = 0x5, /* board only */
+ IBC_READDR = 0x6, /* device only */
+ IBC_AUTOPOLL = 0x7, /* board only */
+ IBC_CICPROT = 0x8, /* board only */
+ IBC_IRQ = 0x9, /* board only */
+ IBC_SC = 0xa, /* board only */
+ IBC_SRE = 0xb, /* board only */
+ IBC_EOS_RD = 0xc,
+ IBC_EOS_WRT = 0xd,
+ IBC_EOS_CMP = 0xe,
+ IBC_EOS_CHAR = 0xf,
+ IBC_PP2 = 0x10, /* board only */
+ IBC_TIMING = 0x11, /* board only */
+ IBC_DMA = 0x12, /* board only */
+ IBC_READ_ADJUST = 0x13,
+ IBC_WRITE_ADJUST = 0x14,
+ IBC_EVENT_QUEUE = 0x15, /* board only */
+ IBC_SPOLL_BIT = 0x16, /* board only */
+ IBC_SEND_LLO = 0x17, /* board only */
+ IBC_SPOLL_TIME = 0x18, /* device only */
+ IBC_PPOLL_TIME = 0x19, /* board only */
+ IBC_END_BIT_IS_NORMAL = 0x1a,
+ IBC_UN_ADDR = 0x1b, /* device only */
+ IBC_HS_CABLE_LENGTH = 0x1f, /* board only */
+ IBC_IST = 0x20, /* board only */
+ IBC_RSV = 0x21, /* board only */
+ IBC_BNA = 0x200 /* device only */
};
enum t1_delays {
@@ -335,18 +286,17 @@ enum {
};
enum gpib_events {
- EventNone = 0,
- EventDevTrg = 1,
- EventDevClr = 2,
- EventIFC = 3
+ EVENT_NONE = 0,
+ EVENT_DEV_TRG = 1,
+ EVENT_DEV_CLR = 2,
+ EVENT_IFC = 3
};
enum gpib_stb {
- IbStbRQS = 0x40, /* IEEE 488.1 & 2 */
- IbStbESB = 0x20, /* IEEE 488.2 only */
- IbStbMAV = 0x10 /* IEEE 488.2 only */
+ IB_STB_RQS = 0x40, /* IEEE 488.1 & 2 */
+ IB_STB_ESB = 0x20, /* IEEE 488.2 only */
+ IB_STB_MAV = 0x10 /* IEEE 488.2 only */
};
-#endif /* _GPIB_USER_H */
+#endif /* _GPIB_H */
-/* Check for errors */
diff --git a/drivers/staging/gpib/uapi/gpib_ioctl.h b/drivers/staging/gpib/uapi/gpib_ioctl.h
index 6202865278ea..0fed5c0fa7f2 100644
--- a/drivers/staging/gpib/uapi/gpib_ioctl.h
+++ b/drivers/staging/gpib/uapi/gpib_ioctl.h
@@ -12,42 +12,42 @@
#define GPIB_CODE 160
-typedef struct {
+struct gpib_board_type_ioctl {
char name[100];
-} board_type_ioctl_t;
+};
/* argument for read/write/command ioctls */
-typedef struct {
- uint64_t buffer_ptr;
+struct gpib_read_write_ioctl {
+ __u64 buffer_ptr;
unsigned int requested_transfer_count;
unsigned int completed_transfer_count;
int end; /* end flag return for reads, end io suppression request for cmd*/
int handle;
-} read_write_ioctl_t;
+};
-typedef struct {
+struct gpib_open_dev_ioctl {
unsigned int handle;
unsigned int pad;
int sad;
unsigned is_board : 1;
-} open_dev_ioctl_t;
+};
-typedef struct {
+struct gpib_close_dev_ioctl {
unsigned int handle;
-} close_dev_ioctl_t;
+};
-typedef struct {
+struct gpib_serial_poll_ioctl {
unsigned int pad;
int sad;
- uint8_t status_byte;
-} serial_poll_ioctl_t;
+ __u8 status_byte;
+};
-typedef struct {
+struct gpib_eos_ioctl {
int eos;
int eos_flags;
-} eos_ioctl_t;
+};
-typedef struct {
+struct gpib_wait_ioctl {
int handle;
int wait_mask;
int clear_mask;
@@ -56,21 +56,21 @@ typedef struct {
int pad;
int sad;
unsigned int usec_timeout;
-} wait_ioctl_t;
+};
-typedef struct {
- uint64_t init_data_ptr;
+struct gpib_online_ioctl {
+ __u64 init_data_ptr;
int init_data_length;
int online;
-} online_ioctl_t;
+};
-typedef struct {
+struct gpib_spoll_bytes_ioctl {
unsigned int num_bytes;
unsigned int pad;
int sad;
-} spoll_bytes_ioctl_t;
+};
-typedef struct {
+struct gpib_board_info_ioctl {
unsigned int pad;
int sad;
int parallel_poll_configuration;
@@ -79,91 +79,85 @@ typedef struct {
unsigned int t1_delay;
unsigned ist : 1;
unsigned no_7_bit_eos : 1;
-} board_info_ioctl_t;
+};
-typedef struct {
+struct gpib_select_pci_ioctl {
int pci_bus;
int pci_slot;
-} select_pci_ioctl_t;
+};
-typedef struct {
- uint8_t config;
+struct gpib_ppoll_config_ioctl {
+ __u8 config;
unsigned set_ist : 1;
unsigned clear_ist : 1;
-} ppoll_config_ioctl_t;
+};
-typedef struct {
+struct gpib_pad_ioctl {
unsigned int handle;
unsigned int pad;
-} pad_ioctl_t;
+};
-typedef struct {
+struct gpib_sad_ioctl {
unsigned int handle;
int sad;
-} sad_ioctl_t;
+};
// select a piece of hardware to attach by its sysfs device path
-typedef struct {
+struct gpib_select_device_path_ioctl {
char device_path[0x1000];
-} select_device_path_ioctl_t;
-
-typedef short event_ioctl_t;
-typedef int rsc_ioctl_t;
-typedef unsigned int t1_delay_ioctl_t;
-typedef short autospoll_ioctl_t;
-typedef short local_ppoll_mode_ioctl_t;
+};
// update status byte and request service
-typedef struct {
- uint8_t status_byte;
+struct gpib_request_service2 {
+ __u8 status_byte;
int new_reason_for_service;
-} request_service2_t;
+};
/* Standard functions. */
enum gpib_ioctl {
- IBRD = _IOWR(GPIB_CODE, 100, read_write_ioctl_t),
- IBWRT = _IOWR(GPIB_CODE, 101, read_write_ioctl_t),
- IBCMD = _IOWR(GPIB_CODE, 102, read_write_ioctl_t),
- IBOPENDEV = _IOWR(GPIB_CODE, 3, open_dev_ioctl_t),
- IBCLOSEDEV = _IOW(GPIB_CODE, 4, close_dev_ioctl_t),
- IBWAIT = _IOWR(GPIB_CODE, 5, wait_ioctl_t),
- IBRPP = _IOWR(GPIB_CODE, 6, uint8_t),
+ IBRD = _IOWR(GPIB_CODE, 100, struct gpib_read_write_ioctl),
+ IBWRT = _IOWR(GPIB_CODE, 101, struct gpib_read_write_ioctl),
+ IBCMD = _IOWR(GPIB_CODE, 102, struct gpib_read_write_ioctl),
+ IBOPENDEV = _IOWR(GPIB_CODE, 3, struct gpib_open_dev_ioctl),
+ IBCLOSEDEV = _IOW(GPIB_CODE, 4, struct gpib_close_dev_ioctl),
+ IBWAIT = _IOWR(GPIB_CODE, 5, struct gpib_wait_ioctl),
+ IBRPP = _IOWR(GPIB_CODE, 6, __u8),
IBSIC = _IOW(GPIB_CODE, 9, unsigned int),
IBSRE = _IOW(GPIB_CODE, 10, int),
IBGTS = _IO(GPIB_CODE, 11),
IBCAC = _IOW(GPIB_CODE, 12, int),
IBLINES = _IOR(GPIB_CODE, 14, short),
- IBPAD = _IOW(GPIB_CODE, 15, pad_ioctl_t),
- IBSAD = _IOW(GPIB_CODE, 16, sad_ioctl_t),
+ IBPAD = _IOW(GPIB_CODE, 15, struct gpib_pad_ioctl),
+ IBSAD = _IOW(GPIB_CODE, 16, struct gpib_sad_ioctl),
IBTMO = _IOW(GPIB_CODE, 17, unsigned int),
- IBRSP = _IOWR(GPIB_CODE, 18, serial_poll_ioctl_t),
- IBEOS = _IOW(GPIB_CODE, 19, eos_ioctl_t),
- IBRSV = _IOW(GPIB_CODE, 20, uint8_t),
- CFCBASE = _IOW(GPIB_CODE, 21, uint64_t),
+ IBRSP = _IOWR(GPIB_CODE, 18, struct gpib_serial_poll_ioctl),
+ IBEOS = _IOW(GPIB_CODE, 19, struct gpib_eos_ioctl),
+ IBRSV = _IOW(GPIB_CODE, 20, __u8),
+ CFCBASE = _IOW(GPIB_CODE, 21, __u64),
CFCIRQ = _IOW(GPIB_CODE, 22, unsigned int),
CFCDMA = _IOW(GPIB_CODE, 23, unsigned int),
- CFCBOARDTYPE = _IOW(GPIB_CODE, 24, board_type_ioctl_t),
+ CFCBOARDTYPE = _IOW(GPIB_CODE, 24, struct gpib_board_type_ioctl),
IBMUTEX = _IOW(GPIB_CODE, 26, int),
- IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, spoll_bytes_ioctl_t),
- IBPPC = _IOW(GPIB_CODE, 28, ppoll_config_ioctl_t),
- IBBOARD_INFO = _IOR(GPIB_CODE, 29, board_info_ioctl_t),
+ IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, struct gpib_spoll_bytes_ioctl),
+ IBPPC = _IOW(GPIB_CODE, 28, struct gpib_ppoll_config_ioctl),
+ IBBOARD_INFO = _IOR(GPIB_CODE, 29, struct gpib_board_info_ioctl),
IBQUERY_BOARD_RSV = _IOR(GPIB_CODE, 31, int),
- IBSELECT_PCI = _IOWR(GPIB_CODE, 32, select_pci_ioctl_t),
- IBEVENT = _IOR(GPIB_CODE, 33, event_ioctl_t),
- IBRSC = _IOW(GPIB_CODE, 34, rsc_ioctl_t),
- IB_T1_DELAY = _IOW(GPIB_CODE, 35, t1_delay_ioctl_t),
+ IBSELECT_PCI = _IOWR(GPIB_CODE, 32, struct gpib_select_pci_ioctl),
+ IBEVENT = _IOR(GPIB_CODE, 33, short),
+ IBRSC = _IOW(GPIB_CODE, 34, int),
+ IB_T1_DELAY = _IOW(GPIB_CODE, 35, unsigned int),
IBLOC = _IO(GPIB_CODE, 36),
- IBAUTOSPOLL = _IOW(GPIB_CODE, 38, autospoll_ioctl_t),
- IBONL = _IOW(GPIB_CODE, 39, online_ioctl_t),
- IBPP2_SET = _IOW(GPIB_CODE, 40, local_ppoll_mode_ioctl_t),
- IBPP2_GET = _IOR(GPIB_CODE, 41, local_ppoll_mode_ioctl_t),
- IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, select_device_path_ioctl_t),
+ IBAUTOSPOLL = _IOW(GPIB_CODE, 38, short),
+ IBONL = _IOW(GPIB_CODE, 39, struct gpib_online_ioctl),
+ IBPP2_SET = _IOW(GPIB_CODE, 40, short),
+ IBPP2_GET = _IOR(GPIB_CODE, 41, short),
+ IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, struct gpib_select_device_path_ioctl),
// 44 was IBSELECT_SERIAL_NUMBER
- IBRSV2 = _IOW(GPIB_CODE, 45, request_service2_t)
+ IBRSV2 = _IOW(GPIB_CODE, 45, struct gpib_request_service2)
};
#endif /* _GPIB_IOCTL_H */
diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c
index 5d80ace41d8e..ec9fddfc0b14 100644
--- a/drivers/staging/greybus/camera.c
+++ b/drivers/staging/greybus/camera.c
@@ -1165,8 +1165,8 @@ static int gb_camera_debugfs_init(struct gb_camera *gcam)
gcam->debugfs.buffers[i].length = 0;
debugfs_create_file_aux(entry->name, entry->mask,
- gcam->debugfs.root, gcam, entry,
- &gb_camera_debugfs_ops);
+ gcam->debugfs.root, gcam, entry,
+ &gb_camera_debugfs_ops);
}
return 0;
diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c
index a47385175582..152949c23d65 100644
--- a/drivers/staging/greybus/fw-management.c
+++ b/drivers/staging/greybus/fw-management.c
@@ -123,17 +123,11 @@ static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt,
fw_info->major = le16_to_cpu(response.major);
fw_info->minor = le16_to_cpu(response.minor);
- strscpy_pad(fw_info->firmware_tag, response.firmware_tag);
-
- /*
- * The firmware-tag should be NULL terminated, otherwise throw error but
- * don't fail.
- */
- if (fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
+ ret = strscpy_pad(fw_info->firmware_tag, response.firmware_tag);
+ if (ret == -E2BIG)
dev_err(fw_mgmt->parent,
- "fw-version: firmware-tag is not NULL terminated\n");
- fw_info->firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] = '\0';
- }
+ "fw-version: truncated firmware tag: %s\n",
+ fw_info->firmware_tag);
return 0;
}
@@ -152,14 +146,12 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
}
request.load_method = load_method;
- strscpy_pad(request.firmware_tag, tag);
- /*
- * The firmware-tag should be NULL terminated, otherwise throw error and
- * fail.
- */
- if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
- dev_err(fw_mgmt->parent, "load-and-validate: firmware-tag is not NULL terminated\n");
+ ret = strscpy_pad(request.firmware_tag, tag);
+ if (ret == -E2BIG) {
+ dev_err(fw_mgmt->parent,
+ "load-and-validate: truncated firmware tag: %s\n",
+ request.firmware_tag);
return -EINVAL;
}
@@ -248,14 +240,11 @@ static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt,
struct gb_fw_mgmt_backend_fw_version_response response;
int ret;
- strscpy_pad(request.firmware_tag, fw_info->firmware_tag);
-
- /*
- * The firmware-tag should be NULL terminated, otherwise throw error and
- * fail.
- */
- if (request.firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE - 1] != '\0') {
- dev_err(fw_mgmt->parent, "backend-version: firmware-tag is not NULL terminated\n");
+ ret = strscpy_pad(request.firmware_tag, fw_info->firmware_tag);
+ if (ret == -E2BIG) {
+ dev_err(fw_mgmt->parent,
+ "backend-fw-version: truncated firmware tag: %s\n",
+ request.firmware_tag);
return -EINVAL;
}
@@ -302,13 +291,10 @@ static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
int ret;
ret = strscpy_pad(request.firmware_tag, tag);
-
- /*
- * The firmware-tag should be NULL terminated, otherwise throw error and
- * fail.
- */
if (ret == -E2BIG) {
- dev_err(fw_mgmt->parent, "backend-update: firmware-tag is not NULL terminated\n");
+ dev_err(fw_mgmt->parent,
+ "backend-fw-update: truncated firmware tag: %s\n",
+ request.firmware_tag);
return -EINVAL;
}
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index 16bcf7fc8158..f81c34160f72 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -185,8 +185,8 @@ static int gb_gpio_get_value_operation(struct gb_gpio_controller *ggc,
return 0;
}
-static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
- u8 which, bool value_high)
+static int gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
+ u8 which, bool value_high)
{
struct device *dev = &ggc->gbphy_dev->dev;
struct gb_gpio_set_value_request request;
@@ -195,7 +195,7 @@ static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
if (ggc->lines[which].direction == 1) {
dev_warn(dev, "refusing to set value of input gpio %u\n",
which);
- return;
+ return -EPERM;
}
request.which = which;
@@ -204,10 +204,12 @@ static void gb_gpio_set_value_operation(struct gb_gpio_controller *ggc,
&request, sizeof(request), NULL, 0);
if (ret) {
dev_err(dev, "failed to set value of gpio %u\n", which);
- return;
+ return ret;
}
ggc->lines[which].value = request.value;
+
+ return 0;
}
static int gb_gpio_set_debounce_operation(struct gb_gpio_controller *ggc,
@@ -457,11 +459,11 @@ static int gb_gpio_get(struct gpio_chip *chip, unsigned int offset)
return ggc->lines[which].value;
}
-static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct gb_gpio_controller *ggc = gpiochip_get_data(chip);
- gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
+ return gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
}
static int gb_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
@@ -555,7 +557,7 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
gpio->direction_input = gb_gpio_direction_input;
gpio->direction_output = gb_gpio_direction_output;
gpio->get = gb_gpio_get;
- gpio->set = gb_gpio_set;
+ gpio->set_rv = gb_gpio_set;
gpio->set_config = gb_gpio_set_config;
gpio->base = -1; /* Allocate base dynamically */
gpio->ngpio = ggc->line_max + 1;
diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c
index c1c73308800c..830ff38fda92 100644
--- a/drivers/staging/iio/accel/adis16203.c
+++ b/drivers/staging/iio/accel/adis16203.c
@@ -294,7 +294,7 @@ static int adis16203_probe(struct spi_device *spi)
static const struct of_device_id adis16203_of_match[] = {
{ .compatible = "adi,adis16203" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adis16203_of_match);
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 081b17f49863..4774df778de9 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -431,7 +431,7 @@ static const struct spi_device_id ad7816_id[] = {
{ "ad7816", ID_AD7816 },
{ "ad7817", ID_AD7817 },
{ "ad7818", ID_AD7818 },
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad7816_id);
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
index e6ad088636f6..f45968ef94ea 100644
--- a/drivers/staging/iio/addac/adt7316-i2c.c
+++ b/drivers/staging/iio/addac/adt7316-i2c.c
@@ -127,7 +127,7 @@ static const struct of_device_id adt7316_of_match[] = {
{ .compatible = "adi,adt7516" },
{ .compatible = "adi,adt7517" },
{ .compatible = "adi,adt7519" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, adt7316_of_match);
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index f4260786d50a..16f30c4f1aa0 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -1794,7 +1794,7 @@ static int adt7316_setup_irq(struct iio_dev *indio_dev)
struct adt7316_chip_info *chip = iio_priv(indio_dev);
int irq_type, ret;
- irq_type = irqd_get_trigger_type(irq_get_irq_data(chip->bus.irq));
+ irq_type = irq_get_trigger_type(chip->bus.irq);
switch (irq_type) {
case IRQF_TRIGGER_HIGH:
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index db42810c7664..49388da5a684 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -7,6 +7,8 @@
#include <asm/div64.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -16,6 +18,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
+#include <linux/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -59,17 +62,17 @@
#define AD9832_CMD_SLEEPRESCLR 0xC
#define AD9832_FREQ BIT(11)
-#define AD9832_PHASE(x) (((x) & 3) << 9)
+#define AD9832_PHASE_MASK GENMASK(10, 9)
#define AD9832_SYNC BIT(13)
#define AD9832_SELSRC BIT(12)
#define AD9832_SLEEP BIT(13)
#define AD9832_RESET BIT(12)
#define AD9832_CLR BIT(11)
-#define CMD_SHIFT 12
-#define ADD_SHIFT 8
#define AD9832_FREQ_BITS 32
#define AD9832_PHASE_BITS 12
-#define RES_MASK(bits) ((1 << (bits)) - 1)
+#define AD9832_CMD_MSK GENMASK(15, 12)
+#define AD9832_ADD_MSK GENMASK(11, 8)
+#define AD9832_DAT_MSK GENMASK(7, 0)
/**
* struct ad9832_state - driver instance specific data
@@ -127,6 +130,8 @@ static int ad9832_write_frequency(struct ad9832_state *st,
{
unsigned long clk_freq;
unsigned long regval;
+ u8 regval_bytes[4];
+ u16 freq_cmd;
clk_freq = clk_get_rate(st->mclk);
@@ -134,19 +139,15 @@ static int ad9832_write_frequency(struct ad9832_state *st,
return -EINVAL;
regval = ad9832_calc_freqreg(clk_freq, fout);
+ put_unaligned_be32(regval, regval_bytes);
- st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
- (addr << ADD_SHIFT) |
- ((regval >> 24) & 0xFF));
- st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
- ((addr - 1) << ADD_SHIFT) |
- ((regval >> 16) & 0xFF));
- st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) |
- ((addr - 2) << ADD_SHIFT) |
- ((regval >> 8) & 0xFF));
- st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) |
- ((addr - 3) << ADD_SHIFT) |
- ((regval >> 0) & 0xFF));
+ for (int i = 0; i < ARRAY_SIZE(regval_bytes); i++) {
+ freq_cmd = (i % 2 == 0) ? AD9832_CMD_FRE8BITSW : AD9832_CMD_FRE16BITSW;
+
+ st->freq_data[i] = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, freq_cmd) |
+ FIELD_PREP(AD9832_ADD_MSK, addr - i) |
+ FIELD_PREP(AD9832_DAT_MSK, regval_bytes[i]));
+ }
return spi_sync(st->spi, &st->freq_msg);
}
@@ -154,15 +155,21 @@ static int ad9832_write_frequency(struct ad9832_state *st,
static int ad9832_write_phase(struct ad9832_state *st,
unsigned long addr, unsigned long phase)
{
+ u8 phase_bytes[2];
+ u16 phase_cmd;
+
if (phase >= BIT(AD9832_PHASE_BITS))
return -EINVAL;
- st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) |
- (addr << ADD_SHIFT) |
- ((phase >> 8) & 0xFF));
- st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) |
- ((addr - 1) << ADD_SHIFT) |
- (phase & 0xFF));
+ put_unaligned_be16(phase, phase_bytes);
+
+ for (int i = 0; i < ARRAY_SIZE(phase_bytes); i++) {
+ phase_cmd = (i % 2 == 0) ? AD9832_CMD_PHA8BITSW : AD9832_CMD_PHA16BITSW;
+
+ st->phase_data[i] = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, phase_cmd) |
+ FIELD_PREP(AD9832_ADD_MSK, addr - i) |
+ FIELD_PREP(AD9832_DAT_MSK, phase_bytes[i]));
+ }
return spi_sync(st->spi, &st->phase_msg);
}
@@ -193,25 +200,23 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr,
ret = ad9832_write_phase(st, this_attr->address, val);
break;
case AD9832_PINCTRL_EN:
- if (val)
- st->ctrl_ss &= ~AD9832_SELSRC;
- else
- st->ctrl_ss |= AD9832_SELSRC;
- st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) |
- st->ctrl_ss);
+ st->ctrl_ss &= ~AD9832_SELSRC;
+ st->ctrl_ss |= FIELD_PREP(AD9832_SELSRC, val ? 0 : 1);
+
+ st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SYNCSELSRC) |
+ st->ctrl_ss);
ret = spi_sync(st->spi, &st->msg);
break;
case AD9832_FREQ_SYM:
- if (val == 1) {
- st->ctrl_fp |= AD9832_FREQ;
- } else if (val == 0) {
+ if (val == 1 || val == 0) {
st->ctrl_fp &= ~AD9832_FREQ;
+ st->ctrl_fp |= FIELD_PREP(AD9832_FREQ, val ? 1 : 0);
} else {
ret = -EINVAL;
break;
}
- st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
- st->ctrl_fp);
+ st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_FPSELECT) |
+ st->ctrl_fp);
ret = spi_sync(st->spi, &st->msg);
break;
case AD9832_PHASE_SYM:
@@ -220,22 +225,21 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr,
break;
}
- st->ctrl_fp &= ~AD9832_PHASE(3);
- st->ctrl_fp |= AD9832_PHASE(val);
+ st->ctrl_fp &= ~AD9832_PHASE_MASK;
+ st->ctrl_fp |= FIELD_PREP(AD9832_PHASE_MASK, val);
- st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) |
- st->ctrl_fp);
+ st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_FPSELECT) |
+ st->ctrl_fp);
ret = spi_sync(st->spi, &st->msg);
break;
case AD9832_OUTPUT_EN:
if (val)
- st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
- AD9832_CLR);
+ st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP | AD9832_CLR);
else
- st->ctrl_src |= AD9832_RESET;
+ st->ctrl_src |= FIELD_PREP(AD9832_RESET, 1);
- st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
- st->ctrl_src);
+ st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SLEEPRESCLR) |
+ st->ctrl_src);
ret = spi_sync(st->spi, &st->msg);
break;
default:
@@ -367,8 +371,8 @@ static int ad9832_probe(struct spi_device *spi)
spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg);
st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
- st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
- st->ctrl_src);
+ st->data = cpu_to_be16(FIELD_PREP(AD9832_CMD_MSK, AD9832_CMD_SLEEPRESCLR) |
+ st->ctrl_src);
ret = spi_sync(st->spi, &st->msg);
if (ret) {
dev_err(&spi->dev, "device init failed\n");
@@ -402,16 +406,24 @@ static int ad9832_probe(struct spi_device *spi)
return devm_iio_device_register(&spi->dev, indio_dev);
}
+static const struct of_device_id ad9832_of_match[] = {
+ { .compatible = "adi,ad9832" },
+ { .compatible = "adi,ad9835" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad9832_of_match);
+
static const struct spi_device_id ad9832_id[] = {
{"ad9832", 0},
{"ad9835", 0},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad9832_id);
static struct spi_driver ad9832_driver = {
.driver = {
.name = "ad9832",
+ .of_match_table = ad9832_of_match,
},
.probe = ad9832_probe,
.id_table = ad9832_id,
diff --git a/drivers/staging/iio/frequency/ad9832.h b/drivers/staging/iio/frequency/ad9832.h
index 98dfbd9289ab..d0d840edb8d2 100644
--- a/drivers/staging/iio/frequency/ad9832.h
+++ b/drivers/staging/iio/frequency/ad9832.h
@@ -13,7 +13,6 @@
/**
* struct ad9832_platform_data - platform specific information
- * @mclk: master clock in Hz
* @freq0: power up freq0 tuning word in Hz
* @freq1: power up freq1 tuning word in Hz
* @phase0: power up phase0 value [0..4095] correlates with 0..2PI
diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 50413da2aa65..0038eb234d40 100644
--- a/drivers/staging/iio/frequency/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -479,7 +479,7 @@ static const struct spi_device_id ad9834_id[] = {
{"ad9834", ID_AD9834},
{"ad9837", ID_AD9837},
{"ad9838", ID_AD9838},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad9834_id);
@@ -488,7 +488,7 @@ static const struct of_device_id ad9834_of_match[] = {
{.compatible = "adi,ad9834"},
{.compatible = "adi,ad9837"},
{.compatible = "adi,ad9838"},
- {}
+ { }
};
MODULE_DEVICE_TABLE(of, ad9834_of_match);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index d5544fc2fe98..85a4223295cd 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -271,11 +271,12 @@ static ssize_t ad5933_show_frequency(struct device *dev,
u8 d8[4];
} dat;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
ret = ad5933_i2c_read(st->client, this_attr->address, 3, &dat.d8[1]);
- iio_device_release_direct_mode(indio_dev);
+
+ iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
@@ -305,11 +306,12 @@ static ssize_t ad5933_store_frequency(struct device *dev,
if (val > AD5933_MAX_OUTPUT_FREQ_Hz)
return -EINVAL;
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
ret = ad5933_set_freq(st, this_attr->address, val);
- iio_device_release_direct_mode(indio_dev);
+
+ iio_device_release_direct(indio_dev);
return ret ? ret : len;
}
@@ -384,9 +386,9 @@ static ssize_t ad5933_store(struct device *dev,
return ret;
}
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
mutex_lock(&st->lock);
switch ((u32)this_attr->address) {
case AD5933_OUT_RANGE:
@@ -411,7 +413,7 @@ static ssize_t ad5933_store(struct device *dev,
ret = ad5933_cmd(st, 0);
break;
case AD5933_OUT_SETTLING_CYCLES:
- val = clamp(val, (u16)0, (u16)0x7FF);
+ val = clamp(val, (u16)0, (u16)0x7FC);
st->settling_cycles = val;
/* 2x, 4x handling, see datasheet */
@@ -438,7 +440,8 @@ static ssize_t ad5933_store(struct device *dev,
}
mutex_unlock(&st->lock);
- iio_device_release_direct_mode(indio_dev);
+
+ iio_device_release_direct(indio_dev);
return ret ? ret : len;
}
@@ -506,9 +509,9 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
- ret = iio_device_claim_direct_mode(indio_dev);
- if (ret)
- return ret;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
ret = ad5933_cmd(st, AD5933_CTRL_MEASURE_TEMP);
if (ret < 0)
goto out;
@@ -521,7 +524,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
2, (u8 *)&dat);
if (ret < 0)
goto out;
- iio_device_release_direct_mode(indio_dev);
+
+ iio_device_release_direct(indio_dev);
*val = sign_extend32(be16_to_cpu(dat), 13);
return IIO_VAL_INT;
@@ -533,7 +537,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
out:
- iio_device_release_direct_mode(indio_dev);
+ iio_device_release_direct(indio_dev);
return ret;
}
@@ -724,7 +728,7 @@ static int ad5933_probe(struct i2c_client *client)
static const struct i2c_device_id ad5933_id[] = {
{ "ad5933" },
{ "ad5934" },
- {}
+ { }
};
MODULE_DEVICE_TABLE(i2c, ad5933_id);
@@ -732,7 +736,7 @@ MODULE_DEVICE_TABLE(i2c, ad5933_id);
static const struct of_device_id ad5933_of_match[] = {
{ .compatible = "adi,ad5933" },
{ .compatible = "adi,ad5934" },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, ad5933_of_match);
diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c
index 50022bb5911e..383a6f7c06f4 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ap.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ap.c
@@ -389,7 +389,7 @@ void update_bmc_sta(struct adapter *padapter)
psta->qos_option = 0;
psta->htpriv.ht_option = false;
- psta->ieee8021x_blocked = 0;
+ psta->ieee8021x_blocked = false;
memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
diff --git a/drivers/staging/rtl8723bs/core/rtw_btcoex.c b/drivers/staging/rtl8723bs/core/rtw_btcoex.c
index d54095f50113..f4b19ef7b341 100644
--- a/drivers/staging/rtl8723bs/core/rtw_btcoex.c
+++ b/drivers/staging/rtl8723bs/core/rtw_btcoex.c
@@ -8,14 +8,14 @@
#include <rtw_btcoex.h>
#include <hal_btcoex.h>
-void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 mediaStatus)
+void rtw_btcoex_MediaStatusNotify(struct adapter *padapter, u8 media_status)
{
- if ((mediaStatus == RT_MEDIA_CONNECT)
+ if ((media_status == RT_MEDIA_CONNECT)
&& (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) {
rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL);
}
- hal_btcoex_MediaStatusNotify(padapter, mediaStatus);
+ hal_btcoex_MediaStatusNotify(padapter, media_status);
}
void rtw_btcoex_HaltNotify(struct adapter *padapter)
@@ -52,14 +52,14 @@ void rtw_btcoex_RejectApAggregatedPacket(struct adapter *padapter, u8 enable)
void rtw_btcoex_LPS_Enter(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv;
- u8 lpsVal;
+ u8 lps_val;
pwrpriv = adapter_to_pwrctl(padapter);
pwrpriv->bpower_saving = true;
- lpsVal = hal_btcoex_LpsVal(padapter);
- rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX");
+ lps_val = hal_btcoex_LpsVal(padapter);
+ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lps_val, "BTCOEX");
}
void rtw_btcoex_LPS_Leave(struct adapter *padapter)
diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c
index 1c9e8b01d9d8..437934dd255e 100644
--- a/drivers/staging/rtl8723bs/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c
@@ -273,9 +273,9 @@ struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
/* spin_lock_bh(&(queue->lock)); */
spin_lock_irqsave(&queue->lock, irqL);
- if (list_empty(&queue->queue))
+ if (list_empty(&queue->queue)) {
obj = NULL;
- else {
+ } else {
obj = container_of(get_next(&queue->queue), struct cmd_obj, list);
list_del_init(&obj->list);
}
@@ -695,7 +695,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
/* for ies is fix buf size */
t_len = sizeof(struct wlan_bssid_ex);
-
/* for hidden ap to set fw_state here */
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != true) {
switch (ndis_network_mode) {
@@ -738,7 +737,6 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork)
psecnetwork->ie_length = rtw_restruct_sec_ie(padapter, &pnetwork->network.ies[0], &psecnetwork->ies[0], pnetwork->network.ie_length);
-
pqospriv->qos_option = 0;
if (pregistrypriv->wmm_enable) {
@@ -1032,7 +1030,6 @@ u8 rtw_reset_securitypriv_cmd(struct adapter *padapter)
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
-
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
@@ -1099,7 +1096,6 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
pdrvextra_cmd_parm->pbuf = NULL;
init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
-
/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
res = rtw_enqueue_cmd(pcmdpriv, ph2c);
exit:
@@ -1256,7 +1252,6 @@ static void dynamic_chk_wk_hdl(struct adapter *padapter)
/* */
hal_btcoex_Handler(padapter);
-
/* always call rtw_ps_processor() at last one. */
rtw_ps_processor(padapter);
}
@@ -1367,7 +1362,6 @@ u8 rtw_dm_in_lps_wk_cmd(struct adapter *padapter)
struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
u8 res = _SUCCESS;
-
ph2c = rtw_zmalloc(sizeof(struct cmd_obj));
if (!ph2c) {
res = _FAIL;
@@ -1850,7 +1844,6 @@ void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
spin_lock_bh(&pmlmepriv->lock);
-
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->mac_address);
if (!psta) {
diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
index 0ed420f3d096..53d4c113b19c 100644
--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
@@ -988,11 +988,10 @@ void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr)
if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) {
addr = of_get_property(np, "local-mac-address", &len);
- if (addr && len == ETH_ALEN) {
+ if (addr && len == ETH_ALEN)
ether_addr_copy(mac_addr, addr);
- } else {
+ else
eth_random_addr(mac_addr);
- }
}
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c
index 58de0c2fdd68..1d23ea7d6f59 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c
@@ -2022,12 +2022,12 @@ signed int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, u
}
iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
- if (iEntry < 0) {
+ if (iEntry < 0)
return ielength;
- } else {
- if (authmode == WLAN_EID_RSN)
- ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
- }
+
+ if (authmode == WLAN_EID_RSN)
+ ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
+
return ielength;
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
index 3d36b6f005e0..e74fb7d5dc37 100644
--- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c
@@ -3511,7 +3511,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
/* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.mac_address)) != NULL) */
psta = rtw_get_stainfo(pstapriv, raddr);
if (psta) {
- start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1;
+ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] % 4096u) + 1;
psta->BA_starting_seqctrl[status & 0x07] = start_seq;
diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
index c60e179bb2e1..44f7c19308a5 100644
--- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
+++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c
@@ -8,7 +8,6 @@
#include <hal_data.h>
#include <linux/jiffies.h>
-
void _ips_enter(struct adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
@@ -56,9 +55,8 @@ int _ips_leave(struct adapter *padapter)
pwrpriv->ips_leave_cnts++;
result = rtw_ips_pwr_up(padapter);
- if (result == _SUCCESS) {
+ if (result == _SUCCESS)
pwrpriv->rf_pwrstate = rf_on;
- }
pwrpriv->bips_processing = false;
pwrpriv->bkeepfwalive = false;
@@ -549,9 +547,8 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter)
LPS_Leave_check(Adapter);
} else {
- if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) {
+ if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off)
ips_leave(Adapter);
- }
}
}
@@ -996,7 +993,6 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter)
pwrctrlpriv->wowlan_ap_mode = false;
}
-
void rtw_free_pwrctrl_priv(struct adapter *adapter)
{
}
diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c
index 895116e9f4e7..709a606be7c9 100644
--- a/drivers/staging/rtl8723bs/core/rtw_recv.c
+++ b/drivers/staging/rtl8723bs/core/rtw_recv.c
@@ -1641,7 +1641,7 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
struct dvobj_priv *psdpriv = padapter->dvobj;
struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
u8 wsize = preorder_ctrl->wsize_b;
- u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */
+ u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096u;
/* Rx Reorder initialize condition. */
if (preorder_ctrl->indicate_seq == 0xFFFF)
@@ -1657,7 +1657,7 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_n
/* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */
/* */
if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) {
- preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096u;
} else if (SN_LESS(wend, seq_num)) {
/* boundary situation, when seq_num cross 0xFFF */
@@ -1772,7 +1772,7 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor
list_del_init(&(prframe->u.hdr.list));
if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num))
- preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096u;
/* Set this as a lock to make sure that only one thread is indicating packet. */
/* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */
diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c
index 297c93d65315..026d58b4bd7f 100644
--- a/drivers/staging/rtl8723bs/core/rtw_xmit.c
+++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c
@@ -943,7 +943,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
if (psta) {
psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
- psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
+ psta->sta_xmitpriv.txseq_tid[pattrib->priority] %= 4096u;
pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
SetSeqNum(hdr, pattrib->seqnum);
@@ -963,11 +963,14 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr
if (SN_LESS(pattrib->seqnum, tx_seq)) {
pattrib->ampdu_en = false;/* AGG BK */
} else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] =
+ (tx_seq + 1) % 4096u;
pattrib->ampdu_en = true;/* AGG EN */
} else {
- psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] =
+ (pattrib->seqnum + 1) % 4096u;
+
pattrib->ampdu_en = true;/* AGG EN */
}
}
@@ -1936,7 +1939,6 @@ static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib
s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
{
static unsigned long start;
- static u32 drop_cnt;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_frame *pxmitframe = NULL;
@@ -1948,15 +1950,11 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
- if (jiffies_to_msecs(jiffies - start) > 2000) {
+ if (jiffies_to_msecs(jiffies - start) > 2000)
start = jiffies;
- drop_cnt = 0;
- }
- if (!pxmitframe) {
- drop_cnt++;
+ if (!pxmitframe)
return -1;
- }
res = update_attrib(padapter, *ppkt, &pxmitframe->attrib);
diff --git a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
index c1c7b5cc17a7..d32dbf94858f 100644
--- a/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
+++ b/drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
@@ -1100,7 +1100,7 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
bCommon = true;
} else {
- if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) {
+ if (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE) {
bLowPwrDisable = false;
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable);
halbtc8723b2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, false, false, 0x8);
@@ -1115,7 +1115,7 @@ static bool halbtc8723b2ant_IsCommonAction(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_SwMechanism2(pBtCoexist, false, false, false, 0x18);
bCommon = true;
- } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) {
+ } else if (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE) {
bLowPwrDisable = true;
pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable);
@@ -1605,7 +1605,7 @@ static void halbtc8723b2ant_ActionSco(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_LEGACY == wifiBw) /* for SCO quality at 11b/g mode */
+ if (wifiBw == BTC_WIFI_BW_LEGACY) /* for SCO quality at 11b/g mode */
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2);
else /* for SCO quality & wifi performance balance at 11n mode */
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 8);
@@ -1613,7 +1613,7 @@ static void halbtc8723b2ant_ActionSco(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 0); /* for voice quality */
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1660,7 +1660,7 @@ static void halbtc8723b2ant_ActionHid(struct btc_coexist *pBtCoexist)
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_LEGACY == wifiBw) /* for HID at 11b/g mode */
+ if (wifiBw == BTC_WIFI_BW_LEGACY) /* for HID at 11b/g mode */
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7);
else /* for HID quality & wifi performance balance at 11n mode */
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 9);
@@ -1674,7 +1674,7 @@ static void halbtc8723b2ant_ActionHid(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, true, 13);
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1723,7 +1723,7 @@ static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist)
/* sw mechanism */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
halbtc8723b2ant_SwMechanism1(pBtCoexist, true, false, false, false);
halbtc8723b2ant_SwMechanism2(pBtCoexist, true, false, true, 0x18);
} else {
@@ -1755,7 +1755,7 @@ static void halbtc8723b2ant_ActionA2dp(struct btc_coexist *pBtCoexist)
/* sw mechanism */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1805,7 +1805,7 @@ static void halbtc8723b2ant_ActionA2dpPanHs(struct btc_coexist *pBtCoexist)
/* sw mechanism */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1861,7 +1861,7 @@ static void halbtc8723b2ant_ActionPanEdr(struct btc_coexist *pBtCoexist)
/* sw mechanism */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1912,7 +1912,7 @@ static void halbtc8723b2ant_ActionPanHs(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, false, 1);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -1964,7 +1964,7 @@ static void halbtc8723b2ant_ActionPanEdrA2dp(struct btc_coexist *pBtCoexist)
(btRssiState == BTC_RSSI_STATE_STAY_HIGH)
) {
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 12);
- if (BTC_WIFI_BW_HT40 == wifiBw)
+ if (wifiBw == BTC_WIFI_BW_HT40)
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, true, 3);
else
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, false, false, 3);
@@ -1974,7 +1974,7 @@ static void halbtc8723b2ant_ActionPanEdrA2dp(struct btc_coexist *pBtCoexist)
}
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -2019,7 +2019,7 @@ static void halbtc8723b2ant_ActionPanEdrHid(struct btc_coexist *pBtCoexist)
(btRssiState == BTC_RSSI_STATE_HIGH) ||
(btRssiState == BTC_RSSI_STATE_STAY_HIGH)
) {
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 3);
halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11);
pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780);
@@ -2037,7 +2037,7 @@ static void halbtc8723b2ant_ActionPanEdrHid(struct btc_coexist *pBtCoexist)
}
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -2090,7 +2090,7 @@ static void halbtc8723b2ant_ActionHidA2dpPanEdr(struct btc_coexist *pBtCoexist)
(btRssiState == BTC_RSSI_STATE_HIGH) ||
(btRssiState == BTC_RSSI_STATE_STAY_HIGH)
) {
- if (BTC_WIFI_BW_HT40 == wifiBw)
+ if (wifiBw == BTC_WIFI_BW_HT40)
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2);
else
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, false, 3);
@@ -2098,7 +2098,7 @@ static void halbtc8723b2ant_ActionHidA2dpPanEdr(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 3);
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -2140,7 +2140,7 @@ static void halbtc8723b2ant_ActionHidA2dp(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6);
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_LEGACY == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_LEGACY) {
if (BTC_RSSI_HIGH(btRssiState))
halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2);
else if (BTC_RSSI_MEDIUM(btRssiState))
@@ -2173,7 +2173,7 @@ static void halbtc8723b2ant_ActionHidA2dp(struct btc_coexist *pBtCoexist)
halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, true, true, 2);
/* sw mechanism */
- if (BTC_WIFI_BW_HT40 == wifiBw) {
+ if (wifiBw == BTC_WIFI_BW_HT40) {
if (
(wifiRssiState == BTC_RSSI_STATE_HIGH) ||
(wifiRssiState == BTC_RSSI_STATE_STAY_HIGH)
@@ -2391,12 +2391,12 @@ void EXhalbtc8723b2ant_InitCoexDm(struct btc_coexist *pBtCoexist)
void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
{
- if (BTC_IPS_ENTER == type) {
+ if (type == BTC_IPS_ENTER) {
pCoexSta->bUnderIps = true;
halbtc8723b2ant_WifiOffHwCfg(pBtCoexist);
halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, true);
halbtc8723b2ant_CoexAllOff(pBtCoexist);
- } else if (BTC_IPS_LEAVE == type) {
+ } else if (type == BTC_IPS_LEAVE) {
pCoexSta->bUnderIps = false;
halbtc8723b2ant_InitHwConfig(pBtCoexist, false);
halbtc8723b2ant_InitCoexDm(pBtCoexist);
@@ -2406,24 +2406,24 @@ void EXhalbtc8723b2ant_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
void EXhalbtc8723b2ant_LpsNotify(struct btc_coexist *pBtCoexist, u8 type)
{
- if (BTC_LPS_ENABLE == type) {
+ if (type == BTC_LPS_ENABLE) {
pCoexSta->bUnderLps = true;
- } else if (BTC_LPS_DISABLE == type) {
+ } else if (type == BTC_LPS_DISABLE) {
pCoexSta->bUnderLps = false;
}
}
void EXhalbtc8723b2ant_ScanNotify(struct btc_coexist *pBtCoexist, u8 type)
{
- if (BTC_SCAN_START == type) {
- } else if (BTC_SCAN_FINISH == type) {
+ if (type == BTC_SCAN_START) {
+ } else if (type == BTC_SCAN_FINISH) {
}
}
void EXhalbtc8723b2ant_ConnectNotify(struct btc_coexist *pBtCoexist, u8 type)
{
- if (BTC_ASSOCIATE_START == type) {
- } else if (BTC_ASSOCIATE_FINISH == type) {
+ if (type == BTC_ASSOCIATE_START) {
+ } else if (type == BTC_ASSOCIATE_FINISH) {
}
}
@@ -2436,11 +2436,11 @@ void EXhalbtc8723b2ant_MediaStatusNotify(struct btc_coexist *pBtCoexist, u8 type
/* only 2.4G we need to inform bt the chnl mask */
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl);
- if ((BTC_MEDIA_CONNECT == type) && (wifiCentralChnl <= 14)) {
+ if ((type == BTC_MEDIA_CONNECT) && (wifiCentralChnl <= 14)) {
H2C_Parameter[0] = 0x1;
H2C_Parameter[1] = wifiCentralChnl;
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw);
- if (BTC_WIFI_BW_HT40 == wifiBw)
+ if (wifiBw == BTC_WIFI_BW_HT40)
H2C_Parameter[2] = 0x30;
else {
pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum);
@@ -2573,9 +2573,9 @@ void EXhalbtc8723b2ant_BtInfoNotify(
}
if (
- (BT_8723B_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) ||
- (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus)
+ (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_ACL_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_SCO_BUSY) ||
+ (pCoexDm->btStatus == BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY)
) {
bBtBusy = true;
bLimitedDig = true;
@@ -2603,8 +2603,8 @@ void EXhalbtc8723b2ant_HaltNotify(struct btc_coexist *pBtCoexist)
void EXhalbtc8723b2ant_PnpNotify(struct btc_coexist *pBtCoexist, u8 pnpState)
{
- if (BTC_WIFI_PNP_SLEEP == pnpState) {
- } else if (BTC_WIFI_PNP_WAKE_UP == pnpState) {
+ if (pnpState == BTC_WIFI_PNP_SLEEP) {
+ } else if (pnpState == BTC_WIFI_PNP_WAKE_UP) {
halbtc8723b2ant_InitHwConfig(pBtCoexist, false);
halbtc8723b2ant_InitCoexDm(pBtCoexist);
halbtc8723b2ant_QueryBtInfo(pBtCoexist);
diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
index b72cf520d576..9105594d2dde 100644
--- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c
+++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c
@@ -91,7 +91,7 @@ static void halbtcoutsrc_LeaveLowPower(struct btc_coexist *pBtCoexist)
stime = jiffies;
do {
ready = rtw_register_task_alive(padapter, BTCOEX_ALIVE);
- if (_SUCCESS == ready)
+ if (ready == _SUCCESS)
break;
utime = jiffies_to_msecs(jiffies - stime);
@@ -668,7 +668,7 @@ static void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 D
struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext;
struct adapter *Adapter = pBtCoexist->Adapter;
- if (BTC_INTF_SDIO == pBtCoexist->chipInterface)
+ if (pBtCoexist->chipInterface == BTC_INTF_SDIO)
rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data);
else
rtw_write8(Adapter, RegAddr, Data);
@@ -894,7 +894,7 @@ void EXhalbtcoutsrc_IpsNotify(struct btc_coexist *pBtCoexist, u8 type)
if (pBtCoexist->bManualControl)
return;
- if (IPS_NONE == type)
+ if (type == IPS_NONE)
ipsType = BTC_IPS_LEAVE;
else
ipsType = BTC_IPS_ENTER;
@@ -922,7 +922,7 @@ void EXhalbtcoutsrc_LpsNotify(struct btc_coexist *pBtCoexist, u8 type)
if (pBtCoexist->bManualControl)
return;
- if (PS_MODE_ACTIVE == type)
+ if (type == PS_MODE_ACTIVE)
lpsType = BTC_LPS_DISABLE;
else
lpsType = BTC_LPS_ENABLE;
@@ -1000,7 +1000,7 @@ void EXhalbtcoutsrc_MediaStatusNotify(struct btc_coexist *pBtCoexist, enum
if (pBtCoexist->bManualControl)
return;
- if (RT_MEDIA_CONNECT == mediaStatus)
+ if (mediaStatus == RT_MEDIA_CONNECT)
mStatus = BTC_MEDIA_CONNECT;
else
mStatus = BTC_MEDIA_DISCONNECT;
@@ -1026,11 +1026,11 @@ void EXhalbtcoutsrc_SpecialPacketNotify(struct btc_coexist *pBtCoexist, u8 pktTy
if (pBtCoexist->bManualControl)
return;
- if (PACKET_DHCP == pktType) {
+ if (pktType == PACKET_DHCP) {
packetType = BTC_PACKET_DHCP;
- } else if (PACKET_EAPOL == pktType) {
+ } else if (pktType == PACKET_EAPOL) {
packetType = BTC_PACKET_EAPOL;
- } else if (PACKET_ARP == pktType) {
+ } else if (pktType == PACKET_ARP) {
packetType = BTC_PACKET_ARP;
} else {
return;
@@ -1114,13 +1114,13 @@ void EXhalbtcoutsrc_Periodical(struct btc_coexist *pBtCoexist)
void EXhalbtcoutsrc_SetAntNum(u8 type, u8 antNum)
{
- if (BT_COEX_ANT_TYPE_PG == type) {
+ if (type == BT_COEX_ANT_TYPE_PG) {
GLBtCoexist.boardInfo.pgAntNum = antNum;
GLBtCoexist.boardInfo.btdmAntNum = antNum;
- } else if (BT_COEX_ANT_TYPE_ANTDIV == type) {
+ } else if (type == BT_COEX_ANT_TYPE_ANTDIV) {
GLBtCoexist.boardInfo.btdmAntNum = antNum;
/* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */
- } else if (BT_COEX_ANT_TYPE_DETECTED == type) {
+ } else if (type == BT_COEX_ANT_TYPE_DETECTED) {
GLBtCoexist.boardInfo.btdmAntNum = antNum;
/* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */
}
diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c
index 1213a91cffff..d91e2461fd7e 100644
--- a/drivers/staging/rtl8723bs/hal/hal_com.c
+++ b/drivers/staging/rtl8723bs/hal/hal_com.c
@@ -890,15 +890,14 @@ static u32 Array_kfreemap[] = {
void rtw_bb_rf_gain_offset(struct adapter *padapter)
{
u8 value = padapter->eeprompriv.EEPROMRFGainOffset;
- u32 res, i = 0;
u32 *Array = Array_kfreemap;
u32 v1 = 0, v2 = 0, target = 0;
+ u32 i = 0;
if (value & BIT4) {
if (padapter->eeprompriv.EEPROMRFGainVal != 0xff) {
- res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
- res &= 0xfff87fff;
- /* res &= 0xfff87fff; */
+ rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
+
for (i = 0; i < ARRAY_SIZE(Array_kfreemap); i += 2) {
v1 = Array[i];
v2 = Array[i+1];
@@ -909,9 +908,7 @@ void rtw_bb_rf_gain_offset(struct adapter *padapter)
}
PHY_SetRFReg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18|BIT17|BIT16|BIT15, target);
- /* res |= (padapter->eeprompriv.EEPROMRFGainVal & 0x0f)<< 15; */
- /* rtw_hal_write_rfreg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, RF_GAIN_OFFSET_MASK, res); */
- res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
+ rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff);
}
}
}
diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
index 928c58be6c9b..666a9f44012d 100644
--- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
+++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
@@ -155,9 +155,9 @@ void ODM_CfoTracking(void *pDM_VOID)
/* 4 1.6 Big jump */
if (pCfoTrack->bAdjust) {
if (CFO_ave > CFO_TH_XTAL_LOW)
- Adjust_Xtal = Adjust_Xtal+((CFO_ave-CFO_TH_XTAL_LOW)>>2);
+ Adjust_Xtal = Adjust_Xtal + ((CFO_ave - CFO_TH_XTAL_LOW) >> 2);
else if (CFO_ave < (-CFO_TH_XTAL_LOW))
- Adjust_Xtal = Adjust_Xtal+((CFO_TH_XTAL_LOW-CFO_ave)>>2);
+ Adjust_Xtal = Adjust_Xtal + ((CFO_TH_XTAL_LOW - CFO_ave) >> 2);
}
/* 4 1.7 Adjust Crystal Cap. */
diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c
index 97a51546463a..1e2946a23beb 100644
--- a/drivers/staging/rtl8723bs/hal/odm_DIG.c
+++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c
@@ -56,7 +56,7 @@ void odm_NHMBBInit(void *pDM_VOID)
{
struct dm_odm_t *pDM_Odm = (struct dm_odm_t *)pDM_VOID;
- pDM_Odm->adaptivity_flag = 0;
+ pDM_Odm->adaptivity_flag = false;
pDM_Odm->tolerance_cnt = 3;
pDM_Odm->NHMLastTxOkcnt = 0;
pDM_Odm->NHMLastRxOkcnt = 0;
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
index e15ec6452fd0..893cab0532ed 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
@@ -501,8 +501,7 @@ void Hal_GetEfuseDefinition(
switch (type) {
case TYPE_EFUSE_MAX_SECTION:
{
- u8 *pMax_section;
- pMax_section = pOut;
+ u8 *pMax_section = pOut;
if (efuseType == EFUSE_WIFI)
*pMax_section = EFUSE_MAX_SECTION_8723B;
@@ -513,8 +512,7 @@ void Hal_GetEfuseDefinition(
case TYPE_EFUSE_REAL_CONTENT_LEN:
{
- u16 *pu2Tmp;
- pu2Tmp = pOut;
+ u16 *pu2Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B;
@@ -525,8 +523,7 @@ void Hal_GetEfuseDefinition(
case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
{
- u16 *pu2Tmp;
- pu2Tmp = pOut;
+ u16 *pu2Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES);
@@ -537,8 +534,7 @@ void Hal_GetEfuseDefinition(
case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
{
- u16 *pu2Tmp;
- pu2Tmp = pOut;
+ u16 *pu2Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723B-EFUSE_OOB_PROTECT_BYTES);
@@ -549,8 +545,7 @@ void Hal_GetEfuseDefinition(
case TYPE_EFUSE_MAP_LEN:
{
- u16 *pu2Tmp;
- pu2Tmp = pOut;
+ u16 *pu2Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu2Tmp = EFUSE_MAX_MAP_LEN;
@@ -561,8 +556,7 @@ void Hal_GetEfuseDefinition(
case TYPE_EFUSE_PROTECT_BYTES_BANK:
{
- u8 *pu1Tmp;
- pu1Tmp = pOut;
+ u8 *pu1Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu1Tmp = EFUSE_OOB_PROTECT_BYTES;
@@ -573,8 +567,7 @@ void Hal_GetEfuseDefinition(
case TYPE_EFUSE_CONTENT_LEN_BANK:
{
- u16 *pu2Tmp;
- pu2Tmp = pOut;
+ u16 *pu2Tmp = pOut;
if (efuseType == EFUSE_WIFI)
*pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723B;
@@ -585,8 +578,7 @@ void Hal_GetEfuseDefinition(
default:
{
- u8 *pu1Tmp;
- pu1Tmp = pOut;
+ u8 *pu1Tmp = pOut;
*pu1Tmp = 0;
}
break;
@@ -835,9 +827,8 @@ static void hal_ReadEFuse_BT(
}
if (offset < EFUSE_BT_MAX_SECTION) {
- u16 addr;
+ u16 addr = offset * PGPKT_DATA_SIZE;
- addr = offset * PGPKT_DATA_SIZE;
for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
/* Check word enable condition in the section */
if (!(wden & (0x01<<i))) {
@@ -1196,10 +1187,9 @@ void rtl8723b_InitBeaconParameters(struct adapter *padapter)
{
struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
u16 val16;
- u8 val8;
+ u8 val8 = DIS_TSF_UDT;
- val8 = DIS_TSF_UDT;
val16 = val8 | (val8 << 8); /* port0 and port1 */
/* Enable prot0 beacon function for PSTDMA */
@@ -1496,10 +1486,7 @@ s32 rtl8723b_InitLLTTable(struct adapter *padapter)
{
unsigned long start, passing_time;
u32 val32;
- s32 ret;
-
-
- ret = _FAIL;
+ s32 ret = _FAIL;
val32 = rtw_read32(padapter, REG_AUTO_LLT);
val32 |= BIT_AUTO_INIT_LLT;
@@ -2273,9 +2260,8 @@ void rtl8723b_fill_fake_txdesc(
/* Encrypt the data frame if under security mode excepct null data. Suggested by CCW. */
/* */
if (bDataFrame) {
- u32 EncAlg;
+ u32 EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm;
- EncAlg = padapter->securitypriv.dot11PrivacyAlgrthm;
switch (EncAlg) {
case _NO_PRIVACY_:
SET_TX_DESC_SEC_TYPE_8723B(pDesc, 0x0);
@@ -2378,9 +2364,7 @@ static void hw_var_set_opmode(struct adapter *padapter, u8 variable, u8 *val)
static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val)
{
u8 idx = 0;
- u32 reg_macid;
-
- reg_macid = REG_MACID;
+ u32 reg_macid = REG_MACID;
for (idx = 0 ; idx < 6; idx++)
rtw_write8(GET_PRIMARY_ADAPTER(padapter), (reg_macid+idx), val[idx]);
@@ -2389,9 +2373,7 @@ static void hw_var_set_macaddr(struct adapter *padapter, u8 variable, u8 *val)
static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val)
{
u8 idx = 0;
- u32 reg_bssid;
-
- reg_bssid = REG_BSSID;
+ u32 reg_bssid = REG_BSSID;
for (idx = 0 ; idx < 6; idx++)
rtw_write8(padapter, (reg_bssid+idx), val[idx]);
@@ -2399,9 +2381,7 @@ static void hw_var_set_bssid(struct adapter *padapter, u8 variable, u8 *val)
static void hw_var_set_bcn_func(struct adapter *padapter, u8 variable, u8 *val)
{
- u32 bcn_ctrl_reg;
-
- bcn_ctrl_reg = REG_BCN_CTRL;
+ u32 bcn_ctrl_reg = REG_BCN_CTRL;
if (*(u8 *)val)
rtw_write8(padapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT));
@@ -2422,12 +2402,8 @@ static void hw_var_set_correct_tsf(struct adapter *padapter, u8 variable, u8 *va
{
u8 val8;
u64 tsf;
- struct mlme_ext_priv *pmlmeext;
- struct mlme_ext_info *pmlmeinfo;
-
-
- pmlmeext = &padapter->mlmeextpriv;
- pmlmeinfo = &pmlmeext->mlmext_info;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
tsf = pmlmeext->TSFValue-do_div(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024))-1024; /* us */
@@ -2543,15 +2519,12 @@ static void hw_var_set_mlme_join(struct adapter *padapter, u8 variable, u8 *val)
u8 val8;
u16 val16;
u32 val32;
- u8 RetryLimit;
- u8 type;
- struct mlme_priv *pmlmepriv;
+ u8 RetryLimit = 0x30;
+ u8 type = *(u8 *)val;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct eeprom_priv *pEEPROM;
- RetryLimit = 0x30;
- type = *(u8 *)val;
- pmlmepriv = &padapter->mlmepriv;
pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
if (type == 0) { /* prepare to join */
@@ -2850,12 +2823,11 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
case HW_VAR_ACK_PREAMBLE:
{
- u8 regTmp;
+ u8 regTmp = 0;
u8 bShortPreamble = *val;
/* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */
/* regTmp = (pHalData->nCur40MhzPrimeSC)<<5; */
- regTmp = 0;
if (bShortPreamble)
regTmp |= 0x80;
rtw_write8(padapter, REG_RRSR+2, regTmp);
@@ -3226,9 +3198,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val)
*/
u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval)
{
- u8 bResult;
-
- bResult = _SUCCESS;
+ u8 bResult = _SUCCESS;
switch (variable) {
default:
@@ -3244,9 +3214,7 @@ u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, v
*/
u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, void *pval)
{
- u8 bResult;
-
- bResult = _SUCCESS;
+ u8 bResult = _SUCCESS;
switch (variable) {
case HAL_DEF_MAX_RECVBUF_SZ:
@@ -3281,9 +3249,8 @@ u8 GetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, v
case HW_DEF_RA_INFO_DUMP:
{
u8 mac_id = *(u8 *)pval;
- u32 cmd;
+ u32 cmd = 0x40000100 | mac_id;
- cmd = 0x40000100 | mac_id;
rtw_write32(padapter, REG_HMEBOX_DBG_2_8723B, cmd);
msleep(10);
rtw_read32(padapter, 0x2F0); // info 1
diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
index 5dc1c12fe03e..842e19b53421 100644
--- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
+++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
@@ -120,13 +120,10 @@ free_xmitbuf:
*/
s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
{
- struct xmit_priv *pxmitpriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
u8 queue_empty, queue_pending;
s32 ret;
-
- pxmitpriv = &padapter->xmitpriv;
-
if (wait_for_completion_interruptible(&pxmitpriv->xmit_comp)) {
netdev_emerg(padapter->pnetdev,
"%s: down SdioXmitBufSema fail!\n", __func__);
@@ -357,12 +354,9 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
*/
static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
{
- struct xmit_priv *pxmitpriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
s32 ret;
-
- pxmitpriv = &padapter->xmitpriv;
-
if (wait_for_completion_interruptible(&pxmitpriv->SdioXmitStart)) {
netdev_emerg(padapter->pnetdev, "%s: SdioXmitStart fail!\n",
__func__);
@@ -408,13 +402,9 @@ next:
int rtl8723bs_xmit_thread(void *context)
{
- s32 ret;
- struct adapter *padapter;
- struct xmit_priv *pxmitpriv;
-
- ret = _SUCCESS;
- padapter = context;
- pxmitpriv = &padapter->xmitpriv;
+ s32 ret = _SUCCESS;
+ struct adapter *padapter = context;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
allow_signal(SIGTERM);
@@ -435,16 +425,13 @@ s32 rtl8723bs_mgnt_xmit(
)
{
s32 ret = _SUCCESS;
- struct pkt_attrib *pattrib;
- struct xmit_buf *pxmitbuf;
+ struct pkt_attrib *pattrib = &pmgntframe->attrib;
+ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
u8 txdesc_size = TXDESC_SIZE;
- pattrib = &pmgntframe->attrib;
- pxmitbuf = pmgntframe->pxmitbuf;
-
rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
@@ -557,15 +544,13 @@ s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
void rtl8723bs_free_xmit_priv(struct adapter *padapter)
{
- struct xmit_priv *pxmitpriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct xmit_buf *pxmitbuf;
- struct __queue *pqueue;
+ struct __queue *pqueue = &pxmitpriv->pending_xmitbuf_queue;
struct list_head *plist, *phead;
struct list_head tmplist;
- pxmitpriv = &padapter->xmitpriv;
- pqueue = &pxmitpriv->pending_xmitbuf_queue;
phead = get_list_head(pqueue);
INIT_LIST_HEAD(&tmplist);
diff --git a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h
index b93d74a5b9a5..48bf7f66a06e 100644
--- a/drivers/staging/rtl8723bs/include/hal_pwr_seq.h
+++ b/drivers/staging/rtl8723bs/include/hal_pwr_seq.h
@@ -209,7 +209,7 @@
#define RTL8723B_TRANS_END \
/* format */ \
/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \
- {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0},
+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0},
extern struct wlan_pwr_cfg rtl8723B_power_on_flow[RTL8723B_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723B_TRANS_END_STEPS];
diff --git a/drivers/staging/rtl8723bs/include/sta_info.h b/drivers/staging/rtl8723bs/include/sta_info.h
index b3535fed3de7..63343998266a 100644
--- a/drivers/staging/rtl8723bs/include/sta_info.h
+++ b/drivers/staging/rtl8723bs/include/sta_info.h
@@ -86,7 +86,7 @@ struct sta_info {
uint qos_option;
u8 hwaddr[ETH_ALEN];
- uint ieee8021x_blocked; /* 0: allowed, 1:blocked */
+ bool ieee8021x_blocked;
uint dot118021XPrivacy; /* aes, tkip... */
union Keytype dot11tkiptxmickey;
union Keytype dot11tkiprxmickey;
diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
index ca808ded61ac..98d3e4777210 100644
--- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c
+++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c
@@ -45,9 +45,8 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
/* free os related resource in struct recv_buf */
void rtw_os_recvbuf_resource_free(struct adapter *padapter, struct recv_buf *precvbuf)
{
- if (precvbuf->pskb) {
+ if (precvbuf->pskb)
dev_kfree_skb_any(precvbuf->pskb);
- }
}
struct sk_buff *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata)
@@ -160,21 +159,19 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
}
}
- if (bgroup) {
+ if (bgroup)
key_type |= NL80211_KEYTYPE_GROUP;
- } else {
+ else
key_type |= NL80211_KEYTYPE_PAIRWISE;
- }
cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[0], key_type, -1,
NULL, GFP_ATOMIC);
memset(&ev, 0x00, sizeof(ev));
- if (bgroup) {
+ if (bgroup)
ev.flags |= IW_MICFAILURE_GROUP;
- } else {
+ else
ev.flags |= IW_MICFAILURE_PAIRWISE;
- }
ev.src_addr.sa_family = ARPHRD_ETHER;
memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
diff --git a/drivers/staging/sm750fb/Makefile b/drivers/staging/sm750fb/Makefile
index b89aa4c12e9d..f7e227df0e54 100644
--- a/drivers/staging/sm750fb/Makefile
+++ b/drivers/staging/sm750fb/Makefile
@@ -3,5 +3,4 @@ obj-$(CONFIG_FB_SM750) += sm750fb.o
sm750fb-objs := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o \
ddk750_chip.o ddk750_power.o ddk750_mode.o \
- ddk750_display.o ddk750_swi2c.o ddk750_sii164.o \
- ddk750_dvi.o ddk750_hwi2c.o
+ ddk750_display.o ddk750_swi2c.o
diff --git a/drivers/staging/sm750fb/TODO b/drivers/staging/sm750fb/TODO
index 9dd57c566257..7ce632d040b3 100644
--- a/drivers/staging/sm750fb/TODO
+++ b/drivers/staging/sm750fb/TODO
@@ -3,9 +3,6 @@ TODO:
- use kernel coding style
- refine the code and remove unused code
- Implement hardware acceleration for imageblit if image->depth > 1
-- check on hardware effects of removal of USE_HW_I2C and USE_DVICHIP (these two
- are supposed to be sample code which is given here if someone wants to
- use those functionalities)
- must be ported to the atomic kms framework in the drm subsystem (which will
give you a basic fbdev driver for free)
diff --git a/drivers/staging/sm750fb/ddk750.h b/drivers/staging/sm750fb/ddk750.h
index 64ef4d258a91..8a32f8cf3a98 100644
--- a/drivers/staging/sm750fb/ddk750.h
+++ b/drivers/staging/sm750fb/ddk750.h
@@ -14,8 +14,5 @@
#include "ddk750_chip.h"
#include "ddk750_display.h"
#include "ddk750_power.h"
-#ifdef USE_HW_I2C
-#include "ddk750_hwi2c.h"
-#endif
#include "ddk750_swi2c.h"
#endif
diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c
index 172624ff98b0..4e390541a507 100644
--- a/drivers/staging/sm750fb/ddk750_display.c
+++ b/drivers/staging/sm750fb/ddk750_display.c
@@ -3,7 +3,6 @@
#include "ddk750_chip.h"
#include "ddk750_display.h"
#include "ddk750_power.h"
-#include "ddk750_dvi.h"
static void set_display_control(int ctrl, int disp_state)
{
diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c
deleted file mode 100644
index 8b81e8642f9e..000000000000
--- a/drivers/staging/sm750fb/ddk750_dvi.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define USE_DVICHIP
-#ifdef USE_DVICHIP
-#include "ddk750_chip.h"
-#include "ddk750_reg.h"
-#include "ddk750_dvi.h"
-#include "ddk750_sii164.h"
-
-/*
- * This global variable contains all the supported driver and its corresponding
- * function API. Please set the function pointer to NULL whenever the function
- * is not supported.
- */
-static struct dvi_ctrl_device dcft_supported_dvi_controller[] = {
-#ifdef DVI_CTRL_SII164
- {
- .init = sii164_init_chip,
- .get_vendor_id = sii164_get_vendor_id,
- .get_device_id = sii164GetDeviceID,
-#ifdef SII164_FULL_FUNCTIONS
- .reset_chip = sii164ResetChip,
- .get_chip_string = sii164GetChipString,
- .set_power = sii164SetPower,
- .enable_hot_plug_detection = sii164EnableHotPlugDetection,
- .is_connected = sii164IsConnected,
- .check_interrupt = sii164CheckInterrupt,
- .clear_interrupt = sii164ClearInterrupt,
-#endif
- },
-#endif
-};
-
-int dvi_init(unsigned char edge_select,
- unsigned char bus_select,
- unsigned char dual_edge_clk_select,
- unsigned char hsync_enable,
- unsigned char vsync_enable,
- unsigned char deskew_enable,
- unsigned char deskew_setting,
- unsigned char continuous_sync_enable,
- unsigned char pll_filter_enable,
- unsigned char pll_filter_value)
-{
- struct dvi_ctrl_device *current_dvi_ctrl;
-
- current_dvi_ctrl = dcft_supported_dvi_controller;
- if (current_dvi_ctrl->init) {
- return current_dvi_ctrl->init(edge_select,
- bus_select,
- dual_edge_clk_select,
- hsync_enable,
- vsync_enable,
- deskew_enable,
- deskew_setting,
- continuous_sync_enable,
- pll_filter_enable,
- pll_filter_value);
- }
- return -1; /* error */
-}
-
-#endif
diff --git a/drivers/staging/sm750fb/ddk750_dvi.h b/drivers/staging/sm750fb/ddk750_dvi.h
deleted file mode 100644
index c2518b73bdbd..000000000000
--- a/drivers/staging/sm750fb/ddk750_dvi.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef DDK750_DVI_H__
-#define DDK750_DVI_H__
-
-/* dvi chip stuffs structros */
-
-typedef long (*PFN_DVICTRL_INIT)(unsigned char edge_select,
- unsigned char bus_select,
- unsigned char dual_edge_clk_select,
- unsigned char hsync_enable,
- unsigned char vsync_enable,
- unsigned char deskew_enable,
- unsigned char deskew_setting,
- unsigned char continuous_sync_enable,
- unsigned char pll_filter_enable,
- unsigned char pll_filter_value);
-
-typedef void (*PFN_DVICTRL_RESETCHIP)(void);
-typedef char* (*PFN_DVICTRL_GETCHIPSTRING)(void);
-typedef unsigned short (*PFN_DVICTRL_GETVENDORID)(void);
-typedef unsigned short (*PFN_DVICTRL_GETDEVICEID)(void);
-typedef void (*PFN_DVICTRL_SETPOWER)(unsigned char power_up);
-typedef void (*PFN_DVICTRL_HOTPLUGDETECTION)(unsigned char enable_hot_plug);
-typedef unsigned char (*PFN_DVICTRL_ISCONNECTED)(void);
-typedef unsigned char (*PFN_DVICTRL_CHECKINTERRUPT)(void);
-typedef void (*PFN_DVICTRL_CLEARINTERRUPT)(void);
-
-/* Structure to hold all the function pointer to the DVI Controller. */
-struct dvi_ctrl_device {
- PFN_DVICTRL_INIT init;
- PFN_DVICTRL_RESETCHIP reset_chip;
- PFN_DVICTRL_GETCHIPSTRING get_chip_string;
- PFN_DVICTRL_GETVENDORID get_vendor_id;
- PFN_DVICTRL_GETDEVICEID get_device_id;
- PFN_DVICTRL_SETPOWER set_power;
- PFN_DVICTRL_HOTPLUGDETECTION enable_hot_plug_detection;
- PFN_DVICTRL_ISCONNECTED is_connected;
- PFN_DVICTRL_CHECKINTERRUPT check_interrupt;
- PFN_DVICTRL_CLEARINTERRUPT clear_interrupt;
-};
-
-#define DVI_CTRL_SII164
-
-/* dvi functions prototype */
-int dvi_init(unsigned char edge_select,
- unsigned char bus_select,
- unsigned char dual_edge_clk_select,
- unsigned char hsync_enable,
- unsigned char vsync_enable,
- unsigned char deskew_enable,
- unsigned char deskew_setting,
- unsigned char continuous_sync_enable,
- unsigned char pll_filter_enable,
- unsigned char pll_filter_value);
-
-#endif
-
diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c
deleted file mode 100644
index 8482689b665b..000000000000
--- a/drivers/staging/sm750fb/ddk750_hwi2c.c
+++ /dev/null
@@ -1,247 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define USE_HW_I2C
-#ifdef USE_HW_I2C
-#include "ddk750_chip.h"
-#include "ddk750_reg.h"
-#include "ddk750_hwi2c.h"
-#include "ddk750_power.h"
-
-#define MAX_HWI2C_FIFO 16
-#define HWI2C_WAIT_TIMEOUT 0xF0000
-
-int sm750_hw_i2c_init(unsigned char bus_speed_mode)
-{
- unsigned int value;
-
- /* Enable GPIO 30 & 31 as IIC clock & data */
- value = peek32(GPIO_MUX);
-
- value |= (GPIO_MUX_30 | GPIO_MUX_31);
- poke32(GPIO_MUX, value);
-
- /*
- * Enable Hardware I2C power.
- * TODO: Check if we need to enable GPIO power?
- */
- sm750_enable_i2c(1);
-
- /* Enable the I2C Controller and set the bus speed mode */
- value = peek32(I2C_CTRL) & ~(I2C_CTRL_MODE | I2C_CTRL_EN);
- if (bus_speed_mode)
- value |= I2C_CTRL_MODE;
- value |= I2C_CTRL_EN;
- poke32(I2C_CTRL, value);
-
- return 0;
-}
-
-void sm750_hw_i2c_close(void)
-{
- unsigned int value;
-
- /* Disable I2C controller */
- value = peek32(I2C_CTRL) & ~I2C_CTRL_EN;
- poke32(I2C_CTRL, value);
-
- /* Disable I2C Power */
- sm750_enable_i2c(0);
-
- /* Set GPIO 30 & 31 back as GPIO pins */
- value = peek32(GPIO_MUX);
- value &= ~GPIO_MUX_30;
- value &= ~GPIO_MUX_31;
- poke32(GPIO_MUX, value);
-}
-
-static long hw_i2c_wait_tx_done(void)
-{
- unsigned int timeout;
-
- /* Wait until the transfer is completed. */
- timeout = HWI2C_WAIT_TIMEOUT;
- while (!(peek32(I2C_STATUS) & I2C_STATUS_TX) && (timeout != 0))
- timeout--;
-
- if (timeout == 0)
- return -1;
-
- return 0;
-}
-
-/*
- * This function writes data to the i2c slave device registers.
- *
- * Parameters:
- * addr - i2c Slave device address
- * length - Total number of bytes to be written to the device
- * buf - The buffer that contains the data to be written to the
- * i2c device.
- *
- * Return Value:
- * Total number of bytes those are actually written.
- */
-static unsigned int hw_i2c_write_data(unsigned char addr,
- unsigned int length,
- unsigned char *buf)
-{
- unsigned char count, i;
- unsigned int total_bytes = 0;
-
- /* Set the Device Address */
- poke32(I2C_SLAVE_ADDRESS, addr & ~0x01);
-
- /*
- * Write data.
- * Note:
- * Only 16 byte can be accessed per i2c start instruction.
- */
- do {
- /*
- * Reset I2C by writing 0 to I2C_RESET register to
- * clear the previous status.
- */
- poke32(I2C_RESET, 0);
-
- /* Set the number of bytes to be written */
- if (length < MAX_HWI2C_FIFO)
- count = length - 1;
- else
- count = MAX_HWI2C_FIFO - 1;
- poke32(I2C_BYTE_COUNT, count);
-
- /* Move the data to the I2C data register */
- for (i = 0; i <= count; i++)
- poke32(I2C_DATA0 + i, *buf++);
-
- /* Start the I2C */
- poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL);
-
- /* Wait until the transfer is completed. */
- if (hw_i2c_wait_tx_done() != 0)
- break;
-
- /* Subtract length */
- length -= (count + 1);
-
- /* Total byte written */
- total_bytes += (count + 1);
-
- } while (length > 0);
-
- return total_bytes;
-}
-
-/*
- * This function reads data from the slave device and stores them
- * in the given buffer
- *
- * Parameters:
- * addr - i2c Slave device address
- * length - Total number of bytes to be read
- * buf - Pointer to a buffer to be filled with the data read
- * from the slave device. It has to be the same size as the
- * length to make sure that it can keep all the data read.
- *
- * Return Value:
- * Total number of actual bytes read from the slave device
- */
-static unsigned int hw_i2c_read_data(unsigned char addr,
- unsigned int length,
- unsigned char *buf)
-{
- unsigned char count, i;
- unsigned int total_bytes = 0;
-
- /* Set the Device Address */
- poke32(I2C_SLAVE_ADDRESS, addr | 0x01);
-
- /*
- * Read data and save them to the buffer.
- * Note:
- * Only 16 byte can be accessed per i2c start instruction.
- */
- do {
- /*
- * Reset I2C by writing 0 to I2C_RESET register to
- * clear all the status.
- */
- poke32(I2C_RESET, 0);
-
- /* Set the number of bytes to be read */
- if (length <= MAX_HWI2C_FIFO)
- count = length - 1;
- else
- count = MAX_HWI2C_FIFO - 1;
- poke32(I2C_BYTE_COUNT, count);
-
- /* Start the I2C */
- poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL);
-
- /* Wait until transaction done. */
- if (hw_i2c_wait_tx_done() != 0)
- break;
-
- /* Save the data to the given buffer */
- for (i = 0; i <= count; i++)
- *buf++ = peek32(I2C_DATA0 + i);
-
- /* Subtract length by 16 */
- length -= (count + 1);
-
- /* Number of bytes read. */
- total_bytes += (count + 1);
-
- } while (length > 0);
-
- return total_bytes;
-}
-
-/*
- * This function reads the slave device's register
- *
- * Parameters:
- * deviceAddress - i2c Slave device address which register
- * to be read from
- * registerIndex - Slave device's register to be read
- *
- * Return Value:
- * Register value
- */
-unsigned char sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg)
-{
- unsigned char value = 0xFF;
-
- if (hw_i2c_write_data(addr, 1, &reg) == 1)
- hw_i2c_read_data(addr, 1, &value);
-
- return value;
-}
-
-/*
- * This function writes a value to the slave device's register
- *
- * Parameters:
- * deviceAddress - i2c Slave device address which register
- * to be written
- * registerIndex - Slave device's register to be written
- * data - Data to be written to the register
- *
- * Result:
- * 0 - Success
- * -1 - Fail
- */
-int sm750_hw_i2c_write_reg(unsigned char addr,
- unsigned char reg,
- unsigned char data)
-{
- unsigned char value[2];
-
- value[0] = reg;
- value[1] = data;
- if (hw_i2c_write_data(addr, 2, value) == 2)
- return 0;
-
- return -1;
-}
-
-#endif
diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.h b/drivers/staging/sm750fb/ddk750_hwi2c.h
deleted file mode 100644
index 337c6493ca61..000000000000
--- a/drivers/staging/sm750fb/ddk750_hwi2c.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef DDK750_HWI2C_H__
-#define DDK750_HWI2C_H__
-
-/* hwi2c functions */
-int sm750_hw_i2c_init(unsigned char bus_speed_mode);
-void sm750_hw_i2c_close(void);
-
-unsigned char sm750_hw_i2c_read_reg(unsigned char addr, unsigned char reg);
-int sm750_hw_i2c_write_reg(unsigned char addr, unsigned char reg,
- unsigned char data);
-#endif
diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h
index 63c9e8b6ffb3..5cbb11986bb8 100644
--- a/drivers/staging/sm750fb/ddk750_power.h
+++ b/drivers/staging/sm750fb/ddk750_power.h
@@ -3,10 +3,10 @@
#define DDK750_POWER_H__
enum dpms {
- crtDPMS_ON = 0x0,
- crtDPMS_STANDBY = 0x1,
- crtDPMS_SUSPEND = 0x2,
- crtDPMS_OFF = 0x3,
+ CRT_DPMS_ON = 0x0,
+ CRT_DPMS_STANDBY = 0x1,
+ CRT_DPMS_SUSPEND = 0x2,
+ CRT_DPMS_OFF = 0x3,
};
#define set_DAC(off) { \
diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c
deleted file mode 100644
index 2532b60245ac..000000000000
--- a/drivers/staging/sm750fb/ddk750_sii164.c
+++ /dev/null
@@ -1,408 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define USE_DVICHIP
-#ifdef USE_DVICHIP
-
-#include "ddk750_sii164.h"
-#include "ddk750_hwi2c.h"
-
-/* I2C Address of each SII164 chip */
-#define SII164_I2C_ADDRESS 0x70
-
-/* Define this definition to use hardware i2c. */
-#define USE_HW_I2C
-
-#ifdef USE_HW_I2C
- #define i2cWriteReg sm750_hw_i2c_write_reg
- #define i2cReadReg sm750_hw_i2c_read_reg
-#else
- #define i2cWriteReg sm750_sw_i2c_write_reg
- #define i2cReadReg sm750_sw_i2c_read_reg
-#endif
-
-/* SII164 Vendor and Device ID */
-#define SII164_VENDOR_ID 0x0001
-#define SII164_DEVICE_ID 0x0006
-
-#ifdef SII164_FULL_FUNCTIONS
-/* Name of the DVI Controller chip */
-static char *gDviCtrlChipName = "Silicon Image SiI 164";
-#endif
-
-/*
- * sii164_get_vendor_id
- * This function gets the vendor ID of the DVI controller chip.
- *
- * Output:
- * Vendor ID
- */
-unsigned short sii164_get_vendor_id(void)
-{
- unsigned short vendorID;
-
- vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
- SII164_VENDOR_ID_HIGH) << 8) |
- (unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
- SII164_VENDOR_ID_LOW);
-
- return vendorID;
-}
-
-/*
- * sii164GetDeviceID
- * This function gets the device ID of the DVI controller chip.
- *
- * Output:
- * Device ID
- */
-unsigned short sii164GetDeviceID(void)
-{
- unsigned short deviceID;
-
- deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
- SII164_DEVICE_ID_HIGH) << 8) |
- (unsigned short)i2cReadReg(SII164_I2C_ADDRESS,
- SII164_DEVICE_ID_LOW);
-
- return deviceID;
-}
-
-/*
- * DVI.C will handle all SiI164 chip stuffs and try its best to make code
- * minimal and useful
- */
-
-/*
- * sii164_init_chip
- * This function initialize and detect the DVI controller chip.
- *
- * Input:
- * edge_select - Edge Select:
- * 0 = Input data is falling edge latched (falling
- * edge latched first in dual edge mode)
- * 1 = Input data is rising edge latched (rising
- * edge latched first in dual edge mode)
- * bus_select - Input Bus Select:
- * 0 = Input data bus is 12-bits wide
- * 1 = Input data bus is 24-bits wide
- * dual_edge_clk_select - Dual Edge Clock Select
- * 0 = Input data is single edge latched
- * 1 = Input data is dual edge latched
- * hsync_enable - Horizontal Sync Enable:
- * 0 = HSYNC input is transmitted as fixed LOW
- * 1 = HSYNC input is transmitted as is
- * vsync_enable - Vertical Sync Enable:
- * 0 = VSYNC input is transmitted as fixed LOW
- * 1 = VSYNC input is transmitted as is
- * deskew_enable - De-skewing Enable:
- * 0 = De-skew disabled
- * 1 = De-skew enabled
- * deskew_setting - De-skewing Setting (increment of 260psec)
- * 0 = 1 step --> minimum setup / maximum hold
- * 1 = 2 step
- * 2 = 3 step
- * 3 = 4 step
- * 4 = 5 step
- * 5 = 6 step
- * 6 = 7 step
- * 7 = 8 step --> maximum setup / minimum hold
- * continuous_sync_enable- SYNC Continuous:
- * 0 = Disable
- * 1 = Enable
- * pll_filter_enable - PLL Filter Enable
- * 0 = Disable PLL Filter
- * 1 = Enable PLL Filter
- * pll_filter_value - PLL Filter characteristics:
- * 0~7 (recommended value is 4)
- *
- * Output:
- * 0 - Success
- * -1 - Fail.
- */
-long sii164_init_chip(unsigned char edge_select,
- unsigned char bus_select,
- unsigned char dual_edge_clk_select,
- unsigned char hsync_enable,
- unsigned char vsync_enable,
- unsigned char deskew_enable,
- unsigned char deskew_setting,
- unsigned char continuous_sync_enable,
- unsigned char pll_filter_enable,
- unsigned char pll_filter_value)
-{
- unsigned char config;
-
- /* Initialize the i2c bus */
-#ifdef USE_HW_I2C
- /* Use fast mode. */
- sm750_hw_i2c_init(1);
-#else
- sm750_sw_i2c_init(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA);
-#endif
-
- /* Check if SII164 Chip exists */
- if ((sii164_get_vendor_id() == SII164_VENDOR_ID) &&
- (sii164GetDeviceID() == SII164_DEVICE_ID)) {
- /*
- * Initialize SII164 controller chip.
- */
-
- /* Select the edge */
- if (edge_select == 0)
- config = SII164_CONFIGURATION_LATCH_FALLING;
- else
- config = SII164_CONFIGURATION_LATCH_RISING;
-
- /* Select bus wide */
- if (bus_select == 0)
- config |= SII164_CONFIGURATION_BUS_12BITS;
- else
- config |= SII164_CONFIGURATION_BUS_24BITS;
-
- /* Select Dual/Single Edge Clock */
- if (dual_edge_clk_select == 0)
- config |= SII164_CONFIGURATION_CLOCK_SINGLE;
- else
- config |= SII164_CONFIGURATION_CLOCK_DUAL;
-
- /* Select HSync Enable */
- if (hsync_enable == 0)
- config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW;
- else
- config |= SII164_CONFIGURATION_HSYNC_AS_IS;
-
- /* Select VSync Enable */
- if (vsync_enable == 0)
- config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW;
- else
- config |= SII164_CONFIGURATION_VSYNC_AS_IS;
-
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
-
- /*
- * De-skew enabled with default 111b value.
- * This fixes some artifacts problem in some mode on board 2.2.
- * Somehow this fix does not affect board 2.1.
- */
- if (deskew_enable == 0)
- config = SII164_DESKEW_DISABLE;
- else
- config = SII164_DESKEW_ENABLE;
-
- switch (deskew_setting) {
- case 0:
- config |= SII164_DESKEW_1_STEP;
- break;
- case 1:
- config |= SII164_DESKEW_2_STEP;
- break;
- case 2:
- config |= SII164_DESKEW_3_STEP;
- break;
- case 3:
- config |= SII164_DESKEW_4_STEP;
- break;
- case 4:
- config |= SII164_DESKEW_5_STEP;
- break;
- case 5:
- config |= SII164_DESKEW_6_STEP;
- break;
- case 6:
- config |= SII164_DESKEW_7_STEP;
- break;
- case 7:
- config |= SII164_DESKEW_8_STEP;
- break;
- }
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config);
-
- /* Enable/Disable Continuous Sync. */
- if (continuous_sync_enable == 0)
- config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE;
- else
- config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE;
-
- /* Enable/Disable PLL Filter */
- if (pll_filter_enable == 0)
- config |= SII164_PLL_FILTER_DISABLE;
- else
- config |= SII164_PLL_FILTER_ENABLE;
-
- /* Set the PLL Filter value */
- config |= ((pll_filter_value & 0x07) << 1);
-
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config);
-
- /* Recover from Power Down and enable output. */
- config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
- config |= SII164_CONFIGURATION_POWER_NORMAL;
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
-
- return 0;
- }
-
- /* Return -1 if initialization fails. */
- return -1;
-}
-
-/* below sii164 function is not necessary */
-
-#ifdef SII164_FULL_FUNCTIONS
-
-/*
- * sii164ResetChip
- * This function resets the DVI Controller Chip.
- */
-void sii164ResetChip(void)
-{
- /* Power down */
- sii164SetPower(0);
- sii164SetPower(1);
-}
-
-/*
- * sii164GetChipString
- * This function returns a char string name of the current DVI Controller
- * chip.
- *
- * It's convenient for application need to display the chip name.
- */
-char *sii164GetChipString(void)
-{
- return gDviCtrlChipName;
-}
-
-/*
- * sii164SetPower
- * This function sets the power configuration of the DVI Controller Chip.
- *
- * Input:
- * powerUp - Flag to set the power down or up
- */
-void sii164SetPower(unsigned char powerUp)
-{
- unsigned char config;
-
- config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION);
- if (powerUp == 1) {
- /* Power up the chip */
- config &= ~SII164_CONFIGURATION_POWER_MASK;
- config |= SII164_CONFIGURATION_POWER_NORMAL;
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
- } else {
- /* Power down the chip */
- config &= ~SII164_CONFIGURATION_POWER_MASK;
- config |= SII164_CONFIGURATION_POWER_DOWN;
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config);
- }
-}
-
-/*
- * sii164SelectHotPlugDetectionMode
- * This function selects the mode of the hot plug detection.
- */
-static
-void sii164SelectHotPlugDetectionMode(enum sii164_hot_plug_mode hotPlugMode)
-{
- unsigned char detectReg;
-
- detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
- ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG;
- switch (hotPlugMode) {
- case SII164_HOTPLUG_DISABLE:
- detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH;
- break;
- case SII164_HOTPLUG_USE_MDI:
- detectReg &= ~SII164_DETECT_INTERRUPT_MASK;
- detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN;
- detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI;
- break;
- case SII164_HOTPLUG_USE_RSEN:
- detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN;
- break;
- case SII164_HOTPLUG_USE_HTPLG:
- detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG;
- break;
- }
-
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg);
-}
-
-/*
- * sii164EnableHotPlugDetection
- * This function enables the Hot Plug detection.
- *
- * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection
- */
-void sii164EnableHotPlugDetection(unsigned char enableHotPlug)
-{
- unsigned char detectReg;
-
- detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
-
- /* Depending on each DVI controller, need to enable the hot plug based
- * on each individual chip design.
- */
- if (enableHotPlug != 0)
- sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI);
- else
- sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE);
-}
-
-/*
- * sii164IsConnected
- * Check if the DVI Monitor is connected.
- *
- * Output:
- * 0 - Not Connected
- * 1 - Connected
- */
-unsigned char sii164IsConnected(void)
-{
- unsigned char hotPlugValue;
-
- hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
- SII164_DETECT_HOT_PLUG_STATUS_MASK;
- if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON)
- return 1;
- else
- return 0;
-}
-
-/*
- * sii164CheckInterrupt
- * Checks if interrupt has occurred.
- *
- * Output:
- * 0 - No interrupt
- * 1 - Interrupt occurs
- */
-unsigned char sii164CheckInterrupt(void)
-{
- unsigned char detectReg;
-
- detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) &
- SII164_DETECT_MONITOR_STATE_MASK;
- if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE)
- return 1;
- else
- return 0;
-}
-
-/*
- * sii164ClearInterrupt
- * Clear the hot plug interrupt.
- */
-void sii164ClearInterrupt(void)
-{
- unsigned char detectReg;
-
- /* Clear the MDI interrupt */
- detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT);
- i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT,
- detectReg | SII164_DETECT_MONITOR_STATE_CLEAR);
-}
-
-#endif
-
-#endif
diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h
deleted file mode 100644
index 71a7c1cb42c4..000000000000
--- a/drivers/staging/sm750fb/ddk750_sii164.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef DDK750_SII164_H__
-#define DDK750_SII164_H__
-
-#define USE_DVICHIP
-
-/* Hot Plug detection mode structure */
-enum sii164_hot_plug_mode {
- SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit
- * (always high).
- */
-
- SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */
- SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */
- SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */
-};
-
-/* Silicon Image SiI164 chip prototype */
-long sii164_init_chip(unsigned char edgeSelect,
- unsigned char busSelect,
- unsigned char dualEdgeClkSelect,
- unsigned char hsyncEnable,
- unsigned char vsyncEnable,
- unsigned char deskewEnable,
- unsigned char deskewSetting,
- unsigned char continuousSyncEnable,
- unsigned char pllFilterEnable,
- unsigned char pllFilterValue);
-
-unsigned short sii164_get_vendor_id(void);
-unsigned short sii164GetDeviceID(void);
-
-#ifdef SII164_FULL_FUNCTIONS
-void sii164ResetChip(void);
-char *sii164GetChipString(void);
-void sii164SetPower(unsigned char powerUp);
-void sii164EnableHotPlugDetection(unsigned char enableHotPlug);
-unsigned char sii164IsConnected(void);
-unsigned char sii164CheckInterrupt(void);
-void sii164ClearInterrupt(void);
-#endif
-/*
- * below register definition is used for
- * Silicon Image SiI164 DVI controller chip
- */
-/*
- * Vendor ID registers
- */
-#define SII164_VENDOR_ID_LOW 0x00
-#define SII164_VENDOR_ID_HIGH 0x01
-
-/*
- * Device ID registers
- */
-#define SII164_DEVICE_ID_LOW 0x02
-#define SII164_DEVICE_ID_HIGH 0x03
-
-/*
- * Device Revision
- */
-#define SII164_DEVICE_REVISION 0x04
-
-/*
- * Frequency Limitation registers
- */
-#define SII164_FREQUENCY_LIMIT_LOW 0x06
-#define SII164_FREQUENCY_LIMIT_HIGH 0x07
-
-/*
- * Power Down and Input Signal Configuration registers
- */
-#define SII164_CONFIGURATION 0x08
-
-/* Power down (PD) */
-#define SII164_CONFIGURATION_POWER_DOWN 0x00
-#define SII164_CONFIGURATION_POWER_NORMAL 0x01
-#define SII164_CONFIGURATION_POWER_MASK 0x01
-
-/* Input Edge Latch Select (EDGE) */
-#define SII164_CONFIGURATION_LATCH_FALLING 0x00
-#define SII164_CONFIGURATION_LATCH_RISING 0x02
-
-/* Bus Select (BSEL) */
-#define SII164_CONFIGURATION_BUS_12BITS 0x00
-#define SII164_CONFIGURATION_BUS_24BITS 0x04
-
-/* Dual Edge Clock Select (DSEL) */
-#define SII164_CONFIGURATION_CLOCK_SINGLE 0x00
-#define SII164_CONFIGURATION_CLOCK_DUAL 0x08
-
-/* Horizontal Sync Enable (HEN) */
-#define SII164_CONFIGURATION_HSYNC_FORCE_LOW 0x00
-#define SII164_CONFIGURATION_HSYNC_AS_IS 0x10
-
-/* Vertical Sync Enable (VEN) */
-#define SII164_CONFIGURATION_VSYNC_FORCE_LOW 0x00
-#define SII164_CONFIGURATION_VSYNC_AS_IS 0x20
-
-/*
- * Detection registers
- */
-#define SII164_DETECT 0x09
-
-/* Monitor Detect Interrupt (MDI) */
-#define SII164_DETECT_MONITOR_STATE_CHANGE 0x00
-#define SII164_DETECT_MONITOR_STATE_NO_CHANGE 0x01
-#define SII164_DETECT_MONITOR_STATE_CLEAR 0x01
-#define SII164_DETECT_MONITOR_STATE_MASK 0x01
-
-/* Hot Plug detect Input (HTPLG) */
-#define SII164_DETECT_HOT_PLUG_STATUS_OFF 0x00
-#define SII164_DETECT_HOT_PLUG_STATUS_ON 0x02
-#define SII164_DETECT_HOT_PLUG_STATUS_MASK 0x02
-
-/* Receiver Sense (RSEN) */
-#define SII164_DETECT_RECEIVER_SENSE_NOT_DETECTED 0x00
-#define SII164_DETECT_RECEIVER_SENSE_DETECTED 0x04
-
-/* Interrupt Generation Method (TSEL) */
-#define SII164_DETECT_INTERRUPT_BY_RSEN_PIN 0x00
-#define SII164_DETECT_INTERRUPT_BY_HTPLG_PIN 0x08
-#define SII164_DETECT_INTERRUPT_MASK 0x08
-
-/* Monitor Sense Output (MSEN) */
-#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH 0x00
-#define SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI 0x10
-#define SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN 0x20
-#define SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG 0x30
-#define SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG 0x30
-
-/*
- * Skewing registers
- */
-#define SII164_DESKEW 0x0A
-
-/* General Purpose Input (CTL[3:1]) */
-#define SII164_DESKEW_GENERAL_PURPOSE_INPUT_MASK 0x0E
-
-/* De-skewing Enable bit (DKEN) */
-#define SII164_DESKEW_DISABLE 0x00
-#define SII164_DESKEW_ENABLE 0x10
-
-/* De-skewing Setting (DK[3:1])*/
-#define SII164_DESKEW_1_STEP 0x00
-#define SII164_DESKEW_2_STEP 0x20
-#define SII164_DESKEW_3_STEP 0x40
-#define SII164_DESKEW_4_STEP 0x60
-#define SII164_DESKEW_5_STEP 0x80
-#define SII164_DESKEW_6_STEP 0xA0
-#define SII164_DESKEW_7_STEP 0xC0
-#define SII164_DESKEW_8_STEP 0xE0
-
-/*
- * User Configuration Data registers (CFG 7:0)
- */
-#define SII164_USER_CONFIGURATION 0x0B
-
-/*
- * PLL registers
- */
-#define SII164_PLL 0x0C
-
-/* PLL Filter Value (PLLF) */
-#define SII164_PLL_FILTER_VALUE_MASK 0x0E
-
-/* PLL Filter Enable (PFEN) */
-#define SII164_PLL_FILTER_DISABLE 0x00
-#define SII164_PLL_FILTER_ENABLE 0x01
-
-/* Sync Continuous (SCNT) */
-#define SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE 0x00
-#define SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE 0x80
-
-#endif
diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 04c1b32a22c5..1d929aca399c 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -120,12 +120,12 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
sm750_hw_cursor_disable(cursor);
if (fbcursor->set & FB_CUR_SETSIZE)
- sm750_hw_cursor_setSize(cursor,
+ sm750_hw_cursor_set_size(cursor,
fbcursor->image.width,
fbcursor->image.height);
if (fbcursor->set & FB_CUR_SETPOS)
- sm750_hw_cursor_setPos(cursor,
+ sm750_hw_cursor_set_pos(cursor,
fbcursor->image.dx - info->var.xoffset,
fbcursor->image.dy - info->var.yoffset);
@@ -141,14 +141,12 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5) |
((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11);
- sm750_hw_cursor_setColor(cursor, fg, bg);
+ sm750_hw_cursor_set_color(cursor, fg, bg);
}
if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
- sm750_hw_cursor_setData(cursor,
- fbcursor->rop,
- fbcursor->image.data,
- fbcursor->mask);
+ sm750_hw_cursor_set_data(cursor, fbcursor->rop, fbcursor->image.data,
+ fbcursor->mask);
}
if (fbcursor->enable)
@@ -394,9 +392,9 @@ static int lynxfb_ops_set_par(struct fb_info *info)
pr_err("bpp %d not supported\n", var->bits_per_pixel);
return ret;
}
- ret = hw_sm750_crtc_setMode(crtc, var, fix);
+ ret = hw_sm750_crtc_set_mode(crtc, var, fix);
if (!ret)
- ret = hw_sm750_output_setMode(output, var, fix);
+ ret = hw_sm750_output_set_mode(output, var, fix);
return ret;
}
@@ -514,7 +512,7 @@ static int lynxfb_ops_check_var(struct fb_var_screeninfo *var,
return -ENOMEM;
}
- return hw_sm750_crtc_checkMode(crtc, var);
+ return hw_sm750_crtc_check_mode(crtc, var);
}
static int lynxfb_ops_setcolreg(unsigned int regno,
@@ -547,7 +545,7 @@ static int lynxfb_ops_setcolreg(unsigned int regno,
red >>= 8;
green >>= 8;
blue >>= 8;
- ret = hw_sm750_setColReg(crtc, regno, red, green, blue);
+ ret = hw_sm750_set_col_reg(crtc, regno, red, green, blue);
goto exit;
}
@@ -608,10 +606,10 @@ static int sm750fb_set_drv(struct lynxfb_par *par)
crtc->ywrapstep = 0;
output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ?
- hw_sm750le_setBLANK : hw_sm750_setBLANK;
+ hw_sm750le_set_blank : hw_sm750_set_blank;
/* chip specific phase */
sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ?
- hw_sm750le_deWait : hw_sm750_deWait;
+ hw_sm750le_de_wait : hw_sm750_de_wait;
switch (sm750_dev->dataflow) {
case sm750_simul_pri:
output->paths = sm750_pnc;
diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h
index aff69661c8e6..9cf8b3d30aac 100644
--- a/drivers/staging/sm750fb/sm750.h
+++ b/drivers/staging/sm750fb/sm750.h
@@ -193,26 +193,26 @@ static inline unsigned long ps_to_hz(unsigned int psvalue)
int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev);
int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev);
-void hw_sm750_initAccel(struct sm750_dev *sm750_dev);
-int hw_sm750_deWait(void);
-int hw_sm750le_deWait(void);
+void hw_sm750_init_accel(struct sm750_dev *sm750_dev);
+int hw_sm750_de_wait(void);
+int hw_sm750le_de_wait(void);
-int hw_sm750_output_setMode(struct lynxfb_output *output,
- struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix);
+int hw_sm750_output_set_mode(struct lynxfb_output *output,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix);
-int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
- struct fb_var_screeninfo *var);
+int hw_sm750_crtc_check_mode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var);
-int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
- struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix);
+int hw_sm750_crtc_set_mode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix);
-int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index,
- ushort red, ushort green, ushort blue);
+int hw_sm750_set_col_reg(struct lynxfb_crtc *crtc, ushort index,
+ ushort red, ushort green, ushort blue);
-int hw_sm750_setBLANK(struct lynxfb_output *output, int blank);
-int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank);
+int hw_sm750_set_blank(struct lynxfb_output *output, int blank);
+int hw_sm750le_set_blank(struct lynxfb_output *output, int blank);
int hw_sm750_pan_display(struct lynxfb_crtc *crtc,
const struct fb_var_screeninfo *var,
const struct fb_info *info);
diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c
index eea4d1bd36ce..7ede144905c9 100644
--- a/drivers/staging/sm750fb/sm750_cursor.c
+++ b/drivers/staging/sm750fb/sm750_cursor.c
@@ -57,13 +57,13 @@ void sm750_hw_cursor_disable(struct lynx_cursor *cursor)
poke32(HWC_ADDRESS, 0);
}
-void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h)
+void sm750_hw_cursor_set_size(struct lynx_cursor *cursor, int w, int h)
{
cursor->w = w;
cursor->h = h;
}
-void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y)
+void sm750_hw_cursor_set_pos(struct lynx_cursor *cursor, int x, int y)
{
u32 reg;
@@ -72,7 +72,7 @@ void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y)
poke32(HWC_LOCATION, reg);
}
-void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg)
+void sm750_hw_cursor_set_color(struct lynx_cursor *cursor, u32 fg, u32 bg)
{
u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) &
HWC_COLOR_12_2_RGB565_MASK;
@@ -81,8 +81,8 @@ void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg)
poke32(HWC_COLOR_3, 0xffe0);
}
-void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop,
- const u8 *pcol, const u8 *pmsk)
+void sm750_hw_cursor_set_data(struct lynx_cursor *cursor, u16 rop,
+ const u8 *pcol, const u8 *pmsk)
{
int i, j, count, pitch, offset;
u8 color, mask, opr;
@@ -131,8 +131,8 @@ void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop,
}
}
-void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop,
- const u8 *pcol, const u8 *pmsk)
+void sm750_hw_cursor_set_data2(struct lynx_cursor *cursor, u16 rop,
+ const u8 *pcol, const u8 *pmsk)
{
int i, j, count, pitch, offset;
u8 color, mask;
diff --git a/drivers/staging/sm750fb/sm750_cursor.h b/drivers/staging/sm750fb/sm750_cursor.h
index b59643dd61ed..88fa02f6377a 100644
--- a/drivers/staging/sm750fb/sm750_cursor.h
+++ b/drivers/staging/sm750fb/sm750_cursor.h
@@ -5,11 +5,11 @@
/* hw_cursor_xxx works for voyager,718 and 750 */
void sm750_hw_cursor_enable(struct lynx_cursor *cursor);
void sm750_hw_cursor_disable(struct lynx_cursor *cursor);
-void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h);
-void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y);
-void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg);
-void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop,
- const u8 *data, const u8 *mask);
-void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop,
+void sm750_hw_cursor_set_size(struct lynx_cursor *cursor, int w, int h);
+void sm750_hw_cursor_set_pos(struct lynx_cursor *cursor, int x, int y);
+void sm750_hw_cursor_set_color(struct lynx_cursor *cursor, u32 fg, u32 bg);
+void sm750_hw_cursor_set_data(struct lynx_cursor *cursor, u16 rop,
const u8 *data, const u8 *mask);
+void sm750_hw_cursor_set_data2(struct lynx_cursor *cursor, u16 rop,
+ const u8 *data, const u8 *mask);
#endif
diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c
index 4bc89218c11c..7119b67efe11 100644
--- a/drivers/staging/sm750fb/sm750_hw.c
+++ b/drivers/staging/sm750fb/sm750_hw.c
@@ -55,9 +55,8 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
pr_err("mmio failed\n");
ret = -EFAULT;
goto exit;
- } else {
- pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
}
+ pr_info("mmio virtual addr = %p\n", sm750_dev->pvReg);
sm750_dev->accel.dprBase = sm750_dev->pvReg + DE_BASE_ADDR_TYPE1;
sm750_dev->accel.dpPortBase = sm750_dev->pvReg + DE_PORT_ADDR_TYPE1;
@@ -84,9 +83,8 @@ int hw_sm750_map(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
pr_err("Map video memory failed\n");
ret = -EFAULT;
goto exit;
- } else {
- pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
}
+ pr_info("video memory vaddr = %p\n", sm750_dev->pvMem);
exit:
return ret;
}
@@ -175,14 +173,14 @@ int hw_sm750_inithw(struct sm750_dev *sm750_dev, struct pci_dev *pdev)
/* init 2d engine */
if (!sm750_dev->accel_off)
- hw_sm750_initAccel(sm750_dev);
+ hw_sm750_init_accel(sm750_dev);
return 0;
}
-int hw_sm750_output_setMode(struct lynxfb_output *output,
- struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix)
+int hw_sm750_output_set_mode(struct lynxfb_output *output,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
{
int ret;
enum disp_output disp_set;
@@ -221,8 +219,8 @@ int hw_sm750_output_setMode(struct lynxfb_output *output,
return ret;
}
-int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
- struct fb_var_screeninfo *var)
+int hw_sm750_crtc_check_mode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var)
{
struct sm750_dev *sm750_dev;
struct lynxfb_par *par = container_of(crtc, struct lynxfb_par, crtc);
@@ -247,9 +245,9 @@ int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc,
}
/* set the controller's mode for @crtc charged with @var and @fix parameters */
-int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc,
- struct fb_var_screeninfo *var,
- struct fb_fix_screeninfo *fix)
+int hw_sm750_crtc_set_mode(struct lynxfb_crtc *crtc,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
{
int ret, fmt;
u32 reg;
@@ -372,8 +370,8 @@ exit:
return ret;
}
-int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red,
- ushort green, ushort blue)
+int hw_sm750_set_col_reg(struct lynxfb_crtc *crtc, ushort index, ushort red,
+ ushort green, ushort blue)
{
static unsigned int add[] = { PANEL_PALETTE_RAM, CRT_PALETTE_RAM };
@@ -382,7 +380,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red,
return 0;
}
-int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
+int hw_sm750le_set_blank(struct lynxfb_output *output, int blank)
{
int dpms, crtdb;
@@ -423,7 +421,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank)
return 0;
}
-int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
+int hw_sm750_set_blank(struct lynxfb_output *output, int blank)
{
unsigned int dpms, pps, crtdb;
@@ -476,7 +474,7 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank)
return 0;
}
-void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
+void hw_sm750_init_accel(struct sm750_dev *sm750_dev)
{
u32 reg;
@@ -506,7 +504,7 @@ void hw_sm750_initAccel(struct sm750_dev *sm750_dev)
sm750_dev->accel.de_init(&sm750_dev->accel);
}
-int hw_sm750le_deWait(void)
+int hw_sm750le_de_wait(void)
{
int i = 0x10000000;
unsigned int mask = DE_STATE2_DE_STATUS_BUSY | DE_STATE2_DE_FIFO_EMPTY |
@@ -523,7 +521,7 @@ int hw_sm750le_deWait(void)
return -1;
}
-int hw_sm750_deWait(void)
+int hw_sm750_de_wait(void)
{
int i = 0x10000000;
unsigned int mask = SYSTEM_CTRL_DE_STATUS_BUSY |
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
index 1c1f040122d7..7d0ddd5c8cce 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-ctl.c
@@ -71,6 +71,7 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ struct snd_ctl_elem_info info;
int val, *valp;
int changed = 0;
@@ -84,6 +85,11 @@ static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
val = ucontrol->value.integer.value[0];
+
+ snd_bcm2835_ctl_info(kcontrol, &info);
+ if (val < info.value.integer.min || val > info.value.integer.max)
+ return -EINVAL;
+
mutex_lock(&chip->audio_mutex);
if (val != *valp) {
*valp = val;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c
index 6bce45925bf1..e670226f1edf 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/controls.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c
@@ -533,17 +533,15 @@ static int ctrl_set_image_effect(struct bcm2835_mmal_dev *dev,
control = &dev->component[COMP_CAMERA]->control;
- ret = vchiq_mmal_port_parameter_set(
- dev->instance, control,
- MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
- &imagefx, sizeof(imagefx));
+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
+ &imagefx, sizeof(imagefx));
if (ret)
goto exit;
- ret = vchiq_mmal_port_parameter_set(
- dev->instance, control,
- MMAL_PARAMETER_COLOUR_EFFECT,
- &dev->colourfx, sizeof(dev->colourfx));
+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ &dev->colourfx, sizeof(dev->colourfx));
}
exit:
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index cd15e84c47f4..1db2e951b53f 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -151,6 +151,11 @@ static void tb_cfg_request_dequeue(struct tb_cfg_request *req)
struct tb_ctl *ctl = req->ctl;
mutex_lock(&ctl->request_queue_lock);
+ if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) {
+ mutex_unlock(&ctl->request_queue_lock);
+ return;
+ }
+
list_del(&req->list);
clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags);
if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags))
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 144d0232a70c..a3a7c8059eee 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -217,7 +217,7 @@ static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);
if (!ret) {
/* Notify userspace about the change */
- kobject_uevent(&tb->dev.kobj, KOBJ_CHANGE);
+ tb_domain_event(tb, NULL);
}
mutex_unlock(&tb->lock);
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index 7859bccc592d..f213d9174dc5 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -22,6 +22,7 @@
#include "ctl.h"
#include "nhi_regs.h"
#include "tb.h"
+#include "tunnel.h"
#define PCIE2CIO_CMD 0x30
#define PCIE2CIO_CMD_TIMEOUT BIT(31)
@@ -379,6 +380,27 @@ static bool icm_firmware_running(const struct tb_nhi *nhi)
return !!(val & REG_FW_STS_ICM_EN);
}
+static void icm_xdomain_activated(struct tb_xdomain *xd, bool activated)
+{
+ struct tb_port *nhi_port, *dst_port;
+ struct tb *tb = xd->tb;
+
+ nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI);
+ dst_port = tb_xdomain_downstream_port(xd);
+
+ if (activated)
+ tb_tunnel_event(tb, TB_TUNNEL_ACTIVATED, TB_TUNNEL_DMA,
+ nhi_port, dst_port);
+ else
+ tb_tunnel_event(tb, TB_TUNNEL_DEACTIVATED, TB_TUNNEL_DMA,
+ nhi_port, dst_port);
+}
+
+static void icm_dp_event(struct tb *tb)
+{
+ tb_tunnel_event(tb, TB_TUNNEL_CHANGED, TB_TUNNEL_DP, NULL, NULL);
+}
+
static bool icm_fr_is_supported(struct tb *tb)
{
return !x86_apple_machine;
@@ -584,6 +606,7 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
if (reply.hdr.flags & ICM_FLAGS_ERROR)
return -EIO;
+ icm_xdomain_activated(xd, true);
return 0;
}
@@ -603,6 +626,8 @@ static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
nhi_mailbox_cmd(tb->nhi, cmd, 1);
usleep_range(10, 50);
nhi_mailbox_cmd(tb->nhi, cmd, 2);
+
+ icm_xdomain_activated(xd, false);
return 0;
}
@@ -1151,6 +1176,7 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
if (reply.hdr.flags & ICM_FLAGS_ERROR)
return -EIO;
+ icm_xdomain_activated(xd, true);
return 0;
}
@@ -1191,7 +1217,12 @@ static int icm_tr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
return ret;
usleep_range(10, 50);
- return icm_tr_xdomain_tear_down(tb, xd, 2);
+ ret = icm_tr_xdomain_tear_down(tb, xd, 2);
+ if (ret)
+ return ret;
+
+ icm_xdomain_activated(xd, false);
+ return 0;
}
static void
@@ -1718,6 +1749,9 @@ static void icm_handle_notification(struct work_struct *work)
if (tb_is_xdomain_enabled())
icm->xdomain_disconnected(tb, n->pkg);
break;
+ case ICM_EVENT_DP_CONFIG_CHANGED:
+ icm_dp_event(tb);
+ break;
case ICM_EVENT_RTD3_VETO:
icm->rtd3_veto(tb, n->pkg);
break;
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 6a2116cbb06f..28febb95f8fa 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -3599,6 +3599,7 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime)
flags |= TB_WAKE_ON_USB4;
flags |= TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE | TB_WAKE_ON_DP;
} else if (device_may_wakeup(&sw->dev)) {
+ flags |= TB_WAKE_ON_CONNECT | TB_WAKE_ON_DISCONNECT;
flags |= TB_WAKE_ON_USB4 | TB_WAKE_ON_USB3 | TB_WAKE_ON_PCIE;
}
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 8c527af98927..c14ab1fbeeaf 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -952,6 +952,15 @@ static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw)
tb_port_dbg(up, "available bandwidth for new USB3 tunnel %d/%d Mb/s\n",
available_up, available_down);
+ /*
+ * If the available bandwidth is less than 1.5 Gb/s notify
+ * userspace that the connected isochronous device may not work
+ * properly.
+ */
+ if (available_up < 1500 || available_down < 1500)
+ tb_tunnel_event(tb, TB_TUNNEL_LOW_BANDWIDTH, TB_TUNNEL_USB3,
+ down, up);
+
tunnel = tb_tunnel_alloc_usb3(tb, up, down, available_up,
available_down);
if (!tunnel) {
@@ -2000,8 +2009,10 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in,
ret = tb_available_bandwidth(tb, in, out, &available_up, &available_down,
true);
- if (ret)
+ if (ret) {
+ tb_tunnel_event(tb, TB_TUNNEL_NO_BANDWIDTH, TB_TUNNEL_DP, in, out);
goto err_reclaim_usb;
+ }
tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n",
available_up, available_down);
@@ -2622,8 +2633,12 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
}
}
- return tb_tunnel_alloc_bandwidth(tunnel, requested_up,
- requested_down);
+ ret = tb_tunnel_alloc_bandwidth(tunnel, requested_up,
+ requested_down);
+ if (ret)
+ goto fail;
+
+ return 0;
}
/*
@@ -2699,6 +2714,7 @@ fail:
"failing the request by rewriting allocated %d/%d Mb/s\n",
allocated_up, allocated_down);
tb_tunnel_alloc_bandwidth(tunnel, &allocated_up, &allocated_down);
+ tb_tunnel_event(tb, TB_TUNNEL_NO_BANDWIDTH, TB_TUNNEL_DP, in, out);
}
return ret;
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index b54147a1ba87..87afd5a7c504 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -804,6 +804,19 @@ static inline void tb_domain_put(struct tb *tb)
put_device(&tb->dev);
}
+/**
+ * tb_domain_event() - Notify userspace about an event in domain
+ * @tb: Domain where event occurred
+ * @envp: Array of uevent environment strings (can be %NULL)
+ *
+ * This function provides a way to notify userspace about any events
+ * that take place in the domain.
+ */
+static inline void tb_domain_event(struct tb *tb, char *envp[])
+{
+ kobject_uevent_env(&tb->dev.kobj, KOBJ_CHANGE, envp);
+}
+
struct tb_nvm *tb_nvm_alloc(struct device *dev);
int tb_nvm_read_version(struct tb_nvm *nvm);
int tb_nvm_validate(struct tb_nvm *nvm);
@@ -1468,6 +1481,7 @@ static inline struct usb4_port *tb_to_usb4_port_device(struct device *dev)
struct usb4_port *usb4_port_device_add(struct tb_port *port);
void usb4_port_device_remove(struct usb4_port *usb4);
int usb4_port_device_resume(struct usb4_port *usb4);
+int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port);
static inline bool usb4_port_device_is_offline(const struct usb4_port *usb4)
{
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
index a1670a96cbdc..144f7332d5d2 100644
--- a/drivers/thunderbolt/tb_msgs.h
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -118,6 +118,7 @@ enum icm_event_code {
ICM_EVENT_DEVICE_DISCONNECTED = 0x4,
ICM_EVENT_XDOMAIN_CONNECTED = 0x6,
ICM_EVENT_XDOMAIN_DISCONNECTED = 0x7,
+ ICM_EVENT_DP_CONFIG_CHANGED = 0x8,
ICM_EVENT_RTD3_VETO = 0xa,
};
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 76254ed3f47f..d52efe3f658c 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -100,6 +100,14 @@ MODULE_PARM_DESC(bw_alloc_mode,
static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" };
+static const char * const tb_event_names[] = {
+ [TB_TUNNEL_ACTIVATED] = "activated",
+ [TB_TUNNEL_CHANGED] = "changed",
+ [TB_TUNNEL_DEACTIVATED] = "deactivated",
+ [TB_TUNNEL_LOW_BANDWIDTH] = "low bandwidth",
+ [TB_TUNNEL_NO_BANDWIDTH] = "insufficient bandwidth",
+};
+
/* Synchronizes kref_get()/put() of struct tb_tunnel */
static DEFINE_MUTEX(tb_tunnel_lock);
@@ -220,6 +228,72 @@ void tb_tunnel_put(struct tb_tunnel *tunnel)
mutex_unlock(&tb_tunnel_lock);
}
+/**
+ * tb_tunnel_event() - Notify userspace about tunneling event
+ * @tb: Domain where the event occurred
+ * @event: Event that happened
+ * @type: Type of the tunnel in question
+ * @src_port: Tunnel source port (can be %NULL)
+ * @dst_port: Tunnel destination port (can be %NULL)
+ *
+ * Notifies userspace about tunneling @event in the domain. The tunnel
+ * does not need to exist (e.g the tunnel was not activated because
+ * there is not enough bandwidth). If the @src_port and @dst_port are
+ * given fill in full %TUNNEL_DETAILS environment variable. Otherwise
+ * uses the shorter one (just the tunnel type).
+ */
+void tb_tunnel_event(struct tb *tb, enum tb_tunnel_event event,
+ enum tb_tunnel_type type,
+ const struct tb_port *src_port,
+ const struct tb_port *dst_port)
+{
+ char *envp[3] = { NULL };
+
+ if (WARN_ON_ONCE(event >= ARRAY_SIZE(tb_event_names)))
+ return;
+ if (WARN_ON_ONCE(type >= ARRAY_SIZE(tb_tunnel_names)))
+ return;
+
+ envp[0] = kasprintf(GFP_KERNEL, "TUNNEL_EVENT=%s", tb_event_names[event]);
+ if (!envp[0])
+ return;
+
+ if (src_port != NULL && dst_port != NULL) {
+ envp[1] = kasprintf(GFP_KERNEL, "TUNNEL_DETAILS=%llx:%u <-> %llx:%u (%s)",
+ tb_route(src_port->sw), src_port->port,
+ tb_route(dst_port->sw), dst_port->port,
+ tb_tunnel_names[type]);
+ } else {
+ envp[1] = kasprintf(GFP_KERNEL, "TUNNEL_DETAILS=(%s)",
+ tb_tunnel_names[type]);
+ }
+
+ if (envp[1])
+ tb_domain_event(tb, envp);
+
+ kfree(envp[1]);
+ kfree(envp[0]);
+}
+
+static inline void tb_tunnel_set_active(struct tb_tunnel *tunnel, bool active)
+{
+ if (active) {
+ tunnel->state = TB_TUNNEL_ACTIVE;
+ tb_tunnel_event(tunnel->tb, TB_TUNNEL_ACTIVATED, tunnel->type,
+ tunnel->src_port, tunnel->dst_port);
+ } else {
+ tunnel->state = TB_TUNNEL_INACTIVE;
+ tb_tunnel_event(tunnel->tb, TB_TUNNEL_DEACTIVATED, tunnel->type,
+ tunnel->src_port, tunnel->dst_port);
+ }
+}
+
+static inline void tb_tunnel_changed(struct tb_tunnel *tunnel)
+{
+ tb_tunnel_event(tunnel->tb, TB_TUNNEL_CHANGED, tunnel->type,
+ tunnel->src_port, tunnel->dst_port);
+}
+
static int tb_pci_set_ext_encapsulation(struct tb_tunnel *tunnel, bool enable)
{
struct tb_port *port = tb_upstream_port(tunnel->dst_port->sw);
@@ -992,7 +1066,7 @@ static void tb_dp_dprx_work(struct work_struct *work)
return;
}
} else {
- tunnel->state = TB_TUNNEL_ACTIVE;
+ tb_tunnel_set_active(tunnel, true);
}
mutex_unlock(&tb->lock);
}
@@ -2326,7 +2400,7 @@ int tb_tunnel_activate(struct tb_tunnel *tunnel)
}
}
- tunnel->state = TB_TUNNEL_ACTIVE;
+ tb_tunnel_set_active(tunnel, true);
return 0;
err:
@@ -2356,7 +2430,7 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel)
if (tunnel->post_deactivate)
tunnel->post_deactivate(tunnel);
- tunnel->state = TB_TUNNEL_INACTIVE;
+ tb_tunnel_set_active(tunnel, false);
}
/**
@@ -2449,8 +2523,16 @@ int tb_tunnel_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
if (!tb_tunnel_is_active(tunnel))
return -ENOTCONN;
- if (tunnel->alloc_bandwidth)
- return tunnel->alloc_bandwidth(tunnel, alloc_up, alloc_down);
+ if (tunnel->alloc_bandwidth) {
+ int ret;
+
+ ret = tunnel->alloc_bandwidth(tunnel, alloc_up, alloc_down);
+ if (ret)
+ return ret;
+
+ tb_tunnel_changed(tunnel);
+ return 0;
+ }
return -EOPNOTSUPP;
}
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index 8a0a0cb21a89..5e9fb73d5220 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -194,6 +194,29 @@ static inline bool tb_tunnel_direction_downstream(const struct tb_tunnel *tunnel
tunnel->dst_port);
}
+/**
+ * enum tb_tunnel_event - Tunnel related events
+ * @TB_TUNNEL_ACTIVATED: A tunnel was activated
+ * @TB_TUNNEL_CHANGED: There is a tunneling change in the domain. Includes
+ * full %TUNNEL_DETAILS if the tunnel in question is known
+ * (ICM does not provide that information).
+ * @TB_TUNNEL_DEACTIVATED: A tunnel was torn down
+ * @TB_TUNNEL_LOW_BANDWIDTH: Tunnel bandwidth is not optimal
+ * @TB_TUNNEL_NO_BANDWIDTH: There is not enough bandwidth for a tunnel
+ */
+enum tb_tunnel_event {
+ TB_TUNNEL_ACTIVATED,
+ TB_TUNNEL_CHANGED,
+ TB_TUNNEL_DEACTIVATED,
+ TB_TUNNEL_LOW_BANDWIDTH,
+ TB_TUNNEL_NO_BANDWIDTH,
+};
+
+void tb_tunnel_event(struct tb *tb, enum tb_tunnel_event event,
+ enum tb_tunnel_type type,
+ const struct tb_port *src_port,
+ const struct tb_port *dst_port);
+
const char *tb_tunnel_type_name(const struct tb_tunnel *tunnel);
#define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index e51d01671d8e..fce3c0f2354a 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -440,10 +440,10 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
bool configured = val & PORT_CS_19_PC;
usb4 = port->usb4;
- if (((flags & TB_WAKE_ON_CONNECT) |
+ if (((flags & TB_WAKE_ON_CONNECT) &&
device_may_wakeup(&usb4->dev)) && !configured)
val |= PORT_CS_19_WOC;
- if (((flags & TB_WAKE_ON_DISCONNECT) |
+ if (((flags & TB_WAKE_ON_DISCONNECT) &&
device_may_wakeup(&usb4->dev)) && configured)
val |= PORT_CS_19_WOD;
if ((flags & TB_WAKE_ON_USB4) && configured)
@@ -935,7 +935,15 @@ int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in)
return status ? -EIO : 0;
}
-static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port)
+/**
+ * usb4_port_index() - Finds matching USB4 port index
+ * @sw: USB4 router
+ * @port: USB4 protocol or lane adapter
+ *
+ * Finds matching USB4 port index (starting from %0) that given @port goes
+ * through.
+ */
+int usb4_port_index(const struct tb_switch *sw, const struct tb_port *port)
{
struct tb_port *p;
int usb4_idx = 0;
@@ -969,7 +977,7 @@ static int usb4_port_idx(const struct tb_switch *sw, const struct tb_port *port)
struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
const struct tb_port *port)
{
- int usb4_idx = usb4_port_idx(sw, port);
+ int usb4_idx = usb4_port_index(sw, port);
struct tb_port *p;
int pcie_idx = 0;
@@ -1000,7 +1008,7 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw,
const struct tb_port *port)
{
- int usb4_idx = usb4_port_idx(sw, port);
+ int usb4_idx = usb4_port_index(sw, port);
struct tb_port *p;
int usb_idx = 0;
diff --git a/drivers/thunderbolt/usb4_port.c b/drivers/thunderbolt/usb4_port.c
index 5150879888ca..852a45fcd19d 100644
--- a/drivers/thunderbolt/usb4_port.c
+++ b/drivers/thunderbolt/usb4_port.c
@@ -105,6 +105,49 @@ static void usb4_port_online(struct usb4_port *usb4)
tb_acpi_power_off_retimers(port);
}
+/**
+ * usb4_usb3_port_match() - Matches USB4 port device with USB 3.x port device
+ * @usb4_port_dev: USB4 port device
+ * @usb3_port_fwnode: USB 3.x port firmware node
+ *
+ * Checks if USB 3.x port @usb3_port_fwnode is tunneled through USB4 port @usb4_port_dev.
+ * Returns true if match is found, false otherwise.
+ *
+ * Function is designed to be used with component framework (component_match_add).
+ */
+bool usb4_usb3_port_match(struct device *usb4_port_dev,
+ const struct fwnode_handle *usb3_port_fwnode)
+{
+ struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = NULL;
+ struct usb4_port *usb4;
+ struct tb_switch *sw;
+ struct tb_nhi *nhi;
+ u8 usb4_port_num;
+ struct tb *tb;
+
+ usb4 = tb_to_usb4_port_device(usb4_port_dev);
+ if (!usb4)
+ return false;
+
+ sw = usb4->port->sw;
+ tb = sw->tb;
+ nhi = tb->nhi;
+
+ nhi_fwnode = fwnode_find_reference(usb3_port_fwnode, "usb4-host-interface", 0);
+ if (IS_ERR(nhi_fwnode))
+ return false;
+
+ /* Check if USB3 fwnode references same NHI where USB4 port resides */
+ if (!device_match_fwnode(&nhi->pdev->dev, nhi_fwnode))
+ return false;
+
+ if (fwnode_property_read_u8(usb3_port_fwnode, "usb4-port-number", &usb4_port_num))
+ return false;
+
+ return usb4_port_index(sw, usb4->port) == usb4_port_num;
+}
+EXPORT_SYMBOL_GPL(usb4_usb3_port_match);
+
static ssize_t offline_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -276,12 +319,10 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
return ERR_PTR(ret);
}
- if (dev_fwnode(&usb4->dev)) {
- ret = component_add(&usb4->dev, &connector_ops);
- if (ret) {
- dev_err(&usb4->dev, "failed to add component\n");
- device_unregister(&usb4->dev);
- }
+ ret = component_add(&usb4->dev, &connector_ops);
+ if (ret) {
+ dev_err(&usb4->dev, "failed to add component\n");
+ device_unregister(&usb4->dev);
}
if (!tb_is_upstream_port(port))
@@ -306,8 +347,7 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
*/
void usb4_port_device_remove(struct usb4_port *usb4)
{
- if (dev_fwnode(&usb4->dev))
- component_del(&usb4->dev, &connector_ops);
+ component_del(&usb4->dev, &connector_ops);
device_unregister(&usb4->dev);
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 4d45eca4929a..2fc13cc02cc5 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1812,7 +1812,7 @@ static int mxser_probe(struct pci_dev *pdev,
/* io address */
ioaddress = pci_resource_start(pdev, 2);
- retval = pci_request_region(pdev, 2, "mxser(IO)");
+ retval = pcim_request_region(pdev, 2, "mxser(IO)");
if (retval)
goto err_zero;
@@ -1822,7 +1822,7 @@ static int mxser_probe(struct pci_dev *pdev,
/* vector */
ioaddress = pci_resource_start(pdev, 3);
- retval = pci_request_region(pdev, 3, "mxser(vector)");
+ retval = pcim_request_region(pdev, 3, "mxser(vector)");
if (retval)
goto err_zero;
brd->vector = ioaddress;
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index eb2a2e58fe78..0213381fa358 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -118,12 +118,11 @@ int serdev_device_add(struct serdev_device *serdev)
err = device_add(&serdev->dev);
if (err < 0) {
- dev_err(&serdev->dev, "Can't add %s, status %pe\n",
- dev_name(&serdev->dev), ERR_PTR(err));
+ dev_err(&serdev->dev, "Failed to add serdev: %d\n", err);
goto err_clear_serdev;
}
- dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev));
+ dev_dbg(&serdev->dev, "serdev registered successfully\n");
return 0;
@@ -783,8 +782,7 @@ int serdev_controller_add(struct serdev_controller *ctrl)
goto err_rpm_disable;
}
- dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n",
- ctrl->nr, &ctrl->dev);
+ dev_dbg(&ctrl->dev, "serdev controller registered: dev:%p\n", &ctrl->dev);
return 0;
err_rpm_disable:
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index b861585ca02a..18530c31a598 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -223,12 +223,6 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line);
-void serial8250_rpm_get(struct uart_8250_port *p);
-void serial8250_rpm_put(struct uart_8250_port *p);
-
-void serial8250_rpm_get_tx(struct uart_8250_port *p);
-void serial8250_rpm_put_tx(struct uart_8250_port *p);
-
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier);
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 5a56f853cf6d..68994a964321 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -461,7 +461,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
char *options)
{
char match[] = "uart"; /* 8250-specific earlycon name */
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 842422921765..dc0371857ecb 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -77,6 +77,8 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
outb(value, port->iobase + offset);
break;
#endif
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
index b10a42d2ad63..b0e44fb00b3a 100644
--- a/drivers/tty/serial/8250/8250_ni.c
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -10,14 +10,18 @@
* Copyright 2012-2023 National Instruments Corporation
*/
-#include <linux/acpi.h>
#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/init.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/property.h>
-#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
#include "8250.h"
@@ -90,10 +94,10 @@ static int ni16550_disable_transceivers(struct uart_port *port)
{
u8 pcr;
- pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
- port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
return 0;
}
@@ -105,7 +109,7 @@ static int ni16550_rs485_config(struct uart_port *port,
struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
u8 pcr;
- pcr = serial_in(up, NI16550_PCR_OFFSET);
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
if ((rs485->flags & SER_RS485_MODE_RS422) ||
@@ -120,7 +124,7 @@ static int ni16550_rs485_config(struct uart_port *port,
}
dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
- serial_out(up, NI16550_PCR_OFFSET, pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
serial_icr_write(up, UART_ACR, up->acr);
return 0;
@@ -224,31 +228,26 @@ static int ni16550_get_regs(struct platform_device *pdev,
{
struct resource *regs;
- regs = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (regs) {
+ regs = platform_get_mem_or_io(pdev, 0);
+ if (!regs)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n");
+
+ switch (resource_type(regs)) {
+ case IORESOURCE_IO:
port->iotype = UPIO_PORT;
port->iobase = regs->start;
return 0;
- }
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (regs) {
+ case IORESOURCE_MEM:
port->iotype = UPIO_MEM;
port->mapbase = regs->start;
port->mapsize = resource_size(regs);
port->flags |= UPF_IOREMAP;
- port->membase = devm_ioremap(&pdev->dev, port->mapbase,
- port->mapsize);
- if (!port->membase)
- return -ENOMEM;
-
return 0;
+ default:
+ return -EINVAL;
}
-
- dev_err(&pdev->dev, "no registers defined\n");
- return -EINVAL;
}
/*
@@ -280,12 +279,11 @@ static int ni16550_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct uart_8250_port uart = {};
unsigned int txfifosz, rxfifosz;
- unsigned int prescaler = 0;
+ unsigned int prescaler;
struct ni16550_data *data;
const char *portmode;
bool rs232_property;
int ret;
- int irq;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -293,10 +291,6 @@ static int ni16550_probe(struct platform_device *pdev)
spin_lock_init(&uart.port.lock);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
ret = ni16550_get_regs(pdev, &uart.port);
if (ret < 0)
return ret;
@@ -307,10 +301,7 @@ static int ni16550_probe(struct platform_device *pdev)
info = device_get_match_data(dev);
uart.port.dev = dev;
- uart.port.irq = irq;
- uart.port.irqflags = IRQF_SHARED;
- uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
- | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.startup = ni16550_port_startup;
uart.port.shutdown = ni16550_port_shutdown;
@@ -332,28 +323,26 @@ static int ni16550_probe(struct platform_device *pdev)
/*
* Declaration of the base clock frequency can come from one of:
* - static declaration in this driver (for older ACPI IDs)
- * - a "clock-frquency" ACPI
+ * - a "clock-frequency" ACPI
*/
- if (info->uartclk)
- uart.port.uartclk = info->uartclk;
- if (device_property_read_u32(dev, "clock-frequency",
- &uart.port.uartclk)) {
+ uart.port.uartclk = info->uartclk;
+
+ ret = uart_read_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ if (!uart.port.uartclk) {
data->clk = devm_clk_get_enabled(dev, NULL);
if (!IS_ERR(data->clk))
uart.port.uartclk = clk_get_rate(data->clk);
}
- if (!uart.port.uartclk) {
- dev_err(dev, "unable to determine clock frequency!\n");
- ret = -ENODEV;
- goto err;
- }
+ if (!uart.port.uartclk)
+ return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n");
- if (info->prescaler)
- prescaler = info->prescaler;
+ prescaler = info->prescaler;
device_property_read_u32(dev, "clock-prescaler", &prescaler);
-
- if (prescaler != 0) {
+ if (prescaler) {
uart.port.set_mctrl = ni16550_set_mctrl;
ni16550_config_prescaler(&uart, (u8)prescaler);
}
@@ -393,14 +382,11 @@ static int ni16550_probe(struct platform_device *pdev)
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
- goto err;
+ return ret;
data->line = ret;
platform_set_drvdata(pdev, data);
return 0;
-
-err:
- return ret;
}
static void ni16550_remove(struct platform_device *pdev)
@@ -410,7 +396,6 @@ static void ni16550_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line);
}
-#ifdef CONFIG_ACPI
/* NI 16550 RS-485 Interface */
static const struct ni16550_device_info nic7750 = {
.uartclk = 33333333,
@@ -435,20 +420,20 @@ static const struct ni16550_device_info nic7a69 = {
.uartclk = 29629629,
.prescaler = 0x09,
};
+
static const struct acpi_device_id ni16550_acpi_match[] = {
{ "NIC7750", (kernel_ulong_t)&nic7750 },
{ "NIC7772", (kernel_ulong_t)&nic7772 },
{ "NIC792B", (kernel_ulong_t)&nic792b },
{ "NIC7A69", (kernel_ulong_t)&nic7a69 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
-#endif
static struct platform_driver ni16550_driver = {
.driver = {
.name = "ni16550",
- .acpi_match_table = ACPI_PTR(ni16550_acpi_match),
+ .acpi_match_table = ni16550_acpi_match,
},
.probe = ni16550_probe,
.remove = ni16550_remove,
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 11c860ea80f6..d178b6c54ea1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -24,6 +24,7 @@
struct of_serial_info {
struct clk *clk;
+ struct clk *bus_clk;
struct reset_control *rst;
int type;
int line;
@@ -123,12 +124,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
- info->clk = devm_clk_get_enabled(dev, NULL);
+ struct clk *bus_clk;
+
+ bus_clk = devm_clk_get_optional_enabled(dev, "bus");
+ if (IS_ERR(bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");
+ goto err_pmruntime;
+ }
+
+ /* If the bus clock is required, core clock must be named */
+ info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
+ info->bus_clk = bus_clk;
port->uartclk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -290,6 +301,7 @@ static int of_serial_suspend(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
clk_disable_unprepare(info->clk);
+ clk_disable_unprepare(info->bus_clk);
}
return 0;
}
@@ -302,6 +314,7 @@ static int of_serial_resume(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_get_sync(dev);
+ clk_prepare_enable(info->bus_clk);
clk_prepare_enable(info->clk);
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 2a0ce11f405d..72ae08d6204f 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1173,16 +1173,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return 0;
}
- sg_init_table(&sg, 1);
- ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
- if (ret != 1) {
- serial8250_clear_THRI(p);
- return 0;
- }
-
- dma->tx_size = sg_dma_len(&sg);
-
if (priv->habit & OMAP_DMA_TX_KICK) {
unsigned char c;
u8 tx_lvl;
@@ -1207,18 +1197,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EBUSY;
goto err;
}
- if (dma->tx_size < 4) {
+ if (kfifo_len(&tport->xmit_fifo) < 4) {
ret = -EINVAL;
goto err;
}
- if (!kfifo_get(&tport->xmit_fifo, &c)) {
+ if (!uart_fifo_out(&p->port, &c, 1)) {
ret = -EINVAL;
goto err;
}
skip_byte = c;
- /* now we need to recompute due to kfifo_get */
- kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
+ }
+
+ sg_init_table(&sg, 1);
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto err;
}
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
@@ -1228,6 +1222,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
goto err;
}
+ dma->tx_size = sg_dma_len(&sg);
dma->tx_running = 1;
desc->callback = omap_8250_dma_tx_complete;
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index e9c51d4e447d..4c149db84692 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -115,6 +115,7 @@
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
+#define UART_RESET_HOT_RESET_DISABLE BIT(17)
#define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
@@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data |= UART_RESET_HOT_RESET_DISABLE;
+
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup)
@@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data &= ~UART_RESET_HOT_RESET_DISABLE;
+
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+
iounmap(p);
for (i = 0; i < priv->nr; i++) {
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8ac452cea36c..6d7b8c4667c9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -517,22 +517,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-void serial8250_rpm_get(struct uart_8250_port *p)
+static void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-void serial8250_rpm_put(struct uart_8250_port *p)
+static void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -647,7 +645,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again.
*/
-void serial8250_rpm_get_tx(struct uart_8250_port *p)
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -659,9 +657,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p)
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
-void serial8250_rpm_put_tx(struct uart_8250_port *p)
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -674,7 +671,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/*
* IER sleep support. UARTs which have EFRs need the "extended
@@ -2993,6 +2989,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
if (!request_region(port->iobase, size, "serial"))
return -EBUSY;
return 0;
+ case UPIO_UNKNOWN:
+ break;
}
return 0;
@@ -3025,6 +3023,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase, size);
break;
+ case UPIO_UNKNOWN:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 82f2593b4c59..4c8b9671bd41 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -43,6 +43,8 @@ static void rsa8250_release_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index bd3d636ff962..f64ef0819cd4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -572,7 +572,7 @@ config SERIAL_8250_BCM7271
config SERIAL_8250_NI
tristate "NI 16550 based serial port"
depends on SERIAL_8250
- depends on (X86 && ACPI) || COMPILE_TEST
+ depends on X86 || COMPILE_TEST
help
This driver supports the integrated serial ports on National
Instruments (NI) controller hardware. This is required for all NI
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 11d65097578c..421ac22555df 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2476,7 +2476,7 @@ static int pl011_console_setup(struct console *co, char *options)
static int pl011_console_match(struct console *co, char *name, int idx,
char *options)
{
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index fe5aed99d55a..dff6a6c57b5f 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -403,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
case UPIO_MEM32BE:
iowrite32be(val, port->membase + off);
break;
+ default:
+ break;
}
}
@@ -563,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
return sport->port.mapbase + UARTDATA;
case UPIO_MEM32BE:
return sport->port.mapbase + UARTDATA + sizeof(u32) - 1;
+ default:
+ return sport->port.mapbase + UARTDR;
}
- return sport->port.mapbase + UARTDR;
}
static int lpuart_dma_tx_request(struct uart_port *port)
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index ce0fef7e2c66..be2f130696b3 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -451,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
if (!brd->channels[i])
continue;
+ brd->channels[i]->uart_port.dev = &brd->pci_dev->dev;
brd->channels[i]->uart_port.irq = brd->irq;
brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 58a3ab030d67..62cd9e0bb377 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -773,10 +773,8 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port)
int ret;
ret = platform_get_irq(to_platform_device(dev), 0);
- if (ret < 0) {
- dev_err(dev, "failed to fetch IRQ for serial port\n");
+ if (ret < 0)
return ret;
- }
ltq_port->common_irq = ret;
port->irq = ret;
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index f2dd83692b2c..d28a2ebfa29f 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -16,6 +16,7 @@
/* 4 MAX3100s should be enough for everyone */
#define MAX_MAX3100 4
+#include <linux/bitops.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -133,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c)
else
c &= 0xff;
- parity = parity ^ (hweight8(c) & 1);
+ parity = parity ^ parity8(c);
return parity;
}
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 35369a2f77b2..541c790c0109 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1189,13 +1189,16 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!((val >> 4) & (1 << (offset % 4)));
}
-static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
value ? 1 << (offset % 4) : 0);
+
+ return 0;
}
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -1411,7 +1414,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
- s->gpio.set = max310x_gpio_set;
+ s->gpio.set_rv = max310x_gpio_set;
s->gpio.set_config = max310x_gpio_set_config;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4;
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index 059bea18dbab..4e47dca2c4ed 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev)
}
port->membase = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
-
+ if (!port->membase) {
+ ret = -ENOMEM;
+ goto failed;
+ }
ret = platform_get_irq_byname(pdev, "rx");
mlb_usio_irq[index][RX] = ret;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index a80ce7aaf309..0293b6210aa6 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -98,6 +98,8 @@
#define DMA_RX_BUF_SIZE 2048
+static DEFINE_IDA(port_ida);
+
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
@@ -253,10 +255,24 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
struct qcom_geni_serial_port *port;
int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
- if (line < 0 || line >= nr_ports)
- return ERR_PTR(-ENXIO);
+ if (console) {
+ if (line < 0 || line >= nr_ports)
+ return ERR_PTR(-ENXIO);
+
+ port = &qcom_geni_console_port;
+ } else {
+ int max_alias_num = of_alias_get_highest_id("serial");
+
+ if (line < 0 || line >= nr_ports)
+ line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
+ else
+ line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
+
+ if (line < 0)
+ return ERR_PTR(-ENXIO);
- port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line];
+ port = &qcom_geni_uart_ports[line];
+ }
return port;
}
@@ -1761,6 +1777,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
return ret;
}
@@ -1772,10 +1789,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
static void qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
struct uart_driver *drv = port->private_data.drv;
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
}
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 210fff7164c1..2fb58c626daf 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -52,7 +52,7 @@
#define S3C24XX_SERIAL_MINOR 64
#ifdef CONFIG_ARM64
-#define UART_NR 12
+#define UART_NR 18
#else
#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS
#endif
@@ -190,6 +190,8 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel_relaxed(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
@@ -2713,6 +2715,8 @@ static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 560f45ed19ae..5ea8aadb6e69 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1333,13 +1333,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset));
}
-static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
val ? BIT(offset) : 0);
+
+ return 0;
}
static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
@@ -1422,7 +1425,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
- s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.set_rv = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = s->devtype->nr_gpio;
s->gpio.can_sleep = 1;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 88669972d9a0..1f7708a91fc6 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport)
wake_up(&uport->state->remove_wait);
}
-#define uart_port_lock(state, flags) \
- ({ \
- struct uart_port *__uport = uart_port_ref(state); \
- if (__uport) \
- uart_port_lock_irqsave(__uport, &flags); \
- __uport; \
- })
-
-#define uart_port_unlock(uport, flags) \
- ({ \
- struct uart_port *__uport = uport; \
- if (__uport) { \
- uart_port_unlock_irqrestore(__uport, flags); \
- uart_port_deref(__uport); \
- } \
- })
+static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags)
+{
+ struct uart_port *uport = uart_port_ref(state);
+
+ if (uport)
+ uart_port_lock_irqsave(uport, flags);
+
+ return uport;
+}
+
+static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags)
+{
+ if (uport) {
+ uart_port_unlock_irqrestore(uport, flags);
+ uart_port_deref(uport);
+ }
+}
static inline struct uart_port *uart_port_check(struct uart_state *state)
{
@@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (port)
port->ops->stop_tx(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void __uart_start(struct uart_state *state)
@@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void
@@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
if (!page)
return -ENOMEM;
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
} else {
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_free_xmit_buf().
@@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port)
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
*/
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
}
@@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
unsigned long flags;
int ret = 0;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
if (WARN_ON(!state))
return -EL3HLT;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
@@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_avail(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_len(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!port)
return;
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
@@ -1275,14 +1276,13 @@ static int uart_get_icount(struct tty_struct *tty,
struct uart_state *state = tty->driver_data;
struct uart_icount cnow;
struct uart_port *uport;
+ unsigned long flags;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
if (!uport)
return -EIO;
- uart_port_lock_irq(uport);
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
icount->cts = cnow.cts;
icount->dsr = cnow.dsr;
@@ -1914,9 +1914,10 @@ static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ unsigned long flags;
int mctrl;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
/*
* Should never observe uport == NULL since checks for hangup should
* abort the tty_port_block_til_ready() loop before checking for carrier
@@ -1925,11 +1926,9 @@ static bool uart_carrier_raised(struct tty_port *port)
*/
if (WARN_ON(!uport))
return true;
- uart_port_lock_irq(uport);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
return mctrl & TIOCM_CAR;
}
@@ -2178,8 +2177,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
*
* Returns: 0 on success or -%EINVAL on failure
*/
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
- char **options)
+int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
+ resource_size_t *addr, char **options)
{
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
@@ -3289,9 +3288,9 @@ bool uart_match_port(const struct uart_port *port1,
case UPIO_AU:
case UPIO_TSI:
return port1->mapbase == port2->mapbase;
+ default:
+ return false;
}
-
- return false;
}
EXPORT_SYMBOL(uart_match_port);
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
new file mode 100644
index 000000000000..bd9d9cfac1c8
--- /dev/null
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __SH_SCI_COMMON_H__
+#define __SH_SCI_COMMON_H__
+
+#include <linux/serial_core.h>
+
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
+/* Offsets into the sci_port->irqs array */
+enum {
+ SCIx_ERI_IRQ,
+ SCIx_RXI_IRQ,
+ SCIx_TXI_IRQ,
+ SCIx_BRI_IRQ,
+ SCIx_DRI_IRQ,
+ SCIx_TEI_IRQ,
+ SCIx_NR_IRQS,
+
+ SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
+};
+
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+void sci_release_port(struct uart_port *port);
+int sci_request_port(struct uart_port *port);
+void sci_config_port(struct uart_port *port, int flags);
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser);
+void sci_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate);
+
+struct plat_sci_reg {
+ u8 offset;
+ u8 size;
+};
+
+struct sci_port_params_bits {
+ unsigned int rxtx_enable;
+ unsigned int te_clear;
+ unsigned int poll_sent_bits;
+};
+
+struct sci_common_regs {
+ unsigned int status;
+ unsigned int control;
+};
+
+/* The actual number of needed registers. This is used by sci only */
+#define SCI_NR_REGS 20
+
+struct sci_port_params {
+ const struct plat_sci_reg regs[SCI_NR_REGS];
+ const struct sci_common_regs *common_regs;
+ const struct sci_port_params_bits *param_bits;
+ unsigned int fifosize;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
+ unsigned int sampling_rate_mask;
+ unsigned int error_mask;
+ unsigned int error_clear;
+};
+
+struct sci_port_ops {
+ u32 (*read_reg)(struct uart_port *port, int reg);
+ void (*write_reg)(struct uart_port *port, int reg, int value);
+ void (*clear_SCxSR)(struct uart_port *port, unsigned int mask);
+
+ void (*transmit_chars)(struct uart_port *port);
+ void (*receive_chars)(struct uart_port *port);
+
+ void (*poll_put_char)(struct uart_port *port, unsigned char c);
+
+ int (*set_rtrg)(struct uart_port *port, int rx_trig);
+ int (*rtrg_enabled)(struct uart_port *port);
+
+ void (*shutdown_complete)(struct uart_port *port);
+
+ void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
+ void (*console_save)(struct uart_port *port);
+ void (*console_restore)(struct uart_port *port);
+ size_t (*suspend_regs_size)(void);
+};
+
+struct sci_of_data {
+ const struct sci_port_params *params;
+ const struct uart_ops *uart_ops;
+ const struct sci_port_ops *ops;
+ unsigned short regtype;
+ unsigned short type;
+};
+
+struct sci_port {
+ struct uart_port port;
+
+ /* Platform configuration */
+ const struct sci_port_params *params;
+ const struct plat_sci_port *cfg;
+
+ unsigned int sampling_rate_mask;
+ resource_size_t reg_size;
+ struct mctrl_gpios *gpios;
+
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
+
+ int irqs[SCIx_NR_IRQS];
+ char *irqstr[SCIx_NR_IRQS];
+
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+
+ struct reset_control *rstc;
+ struct sci_suspend_regs *suspend_regs;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct dma_chan *chan_tx_saved;
+ struct dma_chan *chan_rx_saved;
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx[2];
+ dma_cookie_t active_rx;
+ dma_addr_t tx_dma_addr;
+ unsigned int tx_dma_len;
+ struct scatterlist sg_rx[2];
+ void *rx_buf[2];
+ size_t buf_len_rx;
+ struct work_struct work_tx;
+ struct hrtimer rx_timer;
+ unsigned int rx_timeout; /* microseconds */
+#endif
+ unsigned int rx_frame;
+ int rx_trigger;
+ struct timer_list rx_fifo_timer;
+ int rx_fifo_timeout;
+ u16 hscif_tot;
+
+ const struct sci_port_ops *ops;
+
+ bool has_rtscts;
+ bool autorts;
+ bool tx_occurred;
+};
+
+#define to_sci_port(uart) container_of((uart), struct sci_port, port)
+
+void sci_port_disable(struct sci_port *sci_port);
+void sci_port_enable(struct sci_port *sci_port);
+
+int sci_startup(struct uart_port *port);
+void sci_shutdown(struct uart_port *port);
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data);
+#endif
+
+#endif /* __SH_SCI_COMMON_H__ */
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7e7813ccda41..ff1986dc6af3 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -56,19 +56,7 @@
#include "serial_mctrl_gpio.h"
#include "sh-sci.h"
-
-/* Offsets into the sci_port->irqs array */
-enum {
- SCIx_ERI_IRQ,
- SCIx_RXI_IRQ,
- SCIx_TXI_IRQ,
- SCIx_BRI_IRQ,
- SCIx_DRI_IRQ,
- SCIx_TEI_IRQ,
- SCIx_NR_IRQS,
-
- SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
-};
+#include "sh-sci-common.h"
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
@@ -76,32 +64,38 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
-enum SCI_CLKS {
- SCI_FCK, /* Functional Clock */
- SCI_SCK, /* Optional External Clock */
- SCI_BRG_INT, /* Optional BRG Internal Clock Source */
- SCI_SCIF_CLK, /* Optional BRG External Clock Source */
- SCI_NUM_CLKS
-};
-
-/* Bit x set means sampling rate x + 1 is supported */
-#define SCI_SR(x) BIT((x) - 1)
-#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
-
#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
SCI_SR(19) | SCI_SR(27)
-#define min_sr(_port) ffs((_port)->sampling_rate_mask)
-#define max_sr(_port) fls((_port)->sampling_rate_mask)
-
/* Iterate over all supported sampling rates, from high to low */
#define for_each_sr(_sr, _port) \
for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
-struct plat_sci_reg {
- u8 offset, size;
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+
+static struct sci_port sci_ports[SCI_NPORTS];
+static unsigned long sci_ports_in_use;
+static struct uart_driver sci_uart_driver;
+static bool sci_uart_earlycon;
+static bool sci_uart_earlycon_dev_probing;
+
+static const struct sci_port_params_bits sci_sci_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCI_TDRE | SCI_TEND
+};
+
+static const struct sci_port_params_bits sci_scif_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCIF_TDFE | SCIF_TEND
+};
+
+static const struct sci_common_regs sci_common_regs = {
+ .status = SCxSR,
+ .control = SCSCR,
};
struct sci_suspend_regs {
@@ -118,77 +112,9 @@ struct sci_suspend_regs {
u8 semr;
};
-struct sci_port_params {
- const struct plat_sci_reg regs[SCIx_NR_REGS];
- unsigned int fifosize;
- unsigned int overrun_reg;
- unsigned int overrun_mask;
- unsigned int sampling_rate_mask;
- unsigned int error_mask;
- unsigned int error_clear;
-};
-
-struct sci_port {
- struct uart_port port;
-
- /* Platform configuration */
- const struct sci_port_params *params;
- const struct plat_sci_port *cfg;
- unsigned int sampling_rate_mask;
- resource_size_t reg_size;
- struct mctrl_gpios *gpios;
-
- /* Clocks */
- struct clk *clks[SCI_NUM_CLKS];
- unsigned long clk_rates[SCI_NUM_CLKS];
-
- int irqs[SCIx_NR_IRQS];
- char *irqstr[SCIx_NR_IRQS];
-
- struct dma_chan *chan_tx;
- struct dma_chan *chan_rx;
-
- struct reset_control *rstc;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
- struct dma_chan *chan_tx_saved;
- struct dma_chan *chan_rx_saved;
- dma_cookie_t cookie_tx;
- dma_cookie_t cookie_rx[2];
- dma_cookie_t active_rx;
- dma_addr_t tx_dma_addr;
- unsigned int tx_dma_len;
- struct scatterlist sg_rx[2];
- void *rx_buf[2];
- size_t buf_len_rx;
- struct work_struct work_tx;
- struct hrtimer rx_timer;
- unsigned int rx_timeout; /* microseconds */
-#endif
- unsigned int rx_frame;
- int rx_trigger;
- struct timer_list rx_fifo_timer;
- int rx_fifo_timeout;
- struct sci_suspend_regs suspend_regs;
- u16 hscif_tot;
-
- bool has_rtscts;
- bool autorts;
- bool tx_occurred;
-};
-
-#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-
-static struct sci_port sci_ports[SCI_NPORTS];
-static unsigned long sci_ports_in_use;
-static struct uart_driver sci_uart_driver;
-static bool sci_uart_earlycon;
-static bool sci_uart_earlycon_dev_probing;
-
-static inline struct sci_port *
-to_sci_port(struct uart_port *uart)
+static size_t sci_suspend_regs_size(void)
{
- return container_of(uart, struct sci_port, port);
+ return sizeof(struct sci_suspend_regs);
}
static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
@@ -211,6 +137,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_sci_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -233,6 +161,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -257,6 +187,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -282,6 +214,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -307,10 +241,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
- * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
+ * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1.
* It looks like a normal SCIF with FIFO data, but with a
* compressed address space. Also, the break out of interrupts
* are different: ERI/BRI, RXI, TXI, TEI, DRI.
@@ -335,6 +271,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -366,6 +304,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -388,6 +328,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -412,6 +354,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -439,6 +383,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -468,6 +414,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_RANGE(8, 32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -492,6 +440,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -519,6 +469,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -542,6 +494,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(16),
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
};
@@ -579,7 +533,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value)
WARN(1, "Invalid register access\n");
}
-static void sci_port_enable(struct sci_port *sci_port)
+void sci_port_enable(struct sci_port *sci_port)
{
unsigned int i;
@@ -595,7 +549,7 @@ static void sci_port_enable(struct sci_port *sci_port)
sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
-static void sci_port_disable(struct sci_port *sci_port)
+void sci_port_disable(struct sci_port *sci_port)
{
unsigned int i;
@@ -735,12 +689,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
static int sci_poll_get_char(struct uart_port *port)
{
unsigned short status;
+ struct sci_port *s = to_sci_port(port);
int c;
do {
status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
}
break;
@@ -753,7 +708,7 @@ static int sci_poll_get_char(struct uart_port *port)
/* Dummy read */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
}
@@ -761,14 +716,16 @@ static int sci_poll_get_char(struct uart_port *port)
static void sci_poll_put_char(struct uart_port *port, unsigned char c)
{
- unsigned short status;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status;
do {
- status = sci_serial_in(port, SCxSR);
+ status = s->ops->read_reg(port, regs->status);
} while (!(status & SCxSR_TDxE(port)));
sci_serial_out(port, SCxTDR, c);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
CONFIG_SERIAL_SH_SCI_EARLYCON */
@@ -911,7 +868,7 @@ static void sci_transmit_chars(struct uart_port *port)
port->icount.tx++;
} while (--count > 0);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -930,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port)
static void sci_receive_chars(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
+ struct sci_port *s = to_sci_port(port);
int i, count, copied = 0;
unsigned short status;
unsigned char flag;
@@ -984,7 +942,7 @@ static void sci_receive_chars(struct uart_port *port)
}
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count;
port->icount.rx += count;
@@ -997,16 +955,17 @@ static void sci_receive_chars(struct uart_port *port)
/* TTY buffers full; read from RX reg to prevent lockup */
sci_serial_in(port, SCxRDR);
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
}
static int sci_handle_errors(struct uart_port *port)
{
int copied = 0;
- unsigned short status = sci_serial_in(port, SCxSR);
- struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status = s->ops->read_reg(port, regs->status);
+ struct tty_port *tport = &port->state->port;
/* Handle overruns */
if (status & s->params->overrun_mask) {
@@ -1165,7 +1124,7 @@ static void rx_fifo_timer_fn(struct timer_list *t)
struct uart_port *port = &s->port;
dev_dbg(port->dev, "Rx timed out\n");
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
}
static ssize_t rx_fifo_trigger_show(struct device *dev,
@@ -1190,9 +1149,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev,
if (ret)
return ret;
- sci->rx_trigger = scif_set_rtrg(port, r);
+ sci->rx_trigger = sci->ops->set_rtrg(port, r);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
return count;
}
@@ -1235,7 +1194,7 @@ static ssize_t rx_fifo_timeout_store(struct device *dev,
sci->hscif_tot = r << HSSCR_TOT_SHIFT;
} else {
sci->rx_fifo_timeout = r;
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
if (r > 0)
timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0);
}
@@ -1360,7 +1319,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
else
scr &= ~SCSCR_RDRQE;
}
@@ -1798,7 +1757,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
scr |= SCSCR_RIE;
} else {
scr |= SCSCR_RDRQE;
@@ -1824,8 +1783,8 @@ handle_pio:
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
- if (!scif_rtrg_enabled(port))
- scif_set_rtrg(port, s->rx_trigger);
+ if (!s->ops->rtrg_enabled(port))
+ s->ops->set_rtrg(port, s->rx_trigger);
mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
@@ -1835,7 +1794,7 @@ handle_pio:
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
return IRQ_HANDLED;
}
@@ -1844,9 +1803,10 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
unsigned long flags;
+ struct sci_port *s = to_sci_port(port);
uart_port_lock_irqsave(port, &flags);
- sci_transmit_chars(port);
+ s->ops->transmit_chars(port);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1855,16 +1815,18 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
unsigned long flags;
- unsigned short ctrl;
+ u32 ctrl;
if (port->type != PORT_SCI)
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
- sci_serial_out(port, SCSCR, ctrl);
+ ctrl = s->ops->read_reg(port, regs->control) &
+ ~(s->params->param_bits->te_clear);
+ s->ops->write_reg(port, regs->control, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1873,6 +1835,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
static irqreturn_t sci_br_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
/* Handle BREAKs */
sci_handle_breaks(port);
@@ -1880,7 +1843,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* drop invalid character received before break was detected */
sci_serial_in(port, SCxRDR);
- sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
}
@@ -1908,15 +1871,15 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (sci_handle_errors(port)) {
/* discard character in rx buffer */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
sci_handle_fifo_overrun(port);
if (!s->chan_rx)
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
}
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
if (!s->chan_tx)
@@ -2286,7 +2249,17 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
uart_port_unlock_irqrestore(port, flags);
}
-static int sci_startup(struct uart_port *port)
+static void sci_shutdown_complete(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ u16 scr;
+
+ scr = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR,
+ scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+}
+
+int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
int ret;
@@ -2305,11 +2278,10 @@ static int sci_startup(struct uart_port *port)
return 0;
}
-static void sci_shutdown(struct uart_port *port)
+void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
unsigned long flags;
- u16 scr;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -2319,13 +2291,7 @@ static void sci_shutdown(struct uart_port *port)
uart_port_lock_irqsave(port, &flags);
sci_stop_rx(port);
sci_stop_tx(port);
- /*
- * Stop RX and TX, disable related interrupts, keep clock source
- * and HSCIF TOT bits
- */
- scr = sci_serial_in(port, SCSCR);
- sci_serial_out(port, SCSCR,
- scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+ s->ops->shutdown_complete(port);
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2402,8 +2368,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
/* calculate sample rate, BRR, and clock select */
static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned int *brr, unsigned int *srr,
- unsigned int *cks)
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
unsigned long freq = s->clk_rates[SCI_FCK];
unsigned int sr, br, prediv, scrate, c;
@@ -2480,9 +2446,9 @@ static void sci_reset(struct uart_port *port)
if (reg->size)
sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
- sci_clear_SCxSR(port,
- SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
- SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port,
+ SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
+ SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
@@ -2491,14 +2457,14 @@ static void sci_reset(struct uart_port *port)
if (s->rx_trigger > 1) {
if (s->rx_fifo_timeout) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0);
} else {
if (port->type == PORT_SCIFA ||
port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
else
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
}
}
}
@@ -2758,7 +2724,7 @@ done:
sci_enable_ms(port);
}
-static void sci_pm(struct uart_port *port, unsigned int state,
+void sci_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sci_port *sci_port = to_sci_port(port);
@@ -2821,7 +2787,7 @@ static int sci_remap_port(struct uart_port *port)
return 0;
}
-static void sci_release_port(struct uart_port *port)
+void sci_release_port(struct uart_port *port)
{
struct sci_port *sport = to_sci_port(port);
@@ -2833,7 +2799,7 @@ static void sci_release_port(struct uart_port *port)
release_mem_region(port->mapbase, sport->reg_size);
}
-static int sci_request_port(struct uart_port *port)
+int sci_request_port(struct uart_port *port)
{
struct resource *res;
struct sci_port *sport = to_sci_port(port);
@@ -2855,7 +2821,7 @@ static int sci_request_port(struct uart_port *port)
return 0;
}
-static void sci_config_port(struct uart_port *port, int flags)
+void sci_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
struct sci_port *sport = to_sci_port(port);
@@ -2865,7 +2831,7 @@ static void sci_config_port(struct uart_port *port, int flags)
}
}
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->baud_base < 2400)
/* No paper tape reader for Mitch.. */
@@ -2874,6 +2840,75 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+static void sci_prepare_console_write(struct uart_port *port, u32 ctrl)
+{
+ struct sci_port *s = to_sci_port(port);
+ u32 ctrl_temp =
+ s->params->param_bits->rxtx_enable |
+ (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) |
+ s->hscif_tot;
+ sci_serial_out(port, SCSCR, ctrl_temp);
+}
+
+static void sci_console_save(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ regs->scdl = sci_serial_in(port, SCDL);
+ if (sci_getreg(port, SCCKS)->size)
+ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+ regs->scscr = sci_serial_in(port, SCSCR);
+ if (sci_getreg(port, SCFCR)->size)
+ regs->scfcr = sci_serial_in(port, SCFCR);
+ if (sci_getreg(port, SCSPTR)->size)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
+ if (sci_getreg(port, HSSRR)->size)
+ regs->hssrr = sci_serial_in(port, HSSRR);
+ if (sci_getreg(port, SCPCR)->size)
+ regs->scpcr = sci_serial_in(port, SCPCR);
+ if (sci_getreg(port, SCPDR)->size)
+ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+}
+
+static void sci_console_restore(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ sci_serial_out(port, SCDL, regs->scdl);
+ if (sci_getreg(port, SCCKS)->size)
+ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+ sci_serial_out(port, SCSCR, regs->scscr);
+ if (sci_getreg(port, SCFCR)->size)
+ sci_serial_out(port, SCFCR, regs->scfcr);
+ if (sci_getreg(port, SCSPTR)->size)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
+ if (sci_getreg(port, HSSRR)->size)
+ sci_serial_out(port, HSSRR, regs->hssrr);
+ if (sci_getreg(port, SCPCR)->size)
+ sci_serial_out(port, SCPCR, regs->scpcr);
+ if (sci_getreg(port, SCPDR)->size)
+ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+}
+
static const struct uart_ops sci_uart_ops = {
.tx_empty = sci_tx_empty,
.set_mctrl = sci_set_mctrl,
@@ -2899,6 +2934,25 @@ static const struct uart_ops sci_uart_ops = {
#endif
};
+static const struct sci_port_ops sci_port_ops = {
+ .read_reg = sci_serial_in,
+ .write_reg = sci_serial_out,
+ .clear_SCxSR = sci_clear_SCxSR,
+ .transmit_chars = sci_transmit_chars,
+ .receive_chars = sci_receive_chars,
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
+ .poll_put_char = sci_poll_put_char,
+#endif
+ .set_rtrg = scif_set_rtrg,
+ .rtrg_enabled = scif_rtrg_enabled,
+ .shutdown_complete = sci_shutdown_complete,
+ .prepare_console_write = sci_prepare_console_write,
+ .console_save = sci_console_save,
+ .console_restore = sci_console_restore,
+ .suspend_regs_size = sci_suspend_regs_size,
+};
+
static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
{
const char *clk_names[] = {
@@ -2942,10 +2996,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
}
static const struct sci_port_params *
-sci_probe_regmap(const struct plat_sci_port *cfg)
+sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port)
{
unsigned int regtype;
+ sci_port->ops = &sci_port_ops;
+ sci_port->port.ops = &sci_uart_ops;
+
if (cfg->regtype != SCIx_PROBE_REGTYPE)
return &sci_port_params[cfg->regtype];
@@ -2993,7 +3050,6 @@ static int sci_init_single(struct platform_device *dev,
sci_port->cfg = p;
- port->ops = &sci_uart_ops;
port->iotype = UPIO_MEM;
port->line = index;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE);
@@ -3033,10 +3089,6 @@ static int sci_init_single(struct platform_device *dev,
for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
sci_port->irqs[i] = sci_port->irqs[0];
- sci_port->params = sci_probe_regmap(p);
- if (unlikely(sci_port->params == NULL))
- return -EINVAL;
-
switch (p->type) {
case PORT_SCIFB:
sci_port->rx_trigger = 48;
@@ -3104,7 +3156,7 @@ static int sci_init_single(struct platform_device *dev,
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
{
- sci_poll_put_char(port, ch);
+ to_sci_port(port)->ops->poll_put_char(port, ch);
}
/*
@@ -3116,7 +3168,9 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl, ctrl_temp;
+ const struct sci_common_regs *regs = sci_port->params->common_regs;
+ unsigned int bits;
+ u32 ctrl;
unsigned long flags;
int locked = 1;
@@ -3128,21 +3182,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags);
/* first save SCSCR then disable interrupts, keep clock source */
- ctrl = sci_serial_in(port, SCSCR);
- ctrl_temp = SCSCR_RE | SCSCR_TE |
- (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
- (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
- sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+
+ ctrl = sci_port->ops->read_reg(port, regs->control);
+ sci_port->ops->prepare_console_write(port, ctrl);
uart_console_write(port, s, count, serial_console_putchar);
/* wait until fifo is empty and last bit has been transmitted */
- bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
- while ((sci_serial_in(port, SCxSR) & bits) != bits)
+
+ bits = sci_port->params->param_bits->poll_sent_bits;
+
+ while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits)
cpu_relax();
/* restore the SCSCR */
- sci_serial_out(port, SCSCR, ctrl);
+ sci_port->ops->write_reg(port, regs->control, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3220,13 +3274,18 @@ static struct console early_serial_console = {
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
+ struct sci_port *sp = &sci_ports[pdev->id];
if (early_serial_console.data)
return -EEXIST;
early_serial_console.index = pdev->id;
- sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
+ sp->params = sci_probe_regmap(cfg, sp);
+ if (!sp->params)
+ return -ENODEV;
+
+ sci_init_single(pdev, sp, pdev->id, cfg, true);
if (!strstr(early_serial_buf, "keep"))
early_serial_console.flags |= CON_BOOT;
@@ -3275,59 +3334,126 @@ static void sci_remove(struct platform_device *dev)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
}
+static const struct sci_of_data of_sci_scif_sh2 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rz_scifa = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZ_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rzv2h = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZV2H_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_rcar_scif = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE],
+};
-#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
-#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
-#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
+static const struct sci_of_data of_sci_scif_sh4 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifa = {
+ .type = PORT_SCIFA,
+ .regtype = SCIx_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifb = {
+ .type = PORT_SCIFB,
+ .regtype = SCIx_SCIFB_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFB_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_hscif = {
+ .type = PORT_HSCIF,
+ .regtype = SCIx_HSCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_HSCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_sci = {
+ .type = PORT_SCI,
+ .regtype = SCIx_SCI_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCI_REGTYPE],
+};
static const struct of_device_id of_sci_match[] __maybe_unused = {
/* SoC-specific types */
{
.compatible = "renesas,scif-r7s72100",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ .data = &of_sci_scif_sh2,
},
{
.compatible = "renesas,scif-r7s9210",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a07g044",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a09g057",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ .data = &of_sci_scif_rzv2h,
},
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen2-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen3-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
}, {
.compatible = "renesas,rcar-gen4-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
},
/* Generic types */
{
.compatible = "renesas,scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
+ .data = &of_sci_scif_sh4,
}, {
.compatible = "renesas,scifa",
- .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
+ .data = &of_sci_scifa,
}, {
.compatible = "renesas,scifb",
- .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
+ .data = &of_sci_scifb,
}, {
.compatible = "renesas,hscif",
- .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
+ .data = &of_sci_hscif,
}, {
.compatible = "renesas,sci",
- .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
+ .data = &of_sci_sci,
}, {
/* Terminator */
},
@@ -3346,7 +3472,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
struct reset_control *rstc;
struct plat_sci_port *p;
struct sci_port *sp;
- const void *data;
+ const struct sci_of_data *data;
int id, ret;
if (!IS_ENABLED(CONFIG_OF) || !np)
@@ -3393,8 +3519,12 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
sp->rstc = rstc;
*dev_id = id;
- p->type = SCI_OF_TYPE(data);
- p->regtype = SCI_OF_REGTYPE(data);
+ p->type = data->type;
+ p->regtype = data->regtype;
+
+ sp->ops = data->ops;
+ sp->port.ops = data->uart_ops;
+ sp->params = data->params;
sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
@@ -3501,6 +3631,7 @@ static int sci_probe(struct platform_device *dev)
p = sci_parse_dt(dev, &dev_id);
if (IS_ERR(p))
return PTR_ERR(p);
+ sp = &sci_ports[dev_id];
} else {
p = dev->dev.platform_data;
if (p == NULL) {
@@ -3509,9 +3640,17 @@ static int sci_probe(struct platform_device *dev)
}
dev_id = dev->id;
+ sp = &sci_ports[dev_id];
+ sp->params = sci_probe_regmap(p, sp);
+ if (!sp->params)
+ return -ENODEV;
}
- sp = &sci_ports[dev_id];
+ sp->suspend_regs = devm_kzalloc(&dev->dev,
+ sp->ops->suspend_regs_size(),
+ GFP_KERNEL);
+ if (!sp->suspend_regs)
+ return -ENOMEM;
/*
* In case:
@@ -3563,64 +3702,6 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
-static void sci_console_save(struct sci_port *s)
-{
- struct sci_suspend_regs *regs = &s->suspend_regs;
- struct uart_port *port = &s->port;
-
- if (sci_getreg(port, SCDL)->size)
- regs->scdl = sci_serial_in(port, SCDL);
- if (sci_getreg(port, SCCKS)->size)
- regs->sccks = sci_serial_in(port, SCCKS);
- if (sci_getreg(port, SCSMR)->size)
- regs->scsmr = sci_serial_in(port, SCSMR);
- if (sci_getreg(port, SCSCR)->size)
- regs->scscr = sci_serial_in(port, SCSCR);
- if (sci_getreg(port, SCFCR)->size)
- regs->scfcr = sci_serial_in(port, SCFCR);
- if (sci_getreg(port, SCSPTR)->size)
- regs->scsptr = sci_serial_in(port, SCSPTR);
- if (sci_getreg(port, SCBRR)->size)
- regs->scbrr = sci_serial_in(port, SCBRR);
- if (sci_getreg(port, HSSRR)->size)
- regs->hssrr = sci_serial_in(port, HSSRR);
- if (sci_getreg(port, SCPCR)->size)
- regs->scpcr = sci_serial_in(port, SCPCR);
- if (sci_getreg(port, SCPDR)->size)
- regs->scpdr = sci_serial_in(port, SCPDR);
- if (sci_getreg(port, SEMR)->size)
- regs->semr = sci_serial_in(port, SEMR);
-}
-
-static void sci_console_restore(struct sci_port *s)
-{
- struct sci_suspend_regs *regs = &s->suspend_regs;
- struct uart_port *port = &s->port;
-
- if (sci_getreg(port, SCDL)->size)
- sci_serial_out(port, SCDL, regs->scdl);
- if (sci_getreg(port, SCCKS)->size)
- sci_serial_out(port, SCCKS, regs->sccks);
- if (sci_getreg(port, SCSMR)->size)
- sci_serial_out(port, SCSMR, regs->scsmr);
- if (sci_getreg(port, SCSCR)->size)
- sci_serial_out(port, SCSCR, regs->scscr);
- if (sci_getreg(port, SCFCR)->size)
- sci_serial_out(port, SCFCR, regs->scfcr);
- if (sci_getreg(port, SCSPTR)->size)
- sci_serial_out(port, SCSPTR, regs->scsptr);
- if (sci_getreg(port, SCBRR)->size)
- sci_serial_out(port, SCBRR, regs->scbrr);
- if (sci_getreg(port, HSSRR)->size)
- sci_serial_out(port, HSSRR, regs->hssrr);
- if (sci_getreg(port, SCPCR)->size)
- sci_serial_out(port, SCPCR, regs->scpcr);
- if (sci_getreg(port, SCPDR)->size)
- sci_serial_out(port, SCPDR, regs->scpdr);
- if (sci_getreg(port, SEMR)->size)
- sci_serial_out(port, SEMR, regs->semr);
-}
-
static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@@ -3628,8 +3709,10 @@ static __maybe_unused int sci_suspend(struct device *dev)
if (sport) {
uart_suspend_port(&sci_uart_driver, &sport->port);
- if (!console_suspend_enabled && uart_console(&sport->port))
- sci_console_save(sport);
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_save)
+ sport->ops->console_save(&sport->port);
+ }
else
return reset_control_assert(sport->rstc);
}
@@ -3643,7 +3726,8 @@ static __maybe_unused int sci_resume(struct device *dev)
if (sport) {
if (!console_suspend_enabled && uart_console(&sport->port)) {
- sci_console_restore(sport);
+ if (sport->ops->console_restore)
+ sport->ops->console_restore(&sport->port);
} else {
int ret = reset_control_deassert(sport->rstc);
@@ -3707,21 +3791,31 @@ static int early_console_exit(struct console *co)
return 0;
}
-static int __init early_console_setup(struct earlycon_device *device,
- int type)
+int __init scix_early_console_setup(struct earlycon_device *device,
+ const struct sci_of_data *data)
{
+ const struct sci_common_regs *regs;
+
if (!device->port.membase)
return -ENODEV;
- device->port.type = type;
+ device->port.type = data->type;
sci_ports[0].port = device->port;
- port_cfg.type = type;
+
+ port_cfg.type = data->type;
+ port_cfg.regtype = data->regtype;
+
sci_ports[0].cfg = &port_cfg;
- sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_ports[0].params = data->params;
+ sci_ports[0].ops = data->ops;
+ sci_ports[0].port.ops = data->uart_ops;
sci_uart_earlycon = true;
- port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
- sci_serial_out(&sci_ports[0].port, SCSCR,
- SCSCR_RE | SCSCR_TE | port_cfg.scscr);
+ regs = sci_ports[0].params->common_regs;
+
+ port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control);
+ sci_ports[0].ops->write_reg(&sci_ports[0].port,
+ regs->control,
+ sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr);
device->con->write = serial_console_write;
device->con->exit = early_console_exit;
@@ -3731,41 +3825,39 @@ static int __init early_console_setup(struct earlycon_device *device,
static int __init sci_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCI);
+ return scix_early_console_setup(device, &of_sci_sci);
}
static int __init scif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_sh4);
}
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rz_scifa);
}
static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rzv2h);
}
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFA);
+ return scix_early_console_setup(device, &of_sci_scifa);
}
static int __init scifb_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFB);
+ return scix_early_console_setup(device, &of_sci_scifb);
}
static int __init hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_HSCIF);
+ return scix_early_console_setup(device, &of_sci_hscif);
}
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 0b65563c4e9e..951681aba586 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -32,8 +32,6 @@ enum {
HSRTRGR, /* Rx FIFO Data Count Trigger Register */
HSTTRGR, /* Tx FIFO Data Count Trigger Register */
SEMR, /* Serial extended mode register */
-
- SCIx_NR_REGS,
};
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 054a8e630ace..110d67613192 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -141,6 +141,7 @@
* @baud_rate: UART serial line rate (e.g., 115200 baud)
* @clk: reference to this device's clock
* @clk_notifier: clock rate change notifier for upstream clock changes
+ * @console_line_ended: indicate that the console line is fully written
*
* Configuration data specific to this SiFive UART.
*/
@@ -151,6 +152,7 @@ struct sifive_serial_port {
unsigned long baud_rate;
struct clk *clk;
struct notifier_block clk_notifier;
+ bool console_line_ended;
};
/*
@@ -785,33 +787,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char
__ssp_wait_for_xmitr(ssp);
__ssp_transmit_char(ssp, ch);
+
+ ssp->console_line_ended = (ch == '\n');
+}
+
+static void sifive_serial_device_lock(struct console *co, unsigned long *flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_lock_irqsave(up, flags);
+}
+
+static void sifive_serial_device_unlock(struct console *co, unsigned long flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_unlock_irqrestore(up, flags);
}
-static void sifive_serial_console_write(struct console *co, const char *s,
- unsigned int count)
+static void sifive_serial_console_write_atomic(struct console *co,
+ struct nbcon_write_context *wctxt)
{
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
- unsigned long flags;
+ struct uart_port *port = &ssp->port;
unsigned int ier;
- int locked = 1;
if (!ssp)
return;
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&ssp->port, &flags);
- else
- uart_port_lock_irqsave(&ssp->port, &flags);
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
- uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
+ if (!ssp->console_line_ended)
+ uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
+ uart_console_write(port, wctxt->outbuf, wctxt->len,
+ sifive_serial_console_putchar);
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
- if (locked)
- uart_port_unlock_irqrestore(&ssp->port, flags);
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void sifive_serial_console_write_thread(struct console *co,
+ struct nbcon_write_context *wctxt)
+{
+ struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
+ struct uart_port *port = &ssp->port;
+ unsigned int ier;
+
+ if (!ssp)
+ return;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
+ __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int len = READ_ONCE(wctxt->len);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ uart_console_write(port, wctxt->outbuf + i, 1,
+ sifive_serial_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ nbcon_exit_unsafe(wctxt);
}
static int sifive_serial_console_setup(struct console *co, char *options)
@@ -829,6 +886,8 @@ static int sifive_serial_console_setup(struct console *co, char *options)
if (!ssp)
return -ENODEV;
+ ssp->console_line_ended = true;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -839,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver;
static struct console sifive_serial_console = {
.name = SIFIVE_TTY_PREFIX,
- .write = sifive_serial_console_write,
+ .write_atomic = sifive_serial_console_write_atomic,
+ .write_thread = sifive_serial_console_write_thread,
+ .device_lock = sifive_serial_device_lock,
+ .device_unlock = sifive_serial_device_unlock,
.device = uart_console_device,
.setup = sifive_serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_NBCON,
.index = -1,
.data = &sifive_serial_uart_driver,
};
diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c
index 39b14fe813c9..0c70d3e7b9b9 100644
--- a/drivers/tty/serial/tegra-utc.c
+++ b/drivers/tty/serial/tegra-utc.c
@@ -434,7 +434,7 @@ static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_wr
outbuf += burst_size;
len -= burst_size;
- };
+ }
nbcon_exit_unsafe(wctxt);
}
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index a41e7fc373b7..39c1fd1ff9ce 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -880,16 +880,6 @@ of_err:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- if (!ulite_uart_driver.state) {
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register driver\n");
- clk_disable_unprepare(pdata->clk);
- return ret;
- }
- }
-
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
pm_runtime_mark_last_busy(&pdev->dev);
@@ -929,16 +919,25 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
+ int ret;
+
+ pr_debug("uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
pr_debug("uartlite: calling platform_driver_register()\n");
- return platform_driver_register(&ulite_platform_driver);
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
}
static void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
- if (ulite_uart_driver.state)
- uart_unregister_driver(&ulite_uart_driver);
+ uart_unregister_driver(&ulite_uart_driver);
}
module_init(ulite_init);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index ca9b7d7bad2b..e2d92cf70eb7 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -276,11 +276,10 @@ static void check_tty_count(struct tty_struct *tty, const char *routine)
struct list_head *p;
int count = 0, kopen_count = 0;
- spin_lock(&tty->files_lock);
- list_for_each(p, &tty->tty_files) {
- count++;
- }
- spin_unlock(&tty->files_lock);
+ scoped_guard(spinlock, &tty->files_lock)
+ list_for_each(p, &tty->tty_files)
+ count++;
+
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_SLAVE &&
tty->link && tty->link->count)
@@ -378,7 +377,7 @@ EXPORT_SYMBOL_GPL(tty_dev_name_to_number);
*/
struct tty_driver *tty_find_polling_driver(char *name, int *line)
{
- struct tty_driver *p, *res = NULL;
+ struct tty_driver *p;
int tty_line = 0;
int len;
char *str, *stp;
@@ -392,7 +391,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
len = str - name;
tty_line = simple_strtoul(str, &str, 10);
- mutex_lock(&tty_mutex);
+ guard(mutex)(&tty_mutex);
+
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (!len || strncmp(name, p->name, len) != 0)
@@ -405,14 +405,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (tty_line >= 0 && tty_line < p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
- res = tty_driver_kref_get(p);
*line = tty_line;
- break;
+ return tty_driver_kref_get(p);
}
}
- mutex_unlock(&tty_mutex);
- return res;
+ return NULL;
}
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
#endif
@@ -531,16 +529,15 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
*/
static struct file *tty_release_redirect(struct tty_struct *tty)
{
- struct file *f = NULL;
+ guard(spinlock)(&redirect_lock);
- spin_lock(&redirect_lock);
if (redirect && file_tty(redirect) == tty) {
- f = redirect;
+ struct file *f = redirect;
redirect = NULL;
+ return f;
}
- spin_unlock(&redirect_lock);
- return f;
+ return NULL;
}
/**
@@ -765,11 +762,8 @@ void __stop_tty(struct tty_struct *tty)
*/
void stop_tty(struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tty->flow.lock, flags);
+ guard(spinlock_irqsave)(&tty->flow.lock);
__stop_tty(tty);
- spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(stop_tty);
@@ -796,11 +790,8 @@ void __start_tty(struct tty_struct *tty)
*/
void start_tty(struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tty->flow.lock, flags);
+ guard(spinlock_irqsave)(&tty->flow.lock);
__start_tty(tty);
- spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(start_tty);
@@ -809,7 +800,8 @@ static void tty_update_time(struct tty_struct *tty, bool mtime)
time64_t sec = ktime_get_real_seconds();
struct tty_file_private *priv;
- spin_lock(&tty->files_lock);
+ guard(spinlock)(&tty->files_lock);
+
list_for_each_entry(priv, &tty->tty_files, list) {
struct inode *inode = file_inode(priv->file);
struct timespec64 time = mtime ? inode_get_mtime(inode) : inode_get_atime(inode);
@@ -827,7 +819,6 @@ static void tty_update_time(struct tty_struct *tty, bool mtime)
inode_set_atime(inode, sec, 0);
}
}
- spin_unlock(&tty->files_lock);
}
/*
@@ -2314,13 +2305,12 @@ static int tiocsti(struct tty_struct *tty, u8 __user *p)
*/
static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{
- int err;
+ guard(mutex)(&tty->winsize_mutex);
- mutex_lock(&tty->winsize_mutex);
- err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
- mutex_unlock(&tty->winsize_mutex);
+ if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
+ return -EFAULT;
- return err ? -EFAULT : 0;
+ return 0;
}
/**
@@ -2335,10 +2325,10 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp;
- /* Lock the tty */
- mutex_lock(&tty->winsize_mutex);
+ guard(mutex)(&tty->winsize_mutex);
+
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
- goto done;
+ return 0;
/* Signal the foreground process group */
pgrp = tty_get_pgrp(tty);
@@ -2347,8 +2337,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
put_pid(pgrp);
tty->winsize = *ws;
-done:
- mutex_unlock(&tty->winsize_mutex);
+
return 0;
}
EXPORT_SYMBOL(tty_do_resize);
@@ -2409,13 +2398,14 @@ static int tioccons(struct file *file)
return -EBADF;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
- spin_lock(&redirect_lock);
- if (redirect) {
- spin_unlock(&redirect_lock);
+
+ guard(spinlock)(&redirect_lock);
+
+ if (redirect)
return -EBUSY;
- }
+
redirect = get_file(file);
- spin_unlock(&redirect_lock);
+
return 0;
}
@@ -3028,11 +3018,9 @@ void __do_SAK(struct tty_struct *tty)
struct task_struct *g, *p;
struct pid *session;
int i;
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl.lock, flags);
- session = get_pid(tty->ctrl.session);
- spin_unlock_irqrestore(&tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &tty->ctrl.lock)
+ session = get_pid(tty->ctrl.session);
tty_ldisc_flush(tty);
@@ -3055,7 +3043,7 @@ void __do_SAK(struct tty_struct *tty)
PIDTYPE_SID);
continue;
}
- task_lock(p);
+ guard(task_lock)(p);
i = iterate_fd(p->files, 0, this_tty, tty);
if (i != 0) {
tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
@@ -3063,7 +3051,6 @@ void __do_SAK(struct tty_struct *tty)
group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p,
PIDTYPE_SID);
}
- task_unlock(p);
}
read_unlock(&tasklist_lock);
put_pid(session);
@@ -3465,9 +3452,8 @@ int tty_register_driver(struct tty_driver *driver)
goto err_unreg_char;
}
- mutex_lock(&tty_mutex);
- list_add(&driver->tty_drivers, &tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_add(&driver->tty_drivers, &tty_drivers);
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = 0; i < driver->num; i++) {
@@ -3486,9 +3472,8 @@ err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);
- mutex_lock(&tty_mutex);
- list_del(&driver->tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_del(&driver->tty_drivers);
err_unreg_char:
unregister_chrdev_region(dev, driver->num);
@@ -3507,9 +3492,8 @@ void tty_unregister_driver(struct tty_driver *driver)
{
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num);
- mutex_lock(&tty_mutex);
- list_del(&driver->tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_del(&driver->tty_drivers);
}
EXPORT_SYMBOL(tty_unregister_driver);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 85de90eebc7b..90c70d8d14e3 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -122,21 +122,19 @@ EXPORT_SYMBOL(tty_unthrottle);
*/
bool tty_throttle_safe(struct tty_struct *tty)
{
- bool ret = true;
-
- mutex_lock(&tty->throttle_mutex);
- if (!tty_throttled(tty)) {
- if (tty->flow_change != TTY_THROTTLE_SAFE)
- ret = false;
- else {
- set_bit(TTY_THROTTLED, &tty->flags);
- if (tty->ops->throttle)
- tty->ops->throttle(tty);
- }
- }
- mutex_unlock(&tty->throttle_mutex);
+ guard(mutex)(&tty->throttle_mutex);
- return ret;
+ if (tty_throttled(tty))
+ return true;
+
+ if (tty->flow_change != TTY_THROTTLE_SAFE)
+ return false;
+
+ set_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->throttle)
+ tty->ops->throttle(tty);
+
+ return true;
}
/**
@@ -152,21 +150,19 @@ bool tty_throttle_safe(struct tty_struct *tty)
*/
bool tty_unthrottle_safe(struct tty_struct *tty)
{
- bool ret = true;
+ guard(mutex)(&tty->throttle_mutex);
- mutex_lock(&tty->throttle_mutex);
- if (tty_throttled(tty)) {
- if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
- ret = false;
- else {
- clear_bit(TTY_THROTTLED, &tty->flags);
- if (tty->ops->unthrottle)
- tty->ops->unthrottle(tty);
- }
- }
- mutex_unlock(&tty->throttle_mutex);
+ if (!tty_throttled(tty))
+ return true;
- return ret;
+ if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
+ return false;
+
+ clear_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+
+ return true;
}
/**
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 14cca33d2269..4af1fbf73f51 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -200,26 +200,6 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
/**
- * tty_port_register_device_serdev - register tty or serdev device
- * @port: tty_port of the device
- * @driver: tty_driver for this device
- * @index: index of the tty
- * @host: serial port hardware controller device
- * @parent: parent if exists, otherwise NULL
- *
- * Register a serdev or tty device depending on if the parent device has any
- * defined serdev clients or not.
- */
-struct device *tty_port_register_device_serdev(struct tty_port *port,
- struct tty_driver *driver, unsigned index,
- struct device *host, struct device *parent)
-{
- return tty_port_register_device_attr_serdev(port, driver, index,
- host, parent, NULL, NULL);
-}
-EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
-
-/**
* tty_port_unregister_device - deregister a tty or serdev device
* @port: tty_port of the device
* @driver: tty_driver for this device
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore
index 0221709b177d..a74859bab862 100644
--- a/drivers/tty/vt/.gitignore
+++ b/drivers/tty/vt/.gitignore
@@ -2,3 +2,6 @@
/conmakehash
/consolemap_deftbl.c
/defkeymap.c
+/ucs_fallback_table.h
+/ucs_recompose_table.h
+/ucs_width_table.h
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
index 2c8ce8b592ed..ae746dcdeec8 100644
--- a/drivers/tty/vt/Makefile
+++ b/drivers/tty/vt/Makefile
@@ -7,10 +7,12 @@ FONTMAPFILE = cp437.uni
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \
selection.o keyboard.o \
vt.o defkeymap.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o \
+ ucs.o
# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
+clean-files := consolemap_deftbl.c defkeymap.c \
+ ucs_width_table.h ucs_recompose_table.h ucs_fallback_table.h
hostprogs += conmakehash
@@ -33,3 +35,31 @@ $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
loadkeys --mktable --unicode $< > $@
endif
+
+$(obj)/ucs.o: $(src)/ucs.c $(obj)/ucs_width_table.h \
+ $(obj)/ucs_recompose_table.h $(obj)/ucs_fallback_table.h
+
+# You may uncomment one of those to have the UCS tables be regenerated
+# during the build process. By default the _shipped versions are used.
+#
+#GENERATE_UCS_TABLES := 1
+#GENERATE_UCS_TABLES := 2 # invokes gen_ucs_recompose_table.py with --full
+
+ifdef GENERATE_UCS_TABLES
+
+$(obj)/ucs_width_table.h: $(src)/gen_ucs_width_table.py
+ $(PYTHON3) $< -o $@
+
+ifeq ($(GENERATE_UCS_TABLES),2)
+gen_recomp_arg := --full
+else
+gen_recomp_arg :=
+endif
+
+$(obj)/ucs_recompose_table.h: $(src)/gen_ucs_recompose_table.py
+ $(PYTHON3) $< -o $@ $(gen_recomp_arg)
+
+$(obj)/ucs_fallback_table.h: $(src)/gen_ucs_fallback_table.py
+ $(PYTHON3) $< -o $@
+
+endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 82d70083fead..bb4bb272ebec 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -870,8 +870,6 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs)
return -4; /* Not found */
else if (ucs < 0x20)
return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
- return -2; /* Zero-width space */
/*
* UNI_DIRECT_BASE indicates the start of the region in the User Zone
* which always has a 1:1 mapping to the currently loaded font. The
diff --git a/drivers/tty/vt/gen_ucs_fallback_table.py b/drivers/tty/vt/gen_ucs_fallback_table.py
new file mode 100755
index 000000000000..6e09c1cb6d4b
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_fallback_table.py
@@ -0,0 +1,360 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unidecode module to generate ucs_fallback_table.h
+#
+# The generated table maps complex characters to their simpler fallback forms
+# for a terminal display when corresponding glyphs are unavailable.
+#
+# Usage:
+# python3 gen_ucs_fallback_table.py # Generate fallback tables
+# python3 gen_ucs_fallback_table.py -o FILE # Specify output file
+
+import unicodedata
+from unidecode import unidecode
+import sys
+import argparse
+from collections import defaultdict
+
+# Try to get unidecode version
+try:
+ from importlib.metadata import version
+ unidecode_version = version('unidecode')
+except:
+ unidecode_version = 'unknown'
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_fallback_table.h"
+
+# Define the range marker value
+RANGE_MARKER = 0x00
+
+def generate_fallback_map():
+ """Generate a fallback map using unidecode for all relevant Unicode points."""
+ fallback_map = {}
+
+ # Process BMP characters (0x0000 - 0xFFFF) to keep table size manageable
+ for cp in range(0x0080, 0x10000): # Skip ASCII range (0x00-0x7F)
+ char = chr(cp)
+
+ # Skip unassigned/control characters
+ try:
+ if not unicodedata.name(char, ''):
+ continue
+ except ValueError:
+ continue
+
+ # Get the unidecode transliteration
+ ascii_version = unidecode(char)
+
+ # Only store if it results in a single character mapping
+ if len(ascii_version) == 1:
+ fallback_map[cp] = ord(ascii_version)
+
+ # Apply manual overrides for special cases
+ fallback_map.update(get_special_overrides())
+
+ return fallback_map
+
+def get_special_overrides():
+ """Get special case overrides that need different handling than unidecode
+ provides... or doesn't provide at all."""
+
+ overrides = {}
+
+ # Multi-character unidecode output
+ # These map to single chars instead of unidecode's multiple-char mappings
+ # In a terminal fallback context, we need a single character rather than multiple
+ overrides[0x00C6] = ord('E') # Æ LATIN CAPITAL LETTER AE -> E (unidecode: "AE")
+ overrides[0x00E6] = ord('e') # æ LATIN SMALL LETTER AE -> e (unidecode: "ae")
+ overrides[0x0152] = ord('E') # Œ LATIN CAPITAL LIGATURE OE -> E (unidecode: "OE")
+ overrides[0x0153] = ord('e') # œ LATIN SMALL LETTER LIGATURE OE -> e (unidecode: "oe")
+ overrides[0x00DF] = ord('s') # ß LATIN SMALL LETTER SHARP S -> s (unidecode: "ss")
+
+ # Comparison operators that unidecode renders as multiple characters
+ overrides[0x2264] = ord('<') # ≤ LESS-THAN OR EQUAL TO -> < (unidecode: "<=")
+ overrides[0x2265] = ord('>') # ≥ GREATER-THAN OR EQUAL TO -> > (unidecode: ">=")
+
+ # Unidecode returns an empty string for these
+ overrides[0x2260] = ord('#') # ≠ NOT EQUAL TO -> # (unidecode: empty string)
+
+ # Quadrant block characters that unidecode doesn't map
+ for cp in range(0x2596, 0x259F+1):
+ overrides[cp] = ord('#') # ▖ ▗ ▘ ▙ etc. - map to # (unidecode: empty string)
+
+ # Directional arrows
+ # These provide better semantic meaning than unidecode's mappings
+ overrides[0x2192] = ord('>') # → RIGHTWARDS ARROW -> > (unidecode: "-")
+ overrides[0x2190] = ord('<') # ← LEFTWARDS ARROW -> < (unidecode: "-")
+ overrides[0x2191] = ord('^') # ↑ UPWARDS ARROW -> ^ (unidecode: "|")
+ overrides[0x2193] = ord('v') # ↓ DOWNWARDS ARROW -> v (unidecode: "|")
+
+ # Double arrows with their directional semantic mappings
+ overrides[0x21D0] = ord('<') # ⇐ LEFTWARDS DOUBLE ARROW -> <
+ overrides[0x21D1] = ord('^') # ⇑ UPWARDS DOUBLE ARROW -> ^
+ overrides[0x21D2] = ord('>') # ⇒ RIGHTWARDS DOUBLE ARROW -> >
+ overrides[0x21D3] = ord('v') # ⇓ DOWNWARDS DOUBLE ARROW -> v
+
+ # Halfwidth arrows
+ # These need the same treatment as their normal-width counterparts
+ overrides[0xFFE9] = ord('<') # ← HALFWIDTH LEFTWARDS ARROW -> < (unidecode: "-")
+ overrides[0xFFEA] = ord('^') # ↑ HALFWIDTH UPWARDS ARROW -> ^ (unidecode: "|")
+ overrides[0xFFEB] = ord('>') # → HALFWIDTH RIGHTWARDS ARROW -> > (unidecode: "-")
+ overrides[0xFFEC] = ord('v') # ↓ HALFWIDTH DOWNWARDS ARROW -> v (unidecode: "|")
+
+ # Currency symbols - each mapped to a representative letter
+ overrides[0x00A2] = ord('c') # ¢ CENT SIGN -> c
+ overrides[0x00A3] = ord('L') # £ POUND SIGN -> L
+ overrides[0x00A5] = ord('Y') # ¥ YEN SIGN -> Y
+ overrides[0x20AC] = ord('E') # € EURO SIGN -> E
+
+ # Symbols mapped to letters
+ overrides[0x00A7] = ord('S') # § SECTION SIGN -> S
+ overrides[0x00A9] = ord('C') # © COPYRIGHT SIGN -> C
+ overrides[0x00AE] = ord('R') # ® REGISTERED SIGN -> R
+ overrides[0x2122] = ord('T') # ™ TRADE MARK SIGN -> T
+
+ # Degree-related symbols
+ overrides[0x00B0] = ord('o') # ° DEGREE SIGN -> o
+ overrides[0x2103] = ord('C') # ℃ DEGREE CELSIUS -> C
+ overrides[0x2109] = ord('F') # ℉ DEGREE FAHRENHEIT -> F
+
+ # Angle quotation marks
+ overrides[0x00AB] = ord('<') # « LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> <
+ overrides[0x00BB] = ord('>') # » RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> >
+
+ # Operators with circular shape
+ overrides[0x2218] = ord('o') # ∘ RING OPERATOR -> o
+ overrides[0x2219] = ord('.') # ∙ BULLET OPERATOR -> .
+
+ # Negated mathematical symbols (preserving the negation semantics)
+ # Negated symbols mapped to exclamation mark (semantically "not")
+ for cp in (0x2204, 0x2209, 0x220C, 0x2224, 0x2226, 0x226E, 0x226F, 0x2280, 0x2281, 0x2284, 0x2285):
+ overrides[cp] = ord('!') # Negated math symbols -> ! (not)
+
+ # Negated symbols mapped to hash sign (semantically "not equal")
+ for cp in (0x2241, 0x2244, 0x2249, 0x2262, 0x2268, 0x2269, 0x226D, 0x228A, 0x228B):
+ overrides[cp] = ord('#') # Negated equality symbols -> # (not equal)
+
+ # Negated arrows - all mapped to exclamation mark
+ for cp in (0x219A, 0x219B, 0x21AE, 0x21CD, 0x21CE, 0x21CF):
+ overrides[cp] = ord('!') # Negated arrows -> ! (not)
+
+ # Dashes and hyphens
+ for cp in (0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2043, 0x2052):
+ overrides[cp] = ord('-') # Dashes and hyphens -> -
+
+ # Question mark punctuation
+ for cp in (0x203D, 0x2047, 0x2048):
+ overrides[cp] = ord('?') # Question marks -> ?
+
+ # Exclamation mark punctuation
+ for cp in (0x203C, 0x2049):
+ overrides[cp] = ord('!') # Exclamation marks -> !
+
+ # Asterisk-like symbols
+ for cp in (0x2042, 0x2051, 0x2055):
+ overrides[cp] = ord('*')
+
+ # Other specific punctuation with unique mappings
+ overrides[0x201E] = ord('"') # „ DOUBLE LOW-9 QUOTATION MARK
+ overrides[0x2023] = ord('>') # ‣ TRIANGULAR BULLET
+ overrides[0x2026] = ord('.') # … HORIZONTAL ELLIPSIS
+ overrides[0x2033] = ord('"') # ″ DOUBLE PRIME
+ overrides[0x204B] = ord('P') # ⁋ REVERSED PILCROW SIGN
+ overrides[0x204C] = ord('<') # ⁌ BLACK LEFTWARDS BULLET
+ overrides[0x204D] = ord('>') # ⁍ BLACK RIGHTWARDS BULLET
+ overrides[0x204F] = ord(';') # ⁏ REVERSED SEMICOLON
+ overrides[0x205B] = ord(':') # ⁛ FOUR DOT MARK
+
+ # Check marks
+ overrides[0x2713] = ord('v') # ✓ CHECK MARK
+ overrides[0x2714] = ord('V') # ✔ HEAVY CHECK MARK
+
+ # X marks - lowercase for regular, uppercase for heavy
+ for cp in (0x2715, 0x2717):
+ overrides[cp] = ord('x') # Regular X marks -> x
+ for cp in (0x2716, 0x2718):
+ overrides[cp] = ord('X') # Heavy X marks -> X
+
+ # Stars and asterisk-like symbols mapped to '*'
+ for cp in (0x2605, 0x2606, 0x262A, 0x269D, 0x2698):
+ overrides[cp] = ord('*') # All star and asterisk symbols -> *
+ for cp in range(0x2721, 0x2746+1):
+ overrides[cp] = ord('*') # All star and asterisk symbols -> *
+ for cp in range(0x2749, 0x274B+1):
+ overrides[cp] = ord('*') # Last set of asterisk symbols -> *
+ for cp in (0x229B, 0x22C6, 0x235F, 0x2363):
+ overrides[cp] = ord('*') # Star operators -> *
+
+ # Special exclusions with fallback value of 0
+ # These will be filtered out in organize_by_pages()
+
+ # Exclude U+2028 (LINE SEPARATOR)
+ overrides[0x2028] = 0 # LINE SEPARATOR (unidecode: '\n')
+
+ # Full-width to ASCII mapping (covering all printable ASCII 33-126)
+ # 0xFF01 (!) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~)
+ # Those are excluded here to reduce the table size.
+ # It is more efficient to process them programmatically in
+ # ucs.c:ucs_get_fallback().
+ for cp in range(0xFF01, 0xFF5E + 1):
+ overrides[cp] = 0 # Double-width ASCII characters
+
+ return overrides
+
+def organize_by_pages(fallback_map):
+ """Organize the fallback mappings by their high byte (page)."""
+ # Group by high byte (page)
+ page_groups = defaultdict(list)
+ for code, fallback in fallback_map.items():
+ # Skip characters with fallback value of 0 (excluded characters)
+ if fallback == 0:
+ continue
+
+ page = code >> 8 # Get the high byte (page)
+ offset = code & 0xFF # Get the low byte (offset within page)
+ page_groups[page].append((offset, fallback))
+
+ # Sort each page's entries by offset
+ for page in page_groups:
+ page_groups[page].sort()
+
+ return page_groups
+
+def compress_ranges(page_groups):
+ """Compress consecutive entries with the same fallback character into ranges.
+ A range is only compressed if it contains 3 or more consecutive entries."""
+
+ compressed_pages = {}
+
+ for page, entries in page_groups.items():
+ compressed_entries = []
+ i = 0
+ while i < len(entries):
+ start_offset, fallback = entries[i]
+
+ # Look ahead to find consecutive entries with the same fallback
+ j = i + 1
+ while (j < len(entries) and
+ entries[j][0] == entries[j-1][0] + 1 and # consecutive offsets
+ entries[j][1] == fallback): # same fallback
+ j += 1
+
+ # Calculate the range end
+ end_offset = entries[j-1][0]
+
+ # If we found a range with 3 or more entries (worth compressing)
+ if j - i >= 3:
+ # Add a range entry
+ compressed_entries.append((start_offset, RANGE_MARKER))
+ compressed_entries.append((end_offset, fallback))
+ else:
+ # Add the individual entries as is
+ for k in range(i, j):
+ compressed_entries.append(entries[k])
+
+ i = j
+
+ compressed_pages[page] = compressed_entries
+
+ return compressed_pages
+
+def cp_name(cp):
+ """Get the Unicode character name for a code point."""
+ try:
+ return unicodedata.name(chr(cp))
+ except:
+ return f"U+{cp:04X}"
+
+def generate_fallback_tables(out_file=DEFAULT_OUT_FILE):
+ """Generate the fallback character tables."""
+ # Generate fallback map using unidecode
+ fallback_map = generate_fallback_map()
+ print(f"Generated {len(fallback_map)} total fallback mappings")
+
+ # Organize by pages
+ page_groups = organize_by_pages(fallback_map)
+ print(f"Organized into {len(page_groups)} pages")
+
+ # Compress ranges
+ compressed_pages = compress_ranges(page_groups)
+ total_compressed_entries = sum(len(entries) for entries in compressed_pages.values())
+ print(f"Total compressed entries: {total_compressed_entries}")
+
+ # Create output file
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character fallback table
+ *
+ * Auto-generated by {this_file}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ * Unidecode Version: {unidecode_version}
+ *
+ * This file contains optimized tables that map complex Unicode characters
+ * to simpler fallback characters for terminal display when corresponding
+ * glyphs are unavailable.
+ */
+
+static const struct ucs_page_desc ucs_fallback_pages[] = {{
+""")
+
+ # Convert compressed_pages to a sorted list of (page, entries) tuples
+ sorted_pages = sorted(compressed_pages.items())
+
+ # Track the start index for each page
+ start_index = 0
+
+ # Write page descriptors
+ for page, entries in sorted_pages:
+ count = len(entries)
+ f.write(f"\t{{ 0x{page:02X}, {count}, {start_index} }},\n")
+ start_index += count
+
+ # Write entries array
+ f.write("""\
+};
+
+/* Page entries array (referenced by page descriptors) */
+static const struct ucs_page_entry ucs_fallback_entries[] = {
+""")
+
+ # Write all entries
+ for page, entries in sorted_pages:
+ page_hex = f"0x{page:02X}"
+ f.write(f"\t/* Entries for page {page_hex} */\n")
+
+ for i, (offset, fallback) in enumerate(entries):
+ # Convert to hex for better readability
+ offset_hex = f"0x{offset:02X}"
+ fallback_hex = f"0x{fallback:02X}"
+
+ # Handle comments
+ codepoint = (page << 8) | offset
+
+ if fallback == RANGE_MARKER:
+ comment = f"{cp_name(codepoint)} -> ..."
+ else:
+ comment = f"{cp_name(codepoint)} -> '{chr(fallback)}'"
+ f.write(f"\t{{ 0x{offset:02X}, 0x{fallback:02X} }}, /* {comment} */\n")
+
+ f.write(f"""\
+}};
+
+#define UCS_PAGE_ENTRY_RANGE_MARKER {RANGE_MARKER}
+""")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Generate Unicode fallback character tables")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ generate_fallback_tables(out_file=args.output_file)
diff --git a/drivers/tty/vt/gen_ucs_recompose_table.py b/drivers/tty/vt/gen_ucs_recompose_table.py
new file mode 100755
index 000000000000..4434a436ac9e
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_recompose_table.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unicodedata module to generate ucs_recompose_table.h
+#
+# The generated table maps base character + combining mark pairs to their
+# precomposed equivalents.
+#
+# Usage:
+# python3 gen_ucs_recompose_table.py # Generate with common recomposition pairs
+# python3 gen_ucs_recompose_table.py --full # Generate with all recomposition pairs
+
+import unicodedata
+import sys
+import argparse
+import textwrap
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_recompose_table.h"
+
+common_recompose_description = "most commonly used Latin, Greek, and Cyrillic recomposition pairs only"
+COMMON_RECOMPOSITION_PAIRS = [
+ # Latin letters with accents - uppercase
+ (0x0041, 0x0300, 0x00C0), # A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE
+ (0x0041, 0x0301, 0x00C1), # A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE
+ (0x0041, 0x0302, 0x00C2), # A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ (0x0041, 0x0303, 0x00C3), # A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE
+ (0x0041, 0x0308, 0x00C4), # A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS
+ (0x0041, 0x030A, 0x00C5), # A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE
+ (0x0043, 0x0327, 0x00C7), # C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA
+ (0x0045, 0x0300, 0x00C8), # E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE
+ (0x0045, 0x0301, 0x00C9), # E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE
+ (0x0045, 0x0302, 0x00CA), # E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ (0x0045, 0x0308, 0x00CB), # E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS
+ (0x0049, 0x0300, 0x00CC), # I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE
+ (0x0049, 0x0301, 0x00CD), # I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE
+ (0x0049, 0x0302, 0x00CE), # I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ (0x0049, 0x0308, 0x00CF), # I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS
+ (0x004E, 0x0303, 0x00D1), # N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE
+ (0x004F, 0x0300, 0x00D2), # O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE
+ (0x004F, 0x0301, 0x00D3), # O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE
+ (0x004F, 0x0302, 0x00D4), # O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ (0x004F, 0x0303, 0x00D5), # O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE
+ (0x004F, 0x0308, 0x00D6), # O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS
+ (0x0055, 0x0300, 0x00D9), # U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE
+ (0x0055, 0x0301, 0x00DA), # U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE
+ (0x0055, 0x0302, 0x00DB), # U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ (0x0055, 0x0308, 0x00DC), # U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS
+ (0x0059, 0x0301, 0x00DD), # Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE
+
+ # Latin letters with accents - lowercase
+ (0x0061, 0x0300, 0x00E0), # a + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE
+ (0x0061, 0x0301, 0x00E1), # a + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE
+ (0x0061, 0x0302, 0x00E2), # a + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX
+ (0x0061, 0x0303, 0x00E3), # a + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE
+ (0x0061, 0x0308, 0x00E4), # a + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS
+ (0x0061, 0x030A, 0x00E5), # a + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE
+ (0x0063, 0x0327, 0x00E7), # c + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA
+ (0x0065, 0x0300, 0x00E8), # e + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE
+ (0x0065, 0x0301, 0x00E9), # e + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE
+ (0x0065, 0x0302, 0x00EA), # e + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX
+ (0x0065, 0x0308, 0x00EB), # e + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS
+ (0x0069, 0x0300, 0x00EC), # i + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE
+ (0x0069, 0x0301, 0x00ED), # i + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE
+ (0x0069, 0x0302, 0x00EE), # i + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX
+ (0x0069, 0x0308, 0x00EF), # i + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS
+ (0x006E, 0x0303, 0x00F1), # n + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE
+ (0x006F, 0x0300, 0x00F2), # o + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE
+ (0x006F, 0x0301, 0x00F3), # o + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE
+ (0x006F, 0x0302, 0x00F4), # o + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX
+ (0x006F, 0x0303, 0x00F5), # o + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE
+ (0x006F, 0x0308, 0x00F6), # o + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS
+ (0x0075, 0x0300, 0x00F9), # u + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE
+ (0x0075, 0x0301, 0x00FA), # u + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE
+ (0x0075, 0x0302, 0x00FB), # u + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX
+ (0x0075, 0x0308, 0x00FC), # u + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS
+ (0x0079, 0x0301, 0x00FD), # y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE
+ (0x0079, 0x0308, 0x00FF), # y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS
+
+ # Common Greek characters
+ (0x0391, 0x0301, 0x0386), # Α + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS
+ (0x0395, 0x0301, 0x0388), # Ε + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS
+ (0x0397, 0x0301, 0x0389), # Η + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS
+ (0x0399, 0x0301, 0x038A), # Ι + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS
+ (0x039F, 0x0301, 0x038C), # Ο + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS
+ (0x03A5, 0x0301, 0x038E), # Υ + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS
+ (0x03A9, 0x0301, 0x038F), # Ω + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS
+ (0x03B1, 0x0301, 0x03AC), # α + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS
+ (0x03B5, 0x0301, 0x03AD), # ε + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS
+ (0x03B7, 0x0301, 0x03AE), # η + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS
+ (0x03B9, 0x0301, 0x03AF), # ι + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS
+ (0x03BF, 0x0301, 0x03CC), # ο + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS
+ (0x03C5, 0x0301, 0x03CD), # υ + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS
+ (0x03C9, 0x0301, 0x03CE), # ω + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS
+
+ # Common Cyrillic characters
+ (0x0418, 0x0306, 0x0419), # И + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I
+ (0x0438, 0x0306, 0x0439), # и + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I
+ (0x0423, 0x0306, 0x040E), # У + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U
+ (0x0443, 0x0306, 0x045E), # у + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U
+]
+
+full_recompose_description = "all possible recomposition pairs from the Unicode BMP"
+def collect_all_recomposition_pairs():
+ """Collect all possible recomposition pairs from the Unicode data."""
+ # Map to store recomposition pairs: (base, combining) -> recomposed
+ recompose_map = {}
+
+ # Process all assigned Unicode code points in BMP (Basic Multilingual Plane)
+ # We limit to BMP (0x0000-0xFFFF) to keep our table smaller with uint16_t
+ for cp in range(0, 0x10000):
+ try:
+ char = chr(cp)
+
+ # Skip unassigned or control characters
+ if not unicodedata.name(char, ''):
+ continue
+
+ # Find decomposition
+ decomp = unicodedata.decomposition(char)
+ if not decomp or '<' in decomp: # Skip compatibility decompositions
+ continue
+
+ # Parse the decomposition
+ parts = decomp.split()
+ if len(parts) == 2: # Simple base + combining mark
+ base = int(parts[0], 16)
+ combining = int(parts[1], 16)
+
+ # Only store if both are in BMP
+ if base < 0x10000 and combining < 0x10000:
+ recompose_map[(base, combining)] = cp
+
+ except (ValueError, TypeError):
+ continue
+
+ # Convert to a list of tuples and sort for binary search
+ recompose_list = [(base, combining, recomposed)
+ for (base, combining), recomposed in recompose_map.items()]
+ recompose_list.sort()
+
+ return recompose_list
+
+def validate_common_pairs(full_list):
+ """Validate that all common pairs are in the full list.
+
+ Raises:
+ ValueError: If any common pair is missing or has a different recomposition
+ value than what's in the full table.
+ """
+ full_pairs = {(base, combining): recomposed for base, combining, recomposed in full_list}
+ for base, combining, recomposed in COMMON_RECOMPOSITION_PAIRS:
+ full_recomposed = full_pairs.get((base, combining))
+ if full_recomposed is None:
+ error_msg = f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) not found in full data"
+ print(error_msg)
+ raise ValueError(error_msg)
+ elif full_recomposed != recomposed:
+ error_msg = (f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) has different recomposition: "
+ f"0x{recomposed:04X} vs 0x{full_recomposed:04X}")
+ print(error_msg)
+ raise ValueError(error_msg)
+
+def generate_recomposition_table(use_full_list=False, out_file=DEFAULT_OUT_FILE):
+ """Generate the recomposition C table."""
+
+ # Collect all recomposition pairs for validation
+ full_recompose_list = collect_all_recomposition_pairs()
+
+ # Decide which list to use
+ if use_full_list:
+ print("Using full recomposition list...")
+ recompose_list = full_recompose_list
+ table_description = full_recompose_description
+ alt_list = COMMON_RECOMPOSITION_PAIRS
+ alt_description = common_recompose_description
+ else:
+ print("Using common recomposition list...")
+ # Validate that all common pairs are in the full list
+ validate_common_pairs(full_recompose_list)
+ recompose_list = sorted(COMMON_RECOMPOSITION_PAIRS)
+ table_description = common_recompose_description
+ alt_list = full_recompose_list
+ alt_description = full_recompose_description
+ generation_mode = " --full" if use_full_list else ""
+ alternative_mode = " --full" if not use_full_list else ""
+ table_description_detail = f"{table_description} ({len(recompose_list)} entries)"
+ alt_description_detail = f"{alt_description} ({len(alt_list)} entries)"
+
+ # Calculate min/max values for boundary checks
+ min_base = min(base for base, _, _ in recompose_list)
+ max_base = max(base for base, _, _ in recompose_list)
+ min_combining = min(combining for _, combining, _ in recompose_list)
+ max_combining = max(combining for _, combining, _ in recompose_list)
+
+ # Generate implementation file
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character recomposition
+ *
+ * Auto-generated by {this_file}{generation_mode}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ *
+{textwrap.fill(
+ f"This file contains a table with {table_description_detail}. " +
+ f"To generate a table with {alt_description_detail} instead, run:",
+ width=75, initial_indent=" * ", subsequent_indent=" * ")}
+ *
+ * python3 {this_file}{alternative_mode}
+ */
+
+/*
+ * Table of {table_description}
+ * Sorted by base character and then combining mark for binary search
+ */
+static const struct ucs_recomposition ucs_recomposition_table[] = {{
+""")
+
+ for base, combining, recomposed in recompose_list:
+ try:
+ base_name = unicodedata.name(chr(base))
+ combining_name = unicodedata.name(chr(combining))
+ recomposed_name = unicodedata.name(chr(recomposed))
+ comment = f"/* {base_name} + {combining_name} = {recomposed_name} */"
+ except ValueError:
+ comment = f"/* U+{base:04X} + U+{combining:04X} = U+{recomposed:04X} */"
+ f.write(f"\t{{ 0x{base:04X}, 0x{combining:04X}, 0x{recomposed:04X} }}, {comment}\n")
+
+ f.write(f"""\
+}};
+
+/*
+ * Boundary values for quick rejection
+ * These are calculated by analyzing the table during generation
+ */
+#define UCS_RECOMPOSE_MIN_BASE 0x{min_base:04X}
+#define UCS_RECOMPOSE_MAX_BASE 0x{max_base:04X}
+#define UCS_RECOMPOSE_MIN_MARK 0x{min_combining:04X}
+#define UCS_RECOMPOSE_MAX_MARK 0x{max_combining:04X}
+""")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Generate Unicode recomposition table")
+ parser.add_argument("--full", action="store_true",
+ help="Generate a full recomposition table (default: common pairs only)")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ generate_recomposition_table(use_full_list=args.full, out_file=args.output_file)
diff --git a/drivers/tty/vt/gen_ucs_width_table.py b/drivers/tty/vt/gen_ucs_width_table.py
new file mode 100755
index 000000000000..76e80ebeff13
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_width_table.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unicodedata module to generate ucs_width_table.h
+
+import unicodedata
+import sys
+import argparse
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_width_table.h"
+
+# --- Global Constants for Width Assignments ---
+
+# Known zero-width characters
+KNOWN_ZERO_WIDTH = (
+ 0x200B, # ZERO WIDTH SPACE
+ 0x200C, # ZERO WIDTH NON-JOINER
+ 0x200D, # ZERO WIDTH JOINER
+ 0x2060, # WORD JOINER
+ 0xFEFF # ZERO WIDTH NO-BREAK SPACE (BOM)
+)
+
+# Zero-width emoji modifiers and components
+# NOTE: Some of these characters would normally be single-width according to
+# East Asian Width properties, but we deliberately override them to be
+# zero-width because they function as modifiers in emoji sequences.
+EMOJI_ZERO_WIDTH = [
+ # Skin tone modifiers
+ (0x1F3FB, 0x1F3FF), # Emoji modifiers (skin tones)
+
+ # Variation selectors (note: VS16 is treated specially in vt.c)
+ (0xFE00, 0xFE0F), # Variation Selectors 1-16
+
+ # Gender and hair style modifiers
+ # These would be single-width by Unicode properties, but are zero-width
+ # when part of emoji
+ (0x2640, 0x2640), # Female sign
+ (0x2642, 0x2642), # Male sign
+ (0x26A7, 0x26A7), # Transgender symbol
+ (0x1F9B0, 0x1F9B3), # Hair components (red, curly, white, bald)
+
+ # Tag characters
+ (0xE0020, 0xE007E), # Tags
+]
+
+# Regional indicators (flag components)
+REGIONAL_INDICATORS = (0x1F1E6, 0x1F1FF) # Regional indicator symbols A-Z
+
+# Double-width emoji ranges
+#
+# Many emoji characters are classified as single-width according to Unicode
+# Standard Annex #11 East Asian Width property (N or Neutral), but we
+# deliberately override them to be double-width. References:
+# 1. Unicode Technical Standard #51: Unicode Emoji
+# (https://www.unicode.org/reports/tr51/)
+# 2. Principle of "emoji presentation" in WHATWG CSS Text specification
+# (https://drafts.csswg.org/css-text-3/#character-properties)
+# 3. Terminal emulator implementations (iTerm2, Windows Terminal, etc.) which
+# universally render emoji as double-width characters regardless of their
+# Unicode EAW property
+# 4. W3C Work Item: Requirements for Japanese Text Layout - Section 3.8.1
+# Emoji width (https://www.w3.org/TR/jlreq/)
+EMOJI_RANGES = [
+ (0x1F000, 0x1F02F), # Mahjong Tiles (EAW: N, but displayed as double-width)
+ (0x1F0A0, 0x1F0FF), # Playing Cards (EAW: N, but displayed as double-width)
+ (0x1F300, 0x1F5FF), # Miscellaneous Symbols and Pictographs
+ (0x1F600, 0x1F64F), # Emoticons
+ (0x1F680, 0x1F6FF), # Transport and Map Symbols
+ (0x1F700, 0x1F77F), # Alchemical Symbols
+ (0x1F780, 0x1F7FF), # Geometric Shapes Extended
+ (0x1F800, 0x1F8FF), # Supplemental Arrows-C
+ (0x1F900, 0x1F9FF), # Supplemental Symbols and Pictographs
+ (0x1FA00, 0x1FA6F), # Chess Symbols
+ (0x1FA70, 0x1FAFF), # Symbols and Pictographs Extended-A
+]
+
+def create_width_tables():
+ """
+ Creates Unicode character width tables and returns the data structures.
+
+ Returns:
+ tuple: (zero_width_ranges, double_width_ranges)
+ """
+
+ # Width data mapping
+ width_map = {} # Maps code points to width (0, 1, 2)
+
+ # Mark emoji modifiers as zero-width
+ for start, end in EMOJI_ZERO_WIDTH:
+ for cp in range(start, end + 1):
+ width_map[cp] = 0
+
+ # Mark all regional indicators as single-width as they are usually paired
+ # providing a combined width of 2 when displayed together.
+ start, end = REGIONAL_INDICATORS
+ for cp in range(start, end + 1):
+ width_map[cp] = 1
+
+ # Process all assigned Unicode code points (Basic Multilingual Plane +
+ # Supplementary Planes) Range 0x0 to 0x10FFFF (the full Unicode range)
+ for block_start in range(0, 0x110000, 0x1000):
+ block_end = block_start + 0x1000
+ for cp in range(block_start, block_end):
+ try:
+ char = chr(cp)
+
+ # Skip if already processed
+ if cp in width_map:
+ continue
+
+ # Check for combining marks and a format characters
+ category = unicodedata.category(char)
+
+ # Combining marks
+ if category.startswith('M'):
+ width_map[cp] = 0
+ continue
+
+ # Format characters
+ # Since we have no support for bidirectional text, all format
+ # characters (category Cf) can be treated with width 0 (zero)
+ # for simplicity, as they don't need to occupy visual space
+ # in a non-bidirectional text environment.
+ if category == 'Cf':
+ width_map[cp] = 0
+ continue
+
+ # Known zero-width characters
+ if cp in KNOWN_ZERO_WIDTH:
+ width_map[cp] = 0
+ continue
+
+ # Use East Asian Width property
+ eaw = unicodedata.east_asian_width(char)
+ if eaw in ('F', 'W'): # Fullwidth or Wide
+ width_map[cp] = 2
+ elif eaw in ('Na', 'H', 'N', 'A'): # Narrow, Halfwidth, Neutral, Ambiguous
+ width_map[cp] = 1
+ else:
+ # Default to single-width for unknown
+ width_map[cp] = 1
+
+ except (ValueError, OverflowError):
+ # Skip invalid code points
+ continue
+
+ # Process Emoji - generally double-width
+ for start, end in EMOJI_RANGES:
+ for cp in range(start, end + 1):
+ if cp not in width_map or width_map[cp] != 0: # Don't override zero-width
+ try:
+ char = chr(cp)
+ width_map[cp] = 2
+ except (ValueError, OverflowError):
+ continue
+
+ # Optimize to create range tables
+ def ranges_optimize(width_data, target_width):
+ points = sorted([cp for cp, width in width_data.items() if width == target_width])
+ if not points:
+ return []
+
+ # Group consecutive code points into ranges
+ ranges = []
+ start = points[0]
+ prev = start
+
+ for cp in points[1:]:
+ if cp > prev + 1:
+ ranges.append((start, prev))
+ start = cp
+ prev = cp
+
+ # Add the last range
+ ranges.append((start, prev))
+ return ranges
+
+ # Extract ranges for each width
+ zero_width_ranges = ranges_optimize(width_map, 0)
+ double_width_ranges = ranges_optimize(width_map, 2)
+
+ return zero_width_ranges, double_width_ranges
+
+def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FILE):
+ """
+ Write the generated tables to C header file.
+
+ Args:
+ zero_width_ranges: List of (start, end) ranges for zero-width characters
+ double_width_ranges: List of (start, end) ranges for double-width characters
+ out_file: Output file name (default: DEFAULT_OUT_FILE)
+ """
+
+ # Function to split ranges into BMP (16-bit) and non-BMP (above 16-bit)
+ def split_ranges_by_size(ranges):
+ bmp_ranges = []
+ non_bmp_ranges = []
+
+ for start, end in ranges:
+ if end <= 0xFFFF:
+ bmp_ranges.append((start, end))
+ elif start > 0xFFFF:
+ non_bmp_ranges.append((start, end))
+ else:
+ # Split the range at 0xFFFF
+ bmp_ranges.append((start, 0xFFFF))
+ non_bmp_ranges.append((0x10000, end))
+
+ return bmp_ranges, non_bmp_ranges
+
+ # Split ranges into BMP and non-BMP
+ zero_width_bmp, zero_width_non_bmp = split_ranges_by_size(zero_width_ranges)
+ double_width_bmp, double_width_non_bmp = split_ranges_by_size(double_width_ranges)
+
+ # Function to generate code point description comments
+ def get_code_point_comment(start, end):
+ try:
+ start_char_desc = unicodedata.name(chr(start))
+ if start == end:
+ return f"/* {start_char_desc} */"
+ else:
+ end_char_desc = unicodedata.name(chr(end))
+ return f"/* {start_char_desc} - {end_char_desc} */"
+ except:
+ if start == end:
+ return f"/* U+{start:04X} */"
+ else:
+ return f"/* U+{start:04X} - U+{end:04X} */"
+
+ # Generate C tables
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character width
+ *
+ * Auto-generated by {this_file}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ */
+
+/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {{
+""")
+
+ for start, end in zero_width_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Zero-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = {
+""")
+
+ for start, end in zero_width_non_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = {
+""")
+
+ for start, end in double_width_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Double-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = {
+""")
+
+ for start, end in double_width_non_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n")
+
+ f.write("};\n")
+
+if __name__ == "__main__":
+ # Parse command line arguments
+ parser = argparse.ArgumentParser(description="Generate Unicode width tables")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ # Write tables to header file
+ zero_width_ranges, double_width_ranges = create_width_tables()
+ write_tables(zero_width_ranges, double_width_ranges, out_file=args.output_file)
+
+ # Print summary
+ zero_width_count = sum(end - start + 1 for start, end in zero_width_ranges)
+ double_width_count = sum(end - start + 1 for start, end in double_width_ranges)
+ print(f"Generated {args.output_file} with:")
+ print(f"- {len(zero_width_ranges)} zero-width ranges covering ~{zero_width_count} code points")
+ print(f"- {len(double_width_ranges)} double-width ranges covering ~{double_width_count} code points")
+ print(f"- Unicode Version: {unicodedata.unidata_version}")
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index ae92e6a50a65..dc585079c2fb 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -376,6 +376,17 @@ static void to_utf8(struct vc_data *vc, uint c)
}
}
+static void put_queue_utf8(struct vc_data *vc, u32 value)
+{
+ if (kbd->kbdmode == VC_UNICODE)
+ to_utf8(vc, value);
+ else {
+ int c = conv_uni_to_8bit(value);
+ if (c != -1)
+ put_queue(vc, c);
+ }
+}
+
/* FIXME: review locking for vt.c callers */
static void set_leds(void)
{
@@ -454,13 +465,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
return d;
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, d);
- else {
- int c = conv_uni_to_8bit(d);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, d);
return ch;
}
@@ -471,13 +476,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
static void fn_enter(struct vc_data *vc)
{
if (diacr) {
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, diacr);
- else {
- int c = conv_uni_to_8bit(diacr);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, diacr);
diacr = 0;
}
@@ -685,13 +684,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
diacr = value;
return;
}
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, value);
- else {
- int c = conv_uni_to_8bit(value);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, value);
}
/*
@@ -1519,7 +1512,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT)
return;
- (*k_handler[type])(vc, keysym & 0xff, !down);
+ (*k_handler[type])(vc, KVAL(keysym), !down);
param.ledstate = kbd->ledflagstate;
atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 791e2f1f7c0b..24b0a53e5a79 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -403,6 +403,12 @@ int paste_selection(struct tty_struct *tty)
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+ bool bp = vc->vc_bracketed_paste;
+ static const char bracketed_paste_start[] = "\033[200~";
+ static const char bracketed_paste_end[] = "\033[201~";
+ const char *bps = bp ? bracketed_paste_start : NULL;
+ const char *bpe = bp ? bracketed_paste_end : NULL;
+
console_lock();
poke_blanked_console();
console_unlock();
@@ -414,7 +420,7 @@ int paste_selection(struct tty_struct *tty)
add_wait_queue(&vc->paste_wait, &wait);
mutex_lock(&vc_sel.lock);
- while (vc_sel.buffer && vc_sel.buf_len > pasted) {
+ while (vc_sel.buffer && (vc_sel.buf_len > pasted || bpe)) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
ret = -EINTR;
@@ -427,10 +433,27 @@ int paste_selection(struct tty_struct *tty)
continue;
}
__set_current_state(TASK_RUNNING);
+
+ if (bps) {
+ bps += tty_ldisc_receive_buf(ld, bps, NULL, strlen(bps));
+ if (*bps != '\0')
+ continue;
+ bps = NULL;
+ }
+
count = vc_sel.buf_len - pasted;
- count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
- count);
- pasted += count;
+ if (count) {
+ pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted,
+ NULL, count);
+ if (vc_sel.buf_len > pasted)
+ continue;
+ }
+
+ if (bpe) {
+ bpe += tty_ldisc_receive_buf(ld, bpe, NULL, strlen(bpe));
+ if (*bpe == '\0')
+ bpe = NULL;
+ }
}
mutex_unlock(&vc_sel.lock);
remove_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/tty/vt/ucs.c b/drivers/tty/vt/ucs.c
new file mode 100644
index 000000000000..6ead622b7713
--- /dev/null
+++ b/drivers/tty/vt/ucs.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ucs.c - Universal Character Set processing
+ */
+
+#include <linux/array_size.h>
+#include <linux/bsearch.h>
+#include <linux/consolemap.h>
+#include <linux/minmax.h>
+
+struct ucs_interval16 {
+ u16 first;
+ u16 last;
+};
+
+struct ucs_interval32 {
+ u32 first;
+ u32 last;
+};
+
+#include "ucs_width_table.h"
+
+static int interval16_cmp(const void *key, const void *element)
+{
+ u16 cp = *(u16 *)key;
+ const struct ucs_interval16 *entry = element;
+
+ if (cp < entry->first)
+ return -1;
+ if (cp > entry->last)
+ return 1;
+ return 0;
+}
+
+static int interval32_cmp(const void *key, const void *element)
+{
+ u32 cp = *(u32 *)key;
+ const struct ucs_interval32 *entry = element;
+
+ if (cp < entry->first)
+ return -1;
+ if (cp > entry->last)
+ return 1;
+ return 0;
+}
+
+static bool cp_in_range16(u16 cp, const struct ucs_interval16 *ranges, size_t size)
+{
+ if (cp < ranges[0].first || cp > ranges[size - 1].last)
+ return false;
+
+ return __inline_bsearch(&cp, ranges, size, sizeof(*ranges),
+ interval16_cmp) != NULL;
+}
+
+static bool cp_in_range32(u32 cp, const struct ucs_interval32 *ranges, size_t size)
+{
+ if (cp < ranges[0].first || cp > ranges[size - 1].last)
+ return false;
+
+ return __inline_bsearch(&cp, ranges, size, sizeof(*ranges),
+ interval32_cmp) != NULL;
+}
+
+#define UCS_IS_BMP(cp) ((cp) <= 0xffff)
+
+/**
+ * ucs_is_zero_width() - Determine if a Unicode code point is zero-width.
+ * @cp: Unicode code point (UCS-4)
+ *
+ * Return: true if the character is zero-width, false otherwise
+ */
+bool ucs_is_zero_width(u32 cp)
+{
+ if (UCS_IS_BMP(cp))
+ return cp_in_range16(cp, ucs_zero_width_bmp_ranges,
+ ARRAY_SIZE(ucs_zero_width_bmp_ranges));
+ else
+ return cp_in_range32(cp, ucs_zero_width_non_bmp_ranges,
+ ARRAY_SIZE(ucs_zero_width_non_bmp_ranges));
+}
+
+/**
+ * ucs_is_double_width() - Determine if a Unicode code point is double-width.
+ * @cp: Unicode code point (UCS-4)
+ *
+ * Return: true if the character is double-width, false otherwise
+ */
+bool ucs_is_double_width(u32 cp)
+{
+ if (UCS_IS_BMP(cp))
+ return cp_in_range16(cp, ucs_double_width_bmp_ranges,
+ ARRAY_SIZE(ucs_double_width_bmp_ranges));
+ else
+ return cp_in_range32(cp, ucs_double_width_non_bmp_ranges,
+ ARRAY_SIZE(ucs_double_width_non_bmp_ranges));
+}
+
+/*
+ * Structure for base with combining mark pairs and resulting recompositions.
+ * Using u16 to save space since all values are within BMP range.
+ */
+struct ucs_recomposition {
+ u16 base; /* base character */
+ u16 mark; /* combining mark */
+ u16 recomposed; /* corresponding recomposed character */
+};
+
+#include "ucs_recompose_table.h"
+
+struct compare_key {
+ u16 base;
+ u16 mark;
+};
+
+static int recomposition_cmp(const void *key, const void *element)
+{
+ const struct compare_key *search_key = key;
+ const struct ucs_recomposition *entry = element;
+
+ /* Compare base character first */
+ if (search_key->base < entry->base)
+ return -1;
+ if (search_key->base > entry->base)
+ return 1;
+
+ /* Base characters match, now compare combining character */
+ if (search_key->mark < entry->mark)
+ return -1;
+ if (search_key->mark > entry->mark)
+ return 1;
+
+ /* Both match */
+ return 0;
+}
+
+/**
+ * ucs_recompose() - Attempt to recompose two Unicode characters into a single character.
+ * @base: Base Unicode code point (UCS-4)
+ * @mark: Combining mark Unicode code point (UCS-4)
+ *
+ * Return: Recomposed Unicode code point, or 0 if no recomposition is possible
+ */
+u32 ucs_recompose(u32 base, u32 mark)
+{
+ /* Check if characters are within the range of our table */
+ if (base < UCS_RECOMPOSE_MIN_BASE || base > UCS_RECOMPOSE_MAX_BASE ||
+ mark < UCS_RECOMPOSE_MIN_MARK || mark > UCS_RECOMPOSE_MAX_MARK)
+ return 0;
+
+ struct compare_key key = { base, mark };
+ struct ucs_recomposition *result =
+ __inline_bsearch(&key, ucs_recomposition_table,
+ ARRAY_SIZE(ucs_recomposition_table),
+ sizeof(*ucs_recomposition_table),
+ recomposition_cmp);
+
+ return result ? result->recomposed : 0;
+}
+
+/*
+ * The fallback table structures implement a 2-level lookup.
+ */
+
+struct ucs_page_desc {
+ u8 page; /* Page index (high byte of code points) */
+ u8 count; /* Number of entries in this page */
+ u16 start; /* Start index in entries array */
+};
+
+struct ucs_page_entry {
+ u8 offset; /* Offset within page (0-255) */
+ u8 fallback; /* Fallback character or range start marker */
+};
+
+#include "ucs_fallback_table.h"
+
+static int ucs_page_desc_cmp(const void *key, const void *element)
+{
+ u8 page = *(u8 *)key;
+ const struct ucs_page_desc *entry = element;
+
+ if (page < entry->page)
+ return -1;
+ if (page > entry->page)
+ return 1;
+ return 0;
+}
+
+static int ucs_page_entry_cmp(const void *key, const void *element)
+{
+ u8 offset = *(u8 *)key;
+ const struct ucs_page_entry *entry = element;
+
+ if (offset < entry->offset)
+ return -1;
+ if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER) {
+ if (offset > entry[1].offset)
+ return 1;
+ } else {
+ if (offset > entry->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * ucs_get_fallback() - Get a substitution for the provided Unicode character
+ * @base: Base Unicode code point (UCS-4)
+ *
+ * Get a simpler fallback character for the provided Unicode character.
+ * This is used for terminal display when corresponding glyph is unavailable.
+ * The substitution may not be as good as the actual glyph for the original
+ * character but still way more helpful than a squared question mark.
+ *
+ * Return: Fallback Unicode code point, or 0 if none is available
+ */
+u32 ucs_get_fallback(u32 cp)
+{
+ const struct ucs_page_desc *page;
+ const struct ucs_page_entry *entry;
+ u8 page_idx = cp >> 8, offset = cp;
+
+ if (!UCS_IS_BMP(cp))
+ return 0;
+
+ /*
+ * Full-width to ASCII mapping (covering all printable ASCII 33-126)
+ * 0xFF01 (!) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~)
+ * We process them programmatically to reduce the table size.
+ */
+ if (cp >= 0xFF01 && cp <= 0xFF5E)
+ return cp - 0xFF01 + 33;
+
+ page = __inline_bsearch(&page_idx, ucs_fallback_pages,
+ ARRAY_SIZE(ucs_fallback_pages),
+ sizeof(*ucs_fallback_pages),
+ ucs_page_desc_cmp);
+ if (!page)
+ return 0;
+
+ entry = __inline_bsearch(&offset, ucs_fallback_entries + page->start,
+ page->count, sizeof(*ucs_fallback_entries),
+ ucs_page_entry_cmp);
+ if (!entry)
+ return 0;
+
+ if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER)
+ entry++;
+ return entry->fallback;
+}
diff --git a/drivers/tty/vt/ucs_fallback_table.h_shipped b/drivers/tty/vt/ucs_fallback_table.h_shipped
new file mode 100644
index 000000000000..2da5a8fe1cf1
--- /dev/null
+++ b/drivers/tty/vt/ucs_fallback_table.h_shipped
@@ -0,0 +1,3346 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_fallback_table.h - Unicode character fallback table
+ *
+ * Auto-generated by gen_ucs_fallback_table.py
+ *
+ * Unicode Version: 16.0.0
+ * Unidecode Version: 1.3.8
+ *
+ * This file contains optimized tables that map complex Unicode characters
+ * to simpler fallback characters for terminal display when corresponding
+ * glyphs are unavailable.
+ */
+
+static const struct ucs_page_desc ucs_fallback_pages[] = {
+ { 0x00, 62, 0 },
+ { 0x01, 218, 62 },
+ { 0x02, 196, 280 },
+ { 0x03, 96, 476 },
+ { 0x04, 113, 572 },
+ { 0x05, 100, 685 },
+ { 0x06, 119, 785 },
+ { 0x07, 91, 904 },
+ { 0x09, 99, 995 },
+ { 0x0A, 78, 1094 },
+ { 0x0B, 79, 1172 },
+ { 0x0C, 85, 1251 },
+ { 0x0D, 73, 1336 },
+ { 0x0E, 83, 1409 },
+ { 0x0F, 69, 1492 },
+ { 0x10, 93, 1561 },
+ { 0x11, 51, 1654 },
+ { 0x13, 22, 1705 },
+ { 0x14, 30, 1727 },
+ { 0x15, 17, 1757 },
+ { 0x16, 81, 1774 },
+ { 0x17, 47, 1855 },
+ { 0x18, 96, 1902 },
+ { 0x1D, 105, 1998 },
+ { 0x1E, 246, 2103 },
+ { 0x1F, 94, 2349 },
+ { 0x20, 107, 2443 },
+ { 0x21, 136, 2550 },
+ { 0x22, 34, 2686 },
+ { 0x23, 4, 2720 },
+ { 0x24, 72, 2724 },
+ { 0x25, 60, 2796 },
+ { 0x26, 6, 2856 },
+ { 0x27, 18, 2862 },
+ { 0x28, 64, 2880 },
+ { 0x29, 1, 2944 },
+ { 0x2C, 15, 2945 },
+ { 0x2E, 29, 2960 },
+ { 0x30, 53, 2989 },
+ { 0x31, 50, 3042 },
+ { 0x32, 5, 3092 },
+ { 0xA0, 4, 3097 },
+ { 0xC5, 2, 3101 },
+ { 0xC6, 2, 3103 },
+ { 0xC7, 1, 3105 },
+ { 0xFB, 35, 3106 },
+ { 0xFE, 37, 3141 },
+ { 0xFF, 50, 3178 },
+};
+
+/* Page entries array (referenced by page descriptors) */
+static const struct ucs_page_entry ucs_fallback_entries[] = {
+ /* Entries for page 0x00 */
+ { 0xA0, 0x20 }, /* NO-BREAK SPACE -> ' ' */
+ { 0xA1, 0x21 }, /* INVERTED EXCLAMATION MARK -> '!' */
+ { 0xA2, 0x63 }, /* CENT SIGN -> 'c' */
+ { 0xA3, 0x4C }, /* POUND SIGN -> 'L' */
+ { 0xA5, 0x59 }, /* YEN SIGN -> 'Y' */
+ { 0xA6, 0x7C }, /* BROKEN BAR -> '|' */
+ { 0xA7, 0x53 }, /* SECTION SIGN -> 'S' */
+ { 0xA8, 0x22 }, /* DIAERESIS -> '"' */
+ { 0xA9, 0x43 }, /* COPYRIGHT SIGN -> 'C' */
+ { 0xAA, 0x61 }, /* FEMININE ORDINAL INDICATOR -> 'a' */
+ { 0xAB, 0x3C }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> '<' */
+ { 0xAC, 0x21 }, /* NOT SIGN -> '!' */
+ { 0xAE, 0x52 }, /* REGISTERED SIGN -> 'R' */
+ { 0xAF, 0x2D }, /* MACRON -> '-' */
+ { 0xB0, 0x6F }, /* DEGREE SIGN -> 'o' */
+ { 0xB2, 0x32 }, /* SUPERSCRIPT TWO -> '2' */
+ { 0xB3, 0x33 }, /* SUPERSCRIPT THREE -> '3' */
+ { 0xB4, 0x27 }, /* ACUTE ACCENT -> ''' */
+ { 0xB5, 0x75 }, /* MICRO SIGN -> 'u' */
+ { 0xB6, 0x50 }, /* PILCROW SIGN -> 'P' */
+ { 0xB7, 0x2A }, /* MIDDLE DOT -> '*' */
+ { 0xB8, 0x2C }, /* CEDILLA -> ',' */
+ { 0xB9, 0x31 }, /* SUPERSCRIPT ONE -> '1' */
+ { 0xBA, 0x6F }, /* MASCULINE ORDINAL INDICATOR -> 'o' */
+ { 0xBB, 0x3E }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> '>' */
+ { 0xBF, 0x3F }, /* INVERTED QUESTION MARK -> '?' */
+ { 0xC0, 0x00 }, /* LATIN CAPITAL LETTER A WITH GRAVE -> ... */
+ { 0xC5, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE -> 'A' */
+ { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER AE -> 'E' */
+ { 0xC7, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA -> 'C' */
+ { 0xC8, 0x00 }, /* LATIN CAPITAL LETTER E WITH GRAVE -> ... */
+ { 0xCB, 0x45 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS -> 'E' */
+ { 0xCC, 0x00 }, /* LATIN CAPITAL LETTER I WITH GRAVE -> ... */
+ { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS -> 'I' */
+ { 0xD0, 0x44 }, /* LATIN CAPITAL LETTER ETH -> 'D' */
+ { 0xD1, 0x4E }, /* LATIN CAPITAL LETTER N WITH TILDE -> 'N' */
+ { 0xD2, 0x00 }, /* LATIN CAPITAL LETTER O WITH GRAVE -> ... */
+ { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS -> 'O' */
+ { 0xD7, 0x78 }, /* MULTIPLICATION SIGN -> 'x' */
+ { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE -> 'O' */
+ { 0xD9, 0x00 }, /* LATIN CAPITAL LETTER U WITH GRAVE -> ... */
+ { 0xDC, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS -> 'U' */
+ { 0xDD, 0x59 }, /* LATIN CAPITAL LETTER Y WITH ACUTE -> 'Y' */
+ { 0xDF, 0x73 }, /* LATIN SMALL LETTER SHARP S -> 's' */
+ { 0xE0, 0x00 }, /* LATIN SMALL LETTER A WITH GRAVE -> ... */
+ { 0xE5, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE -> 'a' */
+ { 0xE6, 0x65 }, /* LATIN SMALL LETTER AE -> 'e' */
+ { 0xE7, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA -> 'c' */
+ { 0xE8, 0x00 }, /* LATIN SMALL LETTER E WITH GRAVE -> ... */
+ { 0xEB, 0x65 }, /* LATIN SMALL LETTER E WITH DIAERESIS -> 'e' */
+ { 0xEC, 0x00 }, /* LATIN SMALL LETTER I WITH GRAVE -> ... */
+ { 0xEF, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS -> 'i' */
+ { 0xF0, 0x64 }, /* LATIN SMALL LETTER ETH -> 'd' */
+ { 0xF1, 0x6E }, /* LATIN SMALL LETTER N WITH TILDE -> 'n' */
+ { 0xF2, 0x00 }, /* LATIN SMALL LETTER O WITH GRAVE -> ... */
+ { 0xF6, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS -> 'o' */
+ { 0xF7, 0x2F }, /* DIVISION SIGN -> '/' */
+ { 0xF8, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE -> 'o' */
+ { 0xF9, 0x00 }, /* LATIN SMALL LETTER U WITH GRAVE -> ... */
+ { 0xFC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS -> 'u' */
+ { 0xFD, 0x79 }, /* LATIN SMALL LETTER Y WITH ACUTE -> 'y' */
+ { 0xFF, 0x79 }, /* LATIN SMALL LETTER Y WITH DIAERESIS -> 'y' */
+ /* Entries for page 0x01 */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH MACRON -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH MACRON -> 'a' */
+ { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE -> 'A' */
+ { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE -> 'a' */
+ { 0x04, 0x41 }, /* LATIN CAPITAL LETTER A WITH OGONEK -> 'A' */
+ { 0x05, 0x61 }, /* LATIN SMALL LETTER A WITH OGONEK -> 'a' */
+ { 0x06, 0x43 }, /* LATIN CAPITAL LETTER C WITH ACUTE -> 'C' */
+ { 0x07, 0x63 }, /* LATIN SMALL LETTER C WITH ACUTE -> 'c' */
+ { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX -> 'C' */
+ { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX -> 'c' */
+ { 0x0A, 0x43 }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE -> 'C' */
+ { 0x0B, 0x63 }, /* LATIN SMALL LETTER C WITH DOT ABOVE -> 'c' */
+ { 0x0C, 0x43 }, /* LATIN CAPITAL LETTER C WITH CARON -> 'C' */
+ { 0x0D, 0x63 }, /* LATIN SMALL LETTER C WITH CARON -> 'c' */
+ { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH CARON -> 'D' */
+ { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH CARON -> 'd' */
+ { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH STROKE -> 'D' */
+ { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH STROKE -> 'd' */
+ { 0x12, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON -> 'E' */
+ { 0x13, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON -> 'e' */
+ { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH BREVE -> 'E' */
+ { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH BREVE -> 'e' */
+ { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE -> 'E' */
+ { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH DOT ABOVE -> 'e' */
+ { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH OGONEK -> 'E' */
+ { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH OGONEK -> 'e' */
+ { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH CARON -> 'E' */
+ { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH CARON -> 'e' */
+ { 0x1C, 0x47 }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX -> 'G' */
+ { 0x1D, 0x67 }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX -> 'g' */
+ { 0x1E, 0x47 }, /* LATIN CAPITAL LETTER G WITH BREVE -> 'G' */
+ { 0x1F, 0x67 }, /* LATIN SMALL LETTER G WITH BREVE -> 'g' */
+ { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE -> 'G' */
+ { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH DOT ABOVE -> 'g' */
+ { 0x22, 0x47 }, /* LATIN CAPITAL LETTER G WITH CEDILLA -> 'G' */
+ { 0x23, 0x67 }, /* LATIN SMALL LETTER G WITH CEDILLA -> 'g' */
+ { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX -> 'H' */
+ { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX -> 'h' */
+ { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH STROKE -> 'H' */
+ { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH STROKE -> 'h' */
+ { 0x28, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE -> 'I' */
+ { 0x29, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE -> 'i' */
+ { 0x2A, 0x49 }, /* LATIN CAPITAL LETTER I WITH MACRON -> 'I' */
+ { 0x2B, 0x69 }, /* LATIN SMALL LETTER I WITH MACRON -> 'i' */
+ { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH BREVE -> 'I' */
+ { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH BREVE -> 'i' */
+ { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH OGONEK -> 'I' */
+ { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH OGONEK -> 'i' */
+ { 0x30, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE -> 'I' */
+ { 0x31, 0x69 }, /* LATIN SMALL LETTER DOTLESS I -> 'i' */
+ { 0x34, 0x4A }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX -> 'J' */
+ { 0x35, 0x6A }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX -> 'j' */
+ { 0x36, 0x4B }, /* LATIN CAPITAL LETTER K WITH CEDILLA -> 'K' */
+ { 0x37, 0x6B }, /* LATIN SMALL LETTER K WITH CEDILLA -> 'k' */
+ { 0x38, 0x6B }, /* LATIN SMALL LETTER KRA -> 'k' */
+ { 0x39, 0x4C }, /* LATIN CAPITAL LETTER L WITH ACUTE -> 'L' */
+ { 0x3A, 0x6C }, /* LATIN SMALL LETTER L WITH ACUTE -> 'l' */
+ { 0x3B, 0x4C }, /* LATIN CAPITAL LETTER L WITH CEDILLA -> 'L' */
+ { 0x3C, 0x6C }, /* LATIN SMALL LETTER L WITH CEDILLA -> 'l' */
+ { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH CARON -> 'L' */
+ { 0x3E, 0x6C }, /* LATIN SMALL LETTER L WITH CARON -> 'l' */
+ { 0x3F, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT -> 'L' */
+ { 0x40, 0x6C }, /* LATIN SMALL LETTER L WITH MIDDLE DOT -> 'l' */
+ { 0x41, 0x4C }, /* LATIN CAPITAL LETTER L WITH STROKE -> 'L' */
+ { 0x42, 0x6C }, /* LATIN SMALL LETTER L WITH STROKE -> 'l' */
+ { 0x43, 0x4E }, /* LATIN CAPITAL LETTER N WITH ACUTE -> 'N' */
+ { 0x44, 0x6E }, /* LATIN SMALL LETTER N WITH ACUTE -> 'n' */
+ { 0x45, 0x4E }, /* LATIN CAPITAL LETTER N WITH CEDILLA -> 'N' */
+ { 0x46, 0x6E }, /* LATIN SMALL LETTER N WITH CEDILLA -> 'n' */
+ { 0x47, 0x4E }, /* LATIN CAPITAL LETTER N WITH CARON -> 'N' */
+ { 0x48, 0x6E }, /* LATIN SMALL LETTER N WITH CARON -> 'n' */
+ { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON -> 'O' */
+ { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON -> 'o' */
+ { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH BREVE -> 'O' */
+ { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH BREVE -> 'o' */
+ { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -> 'O' */
+ { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE -> 'o' */
+ { 0x52, 0x45 }, /* LATIN CAPITAL LIGATURE OE -> 'E' */
+ { 0x53, 0x65 }, /* LATIN SMALL LIGATURE OE -> 'e' */
+ { 0x54, 0x52 }, /* LATIN CAPITAL LETTER R WITH ACUTE -> 'R' */
+ { 0x55, 0x72 }, /* LATIN SMALL LETTER R WITH ACUTE -> 'r' */
+ { 0x56, 0x52 }, /* LATIN CAPITAL LETTER R WITH CEDILLA -> 'R' */
+ { 0x57, 0x72 }, /* LATIN SMALL LETTER R WITH CEDILLA -> 'r' */
+ { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH CARON -> 'R' */
+ { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH CARON -> 'r' */
+ { 0x5A, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE -> 'S' */
+ { 0x5B, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE -> 's' */
+ { 0x5C, 0x53 }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX -> 'S' */
+ { 0x5D, 0x73 }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX -> 's' */
+ { 0x5E, 0x53 }, /* LATIN CAPITAL LETTER S WITH CEDILLA -> 'S' */
+ { 0x5F, 0x73 }, /* LATIN SMALL LETTER S WITH CEDILLA -> 's' */
+ { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON -> 'S' */
+ { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH CARON -> 's' */
+ { 0x62, 0x54 }, /* LATIN CAPITAL LETTER T WITH CEDILLA -> 'T' */
+ { 0x63, 0x74 }, /* LATIN SMALL LETTER T WITH CEDILLA -> 't' */
+ { 0x64, 0x54 }, /* LATIN CAPITAL LETTER T WITH CARON -> 'T' */
+ { 0x65, 0x74 }, /* LATIN SMALL LETTER T WITH CARON -> 't' */
+ { 0x66, 0x54 }, /* LATIN CAPITAL LETTER T WITH STROKE -> 'T' */
+ { 0x67, 0x74 }, /* LATIN SMALL LETTER T WITH STROKE -> 't' */
+ { 0x68, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE -> 'U' */
+ { 0x69, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE -> 'u' */
+ { 0x6A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON -> 'U' */
+ { 0x6B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON -> 'u' */
+ { 0x6C, 0x55 }, /* LATIN CAPITAL LETTER U WITH BREVE -> 'U' */
+ { 0x6D, 0x75 }, /* LATIN SMALL LETTER U WITH BREVE -> 'u' */
+ { 0x6E, 0x55 }, /* LATIN CAPITAL LETTER U WITH RING ABOVE -> 'U' */
+ { 0x6F, 0x75 }, /* LATIN SMALL LETTER U WITH RING ABOVE -> 'u' */
+ { 0x70, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */
+ { 0x71, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */
+ { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH OGONEK -> 'U' */
+ { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH OGONEK -> 'u' */
+ { 0x74, 0x57 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX -> 'W' */
+ { 0x75, 0x77 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX -> 'w' */
+ { 0x76, 0x59 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -> 'Y' */
+ { 0x77, 0x79 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX -> 'y' */
+ { 0x78, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS -> 'Y' */
+ { 0x79, 0x5A }, /* LATIN CAPITAL LETTER Z WITH ACUTE -> 'Z' */
+ { 0x7A, 0x7A }, /* LATIN SMALL LETTER Z WITH ACUTE -> 'z' */
+ { 0x7B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE -> 'Z' */
+ { 0x7C, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT ABOVE -> 'z' */
+ { 0x7D, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CARON -> 'Z' */
+ { 0x7E, 0x7A }, /* LATIN SMALL LETTER Z WITH CARON -> 'z' */
+ { 0x7F, 0x73 }, /* LATIN SMALL LETTER LONG S -> 's' */
+ { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH STROKE -> 'b' */
+ { 0x81, 0x42 }, /* LATIN CAPITAL LETTER B WITH HOOK -> 'B' */
+ { 0x82, 0x42 }, /* LATIN CAPITAL LETTER B WITH TOPBAR -> 'B' */
+ { 0x83, 0x62 }, /* LATIN SMALL LETTER B WITH TOPBAR -> 'b' */
+ { 0x84, 0x36 }, /* LATIN CAPITAL LETTER TONE SIX -> '6' */
+ { 0x85, 0x36 }, /* LATIN SMALL LETTER TONE SIX -> '6' */
+ { 0x86, 0x4F }, /* LATIN CAPITAL LETTER OPEN O -> 'O' */
+ { 0x87, 0x43 }, /* LATIN CAPITAL LETTER C WITH HOOK -> 'C' */
+ { 0x88, 0x63 }, /* LATIN SMALL LETTER C WITH HOOK -> 'c' */
+ { 0x89, 0x00 }, /* LATIN CAPITAL LETTER AFRICAN D -> ... */
+ { 0x8B, 0x44 }, /* LATIN CAPITAL LETTER D WITH TOPBAR -> 'D' */
+ { 0x8C, 0x64 }, /* LATIN SMALL LETTER D WITH TOPBAR -> 'd' */
+ { 0x8D, 0x64 }, /* LATIN SMALL LETTER TURNED DELTA -> 'd' */
+ { 0x8E, 0x33 }, /* LATIN CAPITAL LETTER REVERSED E -> '3' */
+ { 0x8F, 0x40 }, /* LATIN CAPITAL LETTER SCHWA -> '@' */
+ { 0x90, 0x45 }, /* LATIN CAPITAL LETTER OPEN E -> 'E' */
+ { 0x91, 0x46 }, /* LATIN CAPITAL LETTER F WITH HOOK -> 'F' */
+ { 0x92, 0x66 }, /* LATIN SMALL LETTER F WITH HOOK -> 'f' */
+ { 0x93, 0x47 }, /* LATIN CAPITAL LETTER G WITH HOOK -> 'G' */
+ { 0x94, 0x47 }, /* LATIN CAPITAL LETTER GAMMA -> 'G' */
+ { 0x96, 0x49 }, /* LATIN CAPITAL LETTER IOTA -> 'I' */
+ { 0x97, 0x49 }, /* LATIN CAPITAL LETTER I WITH STROKE -> 'I' */
+ { 0x98, 0x4B }, /* LATIN CAPITAL LETTER K WITH HOOK -> 'K' */
+ { 0x99, 0x6B }, /* LATIN SMALL LETTER K WITH HOOK -> 'k' */
+ { 0x9A, 0x6C }, /* LATIN SMALL LETTER L WITH BAR -> 'l' */
+ { 0x9B, 0x6C }, /* LATIN SMALL LETTER LAMBDA WITH STROKE -> 'l' */
+ { 0x9C, 0x57 }, /* LATIN CAPITAL LETTER TURNED M -> 'W' */
+ { 0x9D, 0x4E }, /* LATIN CAPITAL LETTER N WITH LEFT HOOK -> 'N' */
+ { 0x9E, 0x6E }, /* LATIN SMALL LETTER N WITH LONG RIGHT LEG -> 'n' */
+ { 0x9F, 0x4F }, /* LATIN CAPITAL LETTER O WITH MIDDLE TILDE -> 'O' */
+ { 0xA0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN -> 'O' */
+ { 0xA1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN -> 'o' */
+ { 0xA4, 0x50 }, /* LATIN CAPITAL LETTER P WITH HOOK -> 'P' */
+ { 0xA5, 0x70 }, /* LATIN SMALL LETTER P WITH HOOK -> 'p' */
+ { 0xA7, 0x32 }, /* LATIN CAPITAL LETTER TONE TWO -> '2' */
+ { 0xA8, 0x32 }, /* LATIN SMALL LETTER TONE TWO -> '2' */
+ { 0xAB, 0x74 }, /* LATIN SMALL LETTER T WITH PALATAL HOOK -> 't' */
+ { 0xAC, 0x54 }, /* LATIN CAPITAL LETTER T WITH HOOK -> 'T' */
+ { 0xAD, 0x74 }, /* LATIN SMALL LETTER T WITH HOOK -> 't' */
+ { 0xAE, 0x54 }, /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK -> 'T' */
+ { 0xAF, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN -> 'U' */
+ { 0xB0, 0x75 }, /* LATIN SMALL LETTER U WITH HORN -> 'u' */
+ { 0xB1, 0x59 }, /* LATIN CAPITAL LETTER UPSILON -> 'Y' */
+ { 0xB2, 0x56 }, /* LATIN CAPITAL LETTER V WITH HOOK -> 'V' */
+ { 0xB3, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK -> 'Y' */
+ { 0xB4, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK -> 'y' */
+ { 0xB5, 0x5A }, /* LATIN CAPITAL LETTER Z WITH STROKE -> 'Z' */
+ { 0xB6, 0x7A }, /* LATIN SMALL LETTER Z WITH STROKE -> 'z' */
+ { 0xBB, 0x32 }, /* LATIN LETTER TWO WITH STROKE -> '2' */
+ { 0xBC, 0x35 }, /* LATIN CAPITAL LETTER TONE FIVE -> '5' */
+ { 0xBD, 0x35 }, /* LATIN SMALL LETTER TONE FIVE -> '5' */
+ { 0xBF, 0x77 }, /* LATIN LETTER WYNN -> 'w' */
+ { 0xC0, 0x7C }, /* LATIN LETTER DENTAL CLICK -> '|' */
+ { 0xC3, 0x21 }, /* LATIN LETTER RETROFLEX CLICK -> '!' */
+ { 0xCD, 0x41 }, /* LATIN CAPITAL LETTER A WITH CARON -> 'A' */
+ { 0xCE, 0x61 }, /* LATIN SMALL LETTER A WITH CARON -> 'a' */
+ { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH CARON -> 'I' */
+ { 0xD0, 0x69 }, /* LATIN SMALL LETTER I WITH CARON -> 'i' */
+ { 0xD1, 0x4F }, /* LATIN CAPITAL LETTER O WITH CARON -> 'O' */
+ { 0xD2, 0x6F }, /* LATIN SMALL LETTER O WITH CARON -> 'o' */
+ { 0xD3, 0x55 }, /* LATIN CAPITAL LETTER U WITH CARON -> 'U' */
+ { 0xD4, 0x75 }, /* LATIN SMALL LETTER U WITH CARON -> 'u' */
+ { 0xD5, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON -> 'U' */
+ { 0xD6, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND MACRON -> 'u' */
+ { 0xD7, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE -> 'U' */
+ { 0xD8, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE -> 'u' */
+ { 0xD9, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON -> 'U' */
+ { 0xDA, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND CARON -> 'u' */
+ { 0xDB, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE -> 'U' */
+ { 0xDC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE -> 'u' */
+ { 0xDD, 0x40 }, /* LATIN SMALL LETTER TURNED E -> '@' */
+ { 0xDE, 0x41 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON -> 'A' */
+ { 0xDF, 0x61 }, /* LATIN SMALL LETTER A WITH DIAERESIS AND MACRON -> 'a' */
+ { 0xE0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON -> 'A' */
+ { 0xE1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON -> 'a' */
+ { 0xE4, 0x47 }, /* LATIN CAPITAL LETTER G WITH STROKE -> 'G' */
+ { 0xE5, 0x67 }, /* LATIN SMALL LETTER G WITH STROKE -> 'g' */
+ { 0xE6, 0x47 }, /* LATIN CAPITAL LETTER G WITH CARON -> 'G' */
+ { 0xE7, 0x67 }, /* LATIN SMALL LETTER G WITH CARON -> 'g' */
+ { 0xE8, 0x4B }, /* LATIN CAPITAL LETTER K WITH CARON -> 'K' */
+ { 0xE9, 0x6B }, /* LATIN SMALL LETTER K WITH CARON -> 'k' */
+ { 0xEA, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK -> 'O' */
+ { 0xEB, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK -> 'o' */
+ { 0xEC, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON -> 'O' */
+ { 0xED, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK AND MACRON -> 'o' */
+ { 0xF0, 0x6A }, /* LATIN SMALL LETTER J WITH CARON -> 'j' */
+ { 0xF4, 0x47 }, /* LATIN CAPITAL LETTER G WITH ACUTE -> 'G' */
+ { 0xF5, 0x67 }, /* LATIN SMALL LETTER G WITH ACUTE -> 'g' */
+ { 0xF7, 0x57 }, /* LATIN CAPITAL LETTER WYNN -> 'W' */
+ { 0xF8, 0x4E }, /* LATIN CAPITAL LETTER N WITH GRAVE -> 'N' */
+ { 0xF9, 0x6E }, /* LATIN SMALL LETTER N WITH GRAVE -> 'n' */
+ { 0xFA, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE -> 'A' */
+ { 0xFB, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE -> 'a' */
+ { 0xFE, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE -> 'O' */
+ { 0xFF, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE -> 'o' */
+ /* Entries for page 0x02 */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH DOUBLE GRAVE -> 'a' */
+ { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH INVERTED BREVE -> 'A' */
+ { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH INVERTED BREVE -> 'a' */
+ { 0x04, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE -> 'E' */
+ { 0x05, 0x65 }, /* LATIN SMALL LETTER E WITH DOUBLE GRAVE -> 'e' */
+ { 0x06, 0x45 }, /* LATIN CAPITAL LETTER E WITH INVERTED BREVE -> 'E' */
+ { 0x07, 0x65 }, /* LATIN SMALL LETTER E WITH INVERTED BREVE -> 'e' */
+ { 0x08, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE -> 'I' */
+ { 0x09, 0x69 }, /* LATIN SMALL LETTER I WITH DOUBLE GRAVE -> 'i' */
+ { 0x0A, 0x49 }, /* LATIN CAPITAL LETTER I WITH INVERTED BREVE -> 'I' */
+ { 0x0B, 0x69 }, /* LATIN SMALL LETTER I WITH INVERTED BREVE -> 'i' */
+ { 0x0C, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE -> 'O' */
+ { 0x0D, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE GRAVE -> 'o' */
+ { 0x0E, 0x4F }, /* LATIN CAPITAL LETTER O WITH INVERTED BREVE -> 'O' */
+ { 0x0F, 0x6F }, /* LATIN SMALL LETTER O WITH INVERTED BREVE -> 'o' */
+ { 0x10, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE -> 'R' */
+ { 0x11, 0x72 }, /* LATIN SMALL LETTER R WITH DOUBLE GRAVE -> 'r' */
+ { 0x12, 0x52 }, /* LATIN CAPITAL LETTER R WITH INVERTED BREVE -> 'R' */
+ { 0x13, 0x72 }, /* LATIN SMALL LETTER R WITH INVERTED BREVE -> 'r' */
+ { 0x14, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE -> 'U' */
+ { 0x15, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE GRAVE -> 'u' */
+ { 0x16, 0x55 }, /* LATIN CAPITAL LETTER U WITH INVERTED BREVE -> 'U' */
+ { 0x17, 0x75 }, /* LATIN SMALL LETTER U WITH INVERTED BREVE -> 'u' */
+ { 0x18, 0x53 }, /* LATIN CAPITAL LETTER S WITH COMMA BELOW -> 'S' */
+ { 0x19, 0x73 }, /* LATIN SMALL LETTER S WITH COMMA BELOW -> 's' */
+ { 0x1A, 0x54 }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW -> 'T' */
+ { 0x1B, 0x74 }, /* LATIN SMALL LETTER T WITH COMMA BELOW -> 't' */
+ { 0x1C, 0x59 }, /* LATIN CAPITAL LETTER YOGH -> 'Y' */
+ { 0x1D, 0x79 }, /* LATIN SMALL LETTER YOGH -> 'y' */
+ { 0x1E, 0x48 }, /* LATIN CAPITAL LETTER H WITH CARON -> 'H' */
+ { 0x1F, 0x68 }, /* LATIN SMALL LETTER H WITH CARON -> 'h' */
+ { 0x20, 0x4E }, /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG -> 'N' */
+ { 0x21, 0x64 }, /* LATIN SMALL LETTER D WITH CURL -> 'd' */
+ { 0x24, 0x5A }, /* LATIN CAPITAL LETTER Z WITH HOOK -> 'Z' */
+ { 0x25, 0x7A }, /* LATIN SMALL LETTER Z WITH HOOK -> 'z' */
+ { 0x26, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE -> 'A' */
+ { 0x27, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE -> 'a' */
+ { 0x28, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA -> 'E' */
+ { 0x29, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA -> 'e' */
+ { 0x2A, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON -> 'O' */
+ { 0x2B, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS AND MACRON -> 'o' */
+ { 0x2C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON -> 'O' */
+ { 0x2D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND MACRON -> 'o' */
+ { 0x2E, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE -> 'O' */
+ { 0x2F, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE -> 'o' */
+ { 0x30, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON -> 'O' */
+ { 0x31, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON -> 'o' */
+ { 0x32, 0x59 }, /* LATIN CAPITAL LETTER Y WITH MACRON -> 'Y' */
+ { 0x33, 0x79 }, /* LATIN SMALL LETTER Y WITH MACRON -> 'y' */
+ { 0x34, 0x6C }, /* LATIN SMALL LETTER L WITH CURL -> 'l' */
+ { 0x35, 0x6E }, /* LATIN SMALL LETTER N WITH CURL -> 'n' */
+ { 0x36, 0x74 }, /* LATIN SMALL LETTER T WITH CURL -> 't' */
+ { 0x37, 0x6A }, /* LATIN SMALL LETTER DOTLESS J -> 'j' */
+ { 0x3A, 0x41 }, /* LATIN CAPITAL LETTER A WITH STROKE -> 'A' */
+ { 0x3B, 0x43 }, /* LATIN CAPITAL LETTER C WITH STROKE -> 'C' */
+ { 0x3C, 0x63 }, /* LATIN SMALL LETTER C WITH STROKE -> 'c' */
+ { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH BAR -> 'L' */
+ { 0x3E, 0x54 }, /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE -> 'T' */
+ { 0x3F, 0x73 }, /* LATIN SMALL LETTER S WITH SWASH TAIL -> 's' */
+ { 0x40, 0x7A }, /* LATIN SMALL LETTER Z WITH SWASH TAIL -> 'z' */
+ { 0x43, 0x42 }, /* LATIN CAPITAL LETTER B WITH STROKE -> 'B' */
+ { 0x44, 0x55 }, /* LATIN CAPITAL LETTER U BAR -> 'U' */
+ { 0x45, 0x5E }, /* LATIN CAPITAL LETTER TURNED V -> '^' */
+ { 0x46, 0x45 }, /* LATIN CAPITAL LETTER E WITH STROKE -> 'E' */
+ { 0x47, 0x65 }, /* LATIN SMALL LETTER E WITH STROKE -> 'e' */
+ { 0x48, 0x4A }, /* LATIN CAPITAL LETTER J WITH STROKE -> 'J' */
+ { 0x49, 0x6A }, /* LATIN SMALL LETTER J WITH STROKE -> 'j' */
+ { 0x4A, 0x71 }, /* LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL -> 'q' */
+ { 0x4B, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK TAIL -> 'q' */
+ { 0x4C, 0x52 }, /* LATIN CAPITAL LETTER R WITH STROKE -> 'R' */
+ { 0x4D, 0x72 }, /* LATIN SMALL LETTER R WITH STROKE -> 'r' */
+ { 0x4E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH STROKE -> 'Y' */
+ { 0x4F, 0x79 }, /* LATIN SMALL LETTER Y WITH STROKE -> 'y' */
+ { 0x50, 0x00 }, /* LATIN SMALL LETTER TURNED A -> ... */
+ { 0x52, 0x61 }, /* LATIN SMALL LETTER TURNED ALPHA -> 'a' */
+ { 0x53, 0x62 }, /* LATIN SMALL LETTER B WITH HOOK -> 'b' */
+ { 0x54, 0x6F }, /* LATIN SMALL LETTER OPEN O -> 'o' */
+ { 0x55, 0x63 }, /* LATIN SMALL LETTER C WITH CURL -> 'c' */
+ { 0x56, 0x64 }, /* LATIN SMALL LETTER D WITH TAIL -> 'd' */
+ { 0x57, 0x64 }, /* LATIN SMALL LETTER D WITH HOOK -> 'd' */
+ { 0x58, 0x65 }, /* LATIN SMALL LETTER REVERSED E -> 'e' */
+ { 0x59, 0x40 }, /* LATIN SMALL LETTER SCHWA -> '@' */
+ { 0x5A, 0x40 }, /* LATIN SMALL LETTER SCHWA WITH HOOK -> '@' */
+ { 0x5B, 0x00 }, /* LATIN SMALL LETTER OPEN E -> ... */
+ { 0x5E, 0x65 }, /* LATIN SMALL LETTER CLOSED REVERSED OPEN E -> 'e' */
+ { 0x5F, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE -> 'j' */
+ { 0x60, 0x00 }, /* LATIN SMALL LETTER G WITH HOOK -> ... */
+ { 0x63, 0x67 }, /* LATIN SMALL LETTER GAMMA -> 'g' */
+ { 0x64, 0x75 }, /* LATIN SMALL LETTER RAMS HORN -> 'u' */
+ { 0x65, 0x59 }, /* LATIN SMALL LETTER TURNED H -> 'Y' */
+ { 0x66, 0x68 }, /* LATIN SMALL LETTER H WITH HOOK -> 'h' */
+ { 0x67, 0x68 }, /* LATIN SMALL LETTER HENG WITH HOOK -> 'h' */
+ { 0x68, 0x69 }, /* LATIN SMALL LETTER I WITH STROKE -> 'i' */
+ { 0x69, 0x69 }, /* LATIN SMALL LETTER IOTA -> 'i' */
+ { 0x6A, 0x49 }, /* LATIN LETTER SMALL CAPITAL I -> 'I' */
+ { 0x6B, 0x00 }, /* LATIN SMALL LETTER L WITH MIDDLE TILDE -> ... */
+ { 0x6D, 0x6C }, /* LATIN SMALL LETTER L WITH RETROFLEX HOOK -> 'l' */
+ { 0x6F, 0x57 }, /* LATIN SMALL LETTER TURNED M -> 'W' */
+ { 0x70, 0x57 }, /* LATIN SMALL LETTER TURNED M WITH LONG LEG -> 'W' */
+ { 0x71, 0x6D }, /* LATIN SMALL LETTER M WITH HOOK -> 'm' */
+ { 0x72, 0x00 }, /* LATIN SMALL LETTER N WITH LEFT HOOK -> ... */
+ { 0x74, 0x6E }, /* LATIN LETTER SMALL CAPITAL N -> 'n' */
+ { 0x75, 0x6F }, /* LATIN SMALL LETTER BARRED O -> 'o' */
+ { 0x77, 0x4F }, /* LATIN SMALL LETTER CLOSED OMEGA -> 'O' */
+ { 0x78, 0x46 }, /* LATIN SMALL LETTER PHI -> 'F' */
+ { 0x79, 0x00 }, /* LATIN SMALL LETTER TURNED R -> ... */
+ { 0x7F, 0x72 }, /* LATIN SMALL LETTER REVERSED R WITH FISHHOOK -> 'r' */
+ { 0x80, 0x52 }, /* LATIN LETTER SMALL CAPITAL R -> 'R' */
+ { 0x81, 0x52 }, /* LATIN LETTER SMALL CAPITAL INVERTED R -> 'R' */
+ { 0x82, 0x73 }, /* LATIN SMALL LETTER S WITH HOOK -> 's' */
+ { 0x83, 0x53 }, /* LATIN SMALL LETTER ESH -> 'S' */
+ { 0x84, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK -> 'j' */
+ { 0x85, 0x53 }, /* LATIN SMALL LETTER SQUAT REVERSED ESH -> 'S' */
+ { 0x86, 0x53 }, /* LATIN SMALL LETTER ESH WITH CURL -> 'S' */
+ { 0x87, 0x74 }, /* LATIN SMALL LETTER TURNED T -> 't' */
+ { 0x88, 0x74 }, /* LATIN SMALL LETTER T WITH RETROFLEX HOOK -> 't' */
+ { 0x89, 0x75 }, /* LATIN SMALL LETTER U BAR -> 'u' */
+ { 0x8A, 0x55 }, /* LATIN SMALL LETTER UPSILON -> 'U' */
+ { 0x8B, 0x76 }, /* LATIN SMALL LETTER V WITH HOOK -> 'v' */
+ { 0x8C, 0x5E }, /* LATIN SMALL LETTER TURNED V -> '^' */
+ { 0x8D, 0x77 }, /* LATIN SMALL LETTER TURNED W -> 'w' */
+ { 0x8E, 0x79 }, /* LATIN SMALL LETTER TURNED Y -> 'y' */
+ { 0x8F, 0x59 }, /* LATIN LETTER SMALL CAPITAL Y -> 'Y' */
+ { 0x90, 0x7A }, /* LATIN SMALL LETTER Z WITH RETROFLEX HOOK -> 'z' */
+ { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CURL -> 'z' */
+ { 0x92, 0x5A }, /* LATIN SMALL LETTER EZH -> 'Z' */
+ { 0x93, 0x5A }, /* LATIN SMALL LETTER EZH WITH CURL -> 'Z' */
+ { 0x94, 0x00 }, /* LATIN LETTER GLOTTAL STOP -> ... */
+ { 0x96, 0x3F }, /* LATIN LETTER INVERTED GLOTTAL STOP -> '?' */
+ { 0x97, 0x43 }, /* LATIN LETTER STRETCHED C -> 'C' */
+ { 0x98, 0x40 }, /* LATIN LETTER BILABIAL CLICK -> '@' */
+ { 0x99, 0x42 }, /* LATIN LETTER SMALL CAPITAL B -> 'B' */
+ { 0x9A, 0x45 }, /* LATIN SMALL LETTER CLOSED OPEN E -> 'E' */
+ { 0x9B, 0x47 }, /* LATIN LETTER SMALL CAPITAL G WITH HOOK -> 'G' */
+ { 0x9C, 0x48 }, /* LATIN LETTER SMALL CAPITAL H -> 'H' */
+ { 0x9D, 0x6A }, /* LATIN SMALL LETTER J WITH CROSSED-TAIL -> 'j' */
+ { 0x9E, 0x6B }, /* LATIN SMALL LETTER TURNED K -> 'k' */
+ { 0x9F, 0x4C }, /* LATIN LETTER SMALL CAPITAL L -> 'L' */
+ { 0xA0, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK -> 'q' */
+ { 0xA1, 0x3F }, /* LATIN LETTER GLOTTAL STOP WITH STROKE -> '?' */
+ { 0xA2, 0x3F }, /* LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE -> '?' */
+ { 0xAE, 0x00 }, /* LATIN SMALL LETTER TURNED H WITH FISHHOOK -> ... */
+ { 0xB1, 0x68 }, /* MODIFIER LETTER SMALL H WITH HOOK -> 'h' */
+ { 0xB2, 0x6A }, /* MODIFIER LETTER SMALL J -> 'j' */
+ { 0xB3, 0x00 }, /* MODIFIER LETTER SMALL R -> ... */
+ { 0xB6, 0x72 }, /* MODIFIER LETTER SMALL CAPITAL INVERTED R -> 'r' */
+ { 0xB7, 0x77 }, /* MODIFIER LETTER SMALL W -> 'w' */
+ { 0xB8, 0x79 }, /* MODIFIER LETTER SMALL Y -> 'y' */
+ { 0xB9, 0x27 }, /* MODIFIER LETTER PRIME -> ''' */
+ { 0xBA, 0x22 }, /* MODIFIER LETTER DOUBLE PRIME -> '"' */
+ { 0xBB, 0x60 }, /* MODIFIER LETTER TURNED COMMA -> '`' */
+ { 0xBC, 0x27 }, /* MODIFIER LETTER APOSTROPHE -> ''' */
+ { 0xBD, 0x60 }, /* MODIFIER LETTER REVERSED COMMA -> '`' */
+ { 0xBE, 0x60 }, /* MODIFIER LETTER RIGHT HALF RING -> '`' */
+ { 0xBF, 0x27 }, /* MODIFIER LETTER LEFT HALF RING -> ''' */
+ { 0xC0, 0x3F }, /* MODIFIER LETTER GLOTTAL STOP -> '?' */
+ { 0xC1, 0x3F }, /* MODIFIER LETTER REVERSED GLOTTAL STOP -> '?' */
+ { 0xC2, 0x3C }, /* MODIFIER LETTER LEFT ARROWHEAD -> '<' */
+ { 0xC3, 0x3E }, /* MODIFIER LETTER RIGHT ARROWHEAD -> '>' */
+ { 0xC4, 0x5E }, /* MODIFIER LETTER UP ARROWHEAD -> '^' */
+ { 0xC5, 0x56 }, /* MODIFIER LETTER DOWN ARROWHEAD -> 'V' */
+ { 0xC6, 0x5E }, /* MODIFIER LETTER CIRCUMFLEX ACCENT -> '^' */
+ { 0xC7, 0x56 }, /* CARON -> 'V' */
+ { 0xC8, 0x27 }, /* MODIFIER LETTER VERTICAL LINE -> ''' */
+ { 0xC9, 0x2D }, /* MODIFIER LETTER MACRON -> '-' */
+ { 0xCA, 0x2F }, /* MODIFIER LETTER ACUTE ACCENT -> '/' */
+ { 0xCB, 0x5C }, /* MODIFIER LETTER GRAVE ACCENT -> '\' */
+ { 0xCC, 0x2C }, /* MODIFIER LETTER LOW VERTICAL LINE -> ',' */
+ { 0xCD, 0x5F }, /* MODIFIER LETTER LOW MACRON -> '_' */
+ { 0xCE, 0x5C }, /* MODIFIER LETTER LOW GRAVE ACCENT -> '\' */
+ { 0xCF, 0x2F }, /* MODIFIER LETTER LOW ACUTE ACCENT -> '/' */
+ { 0xD0, 0x3A }, /* MODIFIER LETTER TRIANGULAR COLON -> ':' */
+ { 0xD1, 0x2E }, /* MODIFIER LETTER HALF TRIANGULAR COLON -> '.' */
+ { 0xD2, 0x60 }, /* MODIFIER LETTER CENTRED RIGHT HALF RING -> '`' */
+ { 0xD3, 0x27 }, /* MODIFIER LETTER CENTRED LEFT HALF RING -> ''' */
+ { 0xD4, 0x5E }, /* MODIFIER LETTER UP TACK -> '^' */
+ { 0xD5, 0x56 }, /* MODIFIER LETTER DOWN TACK -> 'V' */
+ { 0xD6, 0x2B }, /* MODIFIER LETTER PLUS SIGN -> '+' */
+ { 0xD7, 0x2D }, /* MODIFIER LETTER MINUS SIGN -> '-' */
+ { 0xD8, 0x56 }, /* BREVE -> 'V' */
+ { 0xD9, 0x2E }, /* DOT ABOVE -> '.' */
+ { 0xDA, 0x40 }, /* RING ABOVE -> '@' */
+ { 0xDB, 0x2C }, /* OGONEK -> ',' */
+ { 0xDC, 0x7E }, /* SMALL TILDE -> '~' */
+ { 0xDD, 0x22 }, /* DOUBLE ACUTE ACCENT -> '"' */
+ { 0xDE, 0x52 }, /* MODIFIER LETTER RHOTIC HOOK -> 'R' */
+ { 0xDF, 0x58 }, /* MODIFIER LETTER CROSS ACCENT -> 'X' */
+ { 0xE0, 0x47 }, /* MODIFIER LETTER SMALL GAMMA -> 'G' */
+ { 0xE1, 0x6C }, /* MODIFIER LETTER SMALL L -> 'l' */
+ { 0xE2, 0x73 }, /* MODIFIER LETTER SMALL S -> 's' */
+ { 0xE3, 0x78 }, /* MODIFIER LETTER SMALL X -> 'x' */
+ { 0xE4, 0x3F }, /* MODIFIER LETTER SMALL REVERSED GLOTTAL STOP -> '?' */
+ { 0xEC, 0x56 }, /* MODIFIER LETTER VOICING -> 'V' */
+ { 0xED, 0x3D }, /* MODIFIER LETTER UNASPIRATED -> '=' */
+ { 0xEE, 0x22 }, /* MODIFIER LETTER DOUBLE APOSTROPHE -> '"' */
+ /* Entries for page 0x03 */
+ { 0x63, 0x61 }, /* COMBINING LATIN SMALL LETTER A -> 'a' */
+ { 0x64, 0x65 }, /* COMBINING LATIN SMALL LETTER E -> 'e' */
+ { 0x65, 0x69 }, /* COMBINING LATIN SMALL LETTER I -> 'i' */
+ { 0x66, 0x6F }, /* COMBINING LATIN SMALL LETTER O -> 'o' */
+ { 0x67, 0x75 }, /* COMBINING LATIN SMALL LETTER U -> 'u' */
+ { 0x68, 0x63 }, /* COMBINING LATIN SMALL LETTER C -> 'c' */
+ { 0x69, 0x64 }, /* COMBINING LATIN SMALL LETTER D -> 'd' */
+ { 0x6A, 0x68 }, /* COMBINING LATIN SMALL LETTER H -> 'h' */
+ { 0x6B, 0x6D }, /* COMBINING LATIN SMALL LETTER M -> 'm' */
+ { 0x6C, 0x72 }, /* COMBINING LATIN SMALL LETTER R -> 'r' */
+ { 0x6D, 0x74 }, /* COMBINING LATIN SMALL LETTER T -> 't' */
+ { 0x6E, 0x76 }, /* COMBINING LATIN SMALL LETTER V -> 'v' */
+ { 0x6F, 0x78 }, /* COMBINING LATIN SMALL LETTER X -> 'x' */
+ { 0x74, 0x27 }, /* GREEK NUMERAL SIGN -> ''' */
+ { 0x75, 0x2C }, /* GREEK LOWER NUMERAL SIGN -> ',' */
+ { 0x7E, 0x3F }, /* GREEK QUESTION MARK -> '?' */
+ { 0x86, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS -> 'A' */
+ { 0x87, 0x3B }, /* GREEK ANO TELEIA -> ';' */
+ { 0x88, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS -> 'E' */
+ { 0x89, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH TONOS -> 'E' */
+ { 0x8A, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH TONOS -> 'I' */
+ { 0x8C, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS -> 'O' */
+ { 0x8E, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS -> 'U' */
+ { 0x8F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS -> 'O' */
+ { 0x90, 0x49 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -> 'I' */
+ { 0x91, 0x41 }, /* GREEK CAPITAL LETTER ALPHA -> 'A' */
+ { 0x92, 0x42 }, /* GREEK CAPITAL LETTER BETA -> 'B' */
+ { 0x93, 0x47 }, /* GREEK CAPITAL LETTER GAMMA -> 'G' */
+ { 0x94, 0x44 }, /* GREEK CAPITAL LETTER DELTA -> 'D' */
+ { 0x95, 0x45 }, /* GREEK CAPITAL LETTER EPSILON -> 'E' */
+ { 0x96, 0x5A }, /* GREEK CAPITAL LETTER ZETA -> 'Z' */
+ { 0x97, 0x45 }, /* GREEK CAPITAL LETTER ETA -> 'E' */
+ { 0x99, 0x49 }, /* GREEK CAPITAL LETTER IOTA -> 'I' */
+ { 0x9A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA -> 'K' */
+ { 0x9B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA -> 'L' */
+ { 0x9C, 0x4D }, /* GREEK CAPITAL LETTER MU -> 'M' */
+ { 0x9D, 0x4E }, /* GREEK CAPITAL LETTER NU -> 'N' */
+ { 0x9F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON -> 'O' */
+ { 0xA0, 0x50 }, /* GREEK CAPITAL LETTER PI -> 'P' */
+ { 0xA1, 0x52 }, /* GREEK CAPITAL LETTER RHO -> 'R' */
+ { 0xA3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA -> 'S' */
+ { 0xA4, 0x54 }, /* GREEK CAPITAL LETTER TAU -> 'T' */
+ { 0xA5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON -> 'U' */
+ { 0xA9, 0x4F }, /* GREEK CAPITAL LETTER OMEGA -> 'O' */
+ { 0xAA, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -> 'I' */
+ { 0xAB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -> 'U' */
+ { 0xAC, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH TONOS -> 'a' */
+ { 0xAD, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH TONOS -> 'e' */
+ { 0xAE, 0x65 }, /* GREEK SMALL LETTER ETA WITH TONOS -> 'e' */
+ { 0xAF, 0x69 }, /* GREEK SMALL LETTER IOTA WITH TONOS -> 'i' */
+ { 0xB0, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -> 'u' */
+ { 0xB1, 0x61 }, /* GREEK SMALL LETTER ALPHA -> 'a' */
+ { 0xB2, 0x62 }, /* GREEK SMALL LETTER BETA -> 'b' */
+ { 0xB3, 0x67 }, /* GREEK SMALL LETTER GAMMA -> 'g' */
+ { 0xB4, 0x64 }, /* GREEK SMALL LETTER DELTA -> 'd' */
+ { 0xB5, 0x65 }, /* GREEK SMALL LETTER EPSILON -> 'e' */
+ { 0xB6, 0x7A }, /* GREEK SMALL LETTER ZETA -> 'z' */
+ { 0xB7, 0x65 }, /* GREEK SMALL LETTER ETA -> 'e' */
+ { 0xB9, 0x69 }, /* GREEK SMALL LETTER IOTA -> 'i' */
+ { 0xBA, 0x6B }, /* GREEK SMALL LETTER KAPPA -> 'k' */
+ { 0xBB, 0x6C }, /* GREEK SMALL LETTER LAMDA -> 'l' */
+ { 0xBC, 0x6D }, /* GREEK SMALL LETTER MU -> 'm' */
+ { 0xBD, 0x6E }, /* GREEK SMALL LETTER NU -> 'n' */
+ { 0xBE, 0x78 }, /* GREEK SMALL LETTER XI -> 'x' */
+ { 0xBF, 0x6F }, /* GREEK SMALL LETTER OMICRON -> 'o' */
+ { 0xC0, 0x70 }, /* GREEK SMALL LETTER PI -> 'p' */
+ { 0xC1, 0x72 }, /* GREEK SMALL LETTER RHO -> 'r' */
+ { 0xC2, 0x73 }, /* GREEK SMALL LETTER FINAL SIGMA -> 's' */
+ { 0xC3, 0x73 }, /* GREEK SMALL LETTER SIGMA -> 's' */
+ { 0xC4, 0x74 }, /* GREEK SMALL LETTER TAU -> 't' */
+ { 0xC5, 0x75 }, /* GREEK SMALL LETTER UPSILON -> 'u' */
+ { 0xC9, 0x6F }, /* GREEK SMALL LETTER OMEGA -> 'o' */
+ { 0xCA, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA -> 'i' */
+ { 0xCB, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA -> 'u' */
+ { 0xCC, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH TONOS -> 'o' */
+ { 0xCD, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH TONOS -> 'u' */
+ { 0xCE, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH TONOS -> 'o' */
+ { 0xD0, 0x62 }, /* GREEK BETA SYMBOL -> 'b' */
+ { 0xD2, 0x00 }, /* GREEK UPSILON WITH HOOK SYMBOL -> ... */
+ { 0xD4, 0x55 }, /* GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL -> 'U' */
+ { 0xD6, 0x70 }, /* GREEK PI SYMBOL -> 'p' */
+ { 0xD7, 0x26 }, /* GREEK KAI SYMBOL -> '&' */
+ { 0xDC, 0x57 }, /* GREEK LETTER DIGAMMA -> 'W' */
+ { 0xDD, 0x77 }, /* GREEK SMALL LETTER DIGAMMA -> 'w' */
+ { 0xDE, 0x51 }, /* GREEK LETTER KOPPA -> 'Q' */
+ { 0xDF, 0x71 }, /* GREEK SMALL LETTER KOPPA -> 'q' */
+ { 0xE4, 0x46 }, /* COPTIC CAPITAL LETTER FEI -> 'F' */
+ { 0xE5, 0x66 }, /* COPTIC SMALL LETTER FEI -> 'f' */
+ { 0xE8, 0x48 }, /* COPTIC CAPITAL LETTER HORI -> 'H' */
+ { 0xE9, 0x68 }, /* COPTIC SMALL LETTER HORI -> 'h' */
+ { 0xEA, 0x47 }, /* COPTIC CAPITAL LETTER GANGIA -> 'G' */
+ { 0xEB, 0x67 }, /* COPTIC SMALL LETTER GANGIA -> 'g' */
+ { 0xF0, 0x6B }, /* GREEK KAPPA SYMBOL -> 'k' */
+ { 0xF1, 0x72 }, /* GREEK RHO SYMBOL -> 'r' */
+ { 0xF2, 0x63 }, /* GREEK LUNATE SIGMA SYMBOL -> 'c' */
+ { 0xF3, 0x6A }, /* GREEK LETTER YOT -> 'j' */
+ /* Entries for page 0x04 */
+ { 0x06, 0x49 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -> 'I' */
+ { 0x08, 0x4A }, /* CYRILLIC CAPITAL LETTER JE -> 'J' */
+ { 0x0D, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH GRAVE -> 'I' */
+ { 0x0E, 0x55 }, /* CYRILLIC CAPITAL LETTER SHORT U -> 'U' */
+ { 0x10, 0x41 }, /* CYRILLIC CAPITAL LETTER A -> 'A' */
+ { 0x11, 0x42 }, /* CYRILLIC CAPITAL LETTER BE -> 'B' */
+ { 0x12, 0x56 }, /* CYRILLIC CAPITAL LETTER VE -> 'V' */
+ { 0x13, 0x47 }, /* CYRILLIC CAPITAL LETTER GHE -> 'G' */
+ { 0x14, 0x44 }, /* CYRILLIC CAPITAL LETTER DE -> 'D' */
+ { 0x15, 0x45 }, /* CYRILLIC CAPITAL LETTER IE -> 'E' */
+ { 0x17, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE -> 'Z' */
+ { 0x18, 0x49 }, /* CYRILLIC CAPITAL LETTER I -> 'I' */
+ { 0x19, 0x49 }, /* CYRILLIC CAPITAL LETTER SHORT I -> 'I' */
+ { 0x1A, 0x4B }, /* CYRILLIC CAPITAL LETTER KA -> 'K' */
+ { 0x1B, 0x4C }, /* CYRILLIC CAPITAL LETTER EL -> 'L' */
+ { 0x1C, 0x4D }, /* CYRILLIC CAPITAL LETTER EM -> 'M' */
+ { 0x1D, 0x4E }, /* CYRILLIC CAPITAL LETTER EN -> 'N' */
+ { 0x1E, 0x4F }, /* CYRILLIC CAPITAL LETTER O -> 'O' */
+ { 0x1F, 0x50 }, /* CYRILLIC CAPITAL LETTER PE -> 'P' */
+ { 0x20, 0x52 }, /* CYRILLIC CAPITAL LETTER ER -> 'R' */
+ { 0x21, 0x53 }, /* CYRILLIC CAPITAL LETTER ES -> 'S' */
+ { 0x22, 0x54 }, /* CYRILLIC CAPITAL LETTER TE -> 'T' */
+ { 0x23, 0x55 }, /* CYRILLIC CAPITAL LETTER U -> 'U' */
+ { 0x24, 0x46 }, /* CYRILLIC CAPITAL LETTER EF -> 'F' */
+ { 0x2A, 0x27 }, /* CYRILLIC CAPITAL LETTER HARD SIGN -> ''' */
+ { 0x2B, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU -> 'Y' */
+ { 0x2C, 0x27 }, /* CYRILLIC CAPITAL LETTER SOFT SIGN -> ''' */
+ { 0x2D, 0x45 }, /* CYRILLIC CAPITAL LETTER E -> 'E' */
+ { 0x30, 0x61 }, /* CYRILLIC SMALL LETTER A -> 'a' */
+ { 0x31, 0x62 }, /* CYRILLIC SMALL LETTER BE -> 'b' */
+ { 0x32, 0x76 }, /* CYRILLIC SMALL LETTER VE -> 'v' */
+ { 0x33, 0x67 }, /* CYRILLIC SMALL LETTER GHE -> 'g' */
+ { 0x34, 0x64 }, /* CYRILLIC SMALL LETTER DE -> 'd' */
+ { 0x35, 0x65 }, /* CYRILLIC SMALL LETTER IE -> 'e' */
+ { 0x37, 0x7A }, /* CYRILLIC SMALL LETTER ZE -> 'z' */
+ { 0x38, 0x69 }, /* CYRILLIC SMALL LETTER I -> 'i' */
+ { 0x39, 0x69 }, /* CYRILLIC SMALL LETTER SHORT I -> 'i' */
+ { 0x3A, 0x6B }, /* CYRILLIC SMALL LETTER KA -> 'k' */
+ { 0x3B, 0x6C }, /* CYRILLIC SMALL LETTER EL -> 'l' */
+ { 0x3C, 0x6D }, /* CYRILLIC SMALL LETTER EM -> 'm' */
+ { 0x3D, 0x6E }, /* CYRILLIC SMALL LETTER EN -> 'n' */
+ { 0x3E, 0x6F }, /* CYRILLIC SMALL LETTER O -> 'o' */
+ { 0x3F, 0x70 }, /* CYRILLIC SMALL LETTER PE -> 'p' */
+ { 0x40, 0x72 }, /* CYRILLIC SMALL LETTER ER -> 'r' */
+ { 0x41, 0x73 }, /* CYRILLIC SMALL LETTER ES -> 's' */
+ { 0x42, 0x74 }, /* CYRILLIC SMALL LETTER TE -> 't' */
+ { 0x43, 0x75 }, /* CYRILLIC SMALL LETTER U -> 'u' */
+ { 0x44, 0x66 }, /* CYRILLIC SMALL LETTER EF -> 'f' */
+ { 0x4A, 0x27 }, /* CYRILLIC SMALL LETTER HARD SIGN -> ''' */
+ { 0x4B, 0x79 }, /* CYRILLIC SMALL LETTER YERU -> 'y' */
+ { 0x4C, 0x27 }, /* CYRILLIC SMALL LETTER SOFT SIGN -> ''' */
+ { 0x4D, 0x65 }, /* CYRILLIC SMALL LETTER E -> 'e' */
+ { 0x56, 0x69 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -> 'i' */
+ { 0x58, 0x6A }, /* CYRILLIC SMALL LETTER JE -> 'j' */
+ { 0x5D, 0x69 }, /* CYRILLIC SMALL LETTER I WITH GRAVE -> 'i' */
+ { 0x5E, 0x75 }, /* CYRILLIC SMALL LETTER SHORT U -> 'u' */
+ { 0x60, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA -> 'O' */
+ { 0x61, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA -> 'o' */
+ { 0x62, 0x45 }, /* CYRILLIC CAPITAL LETTER YAT -> 'E' */
+ { 0x63, 0x65 }, /* CYRILLIC SMALL LETTER YAT -> 'e' */
+ { 0x66, 0x45 }, /* CYRILLIC CAPITAL LETTER LITTLE YUS -> 'E' */
+ { 0x67, 0x65 }, /* CYRILLIC SMALL LETTER LITTLE YUS -> 'e' */
+ { 0x6A, 0x4F }, /* CYRILLIC CAPITAL LETTER BIG YUS -> 'O' */
+ { 0x6B, 0x6F }, /* CYRILLIC SMALL LETTER BIG YUS -> 'o' */
+ { 0x72, 0x46 }, /* CYRILLIC CAPITAL LETTER FITA -> 'F' */
+ { 0x73, 0x66 }, /* CYRILLIC SMALL LETTER FITA -> 'f' */
+ { 0x74, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA -> 'Y' */
+ { 0x75, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA -> 'y' */
+ { 0x76, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'Y' */
+ { 0x77, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'y' */
+ { 0x78, 0x75 }, /* CYRILLIC CAPITAL LETTER UK -> 'u' */
+ { 0x79, 0x75 }, /* CYRILLIC SMALL LETTER UK -> 'u' */
+ { 0x7A, 0x4F }, /* CYRILLIC CAPITAL LETTER ROUND OMEGA -> 'O' */
+ { 0x7B, 0x6F }, /* CYRILLIC SMALL LETTER ROUND OMEGA -> 'o' */
+ { 0x7C, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO -> 'O' */
+ { 0x7D, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA WITH TITLO -> 'o' */
+ { 0x80, 0x51 }, /* CYRILLIC CAPITAL LETTER KOPPA -> 'Q' */
+ { 0x81, 0x71 }, /* CYRILLIC SMALL LETTER KOPPA -> 'q' */
+ { 0x8C, 0x22 }, /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN -> '"' */
+ { 0x8D, 0x22 }, /* CYRILLIC SMALL LETTER SEMISOFT SIGN -> '"' */
+ { 0xAE, 0x55 }, /* CYRILLIC CAPITAL LETTER STRAIGHT U -> 'U' */
+ { 0xAF, 0x75 }, /* CYRILLIC SMALL LETTER STRAIGHT U -> 'u' */
+ { 0xBA, 0x48 }, /* CYRILLIC CAPITAL LETTER SHHA -> 'H' */
+ { 0xBB, 0x68 }, /* CYRILLIC SMALL LETTER SHHA -> 'h' */
+ { 0xC0, 0x60 }, /* CYRILLIC LETTER PALOCHKA -> '`' */
+ { 0xD0, 0x61 }, /* CYRILLIC CAPITAL LETTER A WITH BREVE -> 'a' */
+ { 0xD1, 0x61 }, /* CYRILLIC SMALL LETTER A WITH BREVE -> 'a' */
+ { 0xD2, 0x41 }, /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS -> 'A' */
+ { 0xD3, 0x61 }, /* CYRILLIC SMALL LETTER A WITH DIAERESIS -> 'a' */
+ { 0xD8, 0x00 }, /* CYRILLIC CAPITAL LETTER SCHWA -> ... */
+ { 0xDB, 0x40 }, /* CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS -> '@' */
+ { 0xDE, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS -> 'Z' */
+ { 0xDF, 0x7A }, /* CYRILLIC SMALL LETTER ZE WITH DIAERESIS -> 'z' */
+ { 0xE2, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH MACRON -> 'I' */
+ { 0xE3, 0x69 }, /* CYRILLIC SMALL LETTER I WITH MACRON -> 'i' */
+ { 0xE4, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS -> 'I' */
+ { 0xE5, 0x69 }, /* CYRILLIC SMALL LETTER I WITH DIAERESIS -> 'i' */
+ { 0xE6, 0x4F }, /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS -> 'O' */
+ { 0xE7, 0x6F }, /* CYRILLIC SMALL LETTER O WITH DIAERESIS -> 'o' */
+ { 0xE8, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O -> 'O' */
+ { 0xE9, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O -> 'o' */
+ { 0xEA, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS -> 'O' */
+ { 0xEB, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS -> 'o' */
+ { 0xEC, 0x45 }, /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS -> 'E' */
+ { 0xED, 0x65 }, /* CYRILLIC SMALL LETTER E WITH DIAERESIS -> 'e' */
+ { 0xEE, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH MACRON -> 'U' */
+ { 0xEF, 0x75 }, /* CYRILLIC SMALL LETTER U WITH MACRON -> 'u' */
+ { 0xF0, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS -> 'U' */
+ { 0xF1, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DIAERESIS -> 'u' */
+ { 0xF2, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */
+ { 0xF3, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */
+ { 0xF8, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS -> 'Y' */
+ { 0xF9, 0x79 }, /* CYRILLIC SMALL LETTER YERU WITH DIAERESIS -> 'y' */
+ /* Entries for page 0x05 */
+ { 0x31, 0x41 }, /* ARMENIAN CAPITAL LETTER AYB -> 'A' */
+ { 0x32, 0x42 }, /* ARMENIAN CAPITAL LETTER BEN -> 'B' */
+ { 0x33, 0x47 }, /* ARMENIAN CAPITAL LETTER GIM -> 'G' */
+ { 0x34, 0x44 }, /* ARMENIAN CAPITAL LETTER DA -> 'D' */
+ { 0x35, 0x45 }, /* ARMENIAN CAPITAL LETTER ECH -> 'E' */
+ { 0x36, 0x5A }, /* ARMENIAN CAPITAL LETTER ZA -> 'Z' */
+ { 0x37, 0x45 }, /* ARMENIAN CAPITAL LETTER EH -> 'E' */
+ { 0x38, 0x45 }, /* ARMENIAN CAPITAL LETTER ET -> 'E' */
+ { 0x3B, 0x49 }, /* ARMENIAN CAPITAL LETTER INI -> 'I' */
+ { 0x3C, 0x4C }, /* ARMENIAN CAPITAL LETTER LIWN -> 'L' */
+ { 0x3F, 0x4B }, /* ARMENIAN CAPITAL LETTER KEN -> 'K' */
+ { 0x40, 0x48 }, /* ARMENIAN CAPITAL LETTER HO -> 'H' */
+ { 0x44, 0x4D }, /* ARMENIAN CAPITAL LETTER MEN -> 'M' */
+ { 0x45, 0x59 }, /* ARMENIAN CAPITAL LETTER YI -> 'Y' */
+ { 0x46, 0x4E }, /* ARMENIAN CAPITAL LETTER NOW -> 'N' */
+ { 0x48, 0x4F }, /* ARMENIAN CAPITAL LETTER VO -> 'O' */
+ { 0x4A, 0x50 }, /* ARMENIAN CAPITAL LETTER PEH -> 'P' */
+ { 0x4B, 0x4A }, /* ARMENIAN CAPITAL LETTER JHEH -> 'J' */
+ { 0x4D, 0x53 }, /* ARMENIAN CAPITAL LETTER SEH -> 'S' */
+ { 0x4E, 0x56 }, /* ARMENIAN CAPITAL LETTER VEW -> 'V' */
+ { 0x4F, 0x54 }, /* ARMENIAN CAPITAL LETTER TIWN -> 'T' */
+ { 0x50, 0x52 }, /* ARMENIAN CAPITAL LETTER REH -> 'R' */
+ { 0x52, 0x57 }, /* ARMENIAN CAPITAL LETTER YIWN -> 'W' */
+ { 0x55, 0x4F }, /* ARMENIAN CAPITAL LETTER OH -> 'O' */
+ { 0x56, 0x46 }, /* ARMENIAN CAPITAL LETTER FEH -> 'F' */
+ { 0x59, 0x3C }, /* ARMENIAN MODIFIER LETTER LEFT HALF RING -> '<' */
+ { 0x5A, 0x27 }, /* ARMENIAN APOSTROPHE -> ''' */
+ { 0x5B, 0x2F }, /* ARMENIAN EMPHASIS MARK -> '/' */
+ { 0x5C, 0x21 }, /* ARMENIAN EXCLAMATION MARK -> '!' */
+ { 0x5D, 0x2C }, /* ARMENIAN COMMA -> ',' */
+ { 0x5E, 0x3F }, /* ARMENIAN QUESTION MARK -> '?' */
+ { 0x5F, 0x2E }, /* ARMENIAN ABBREVIATION MARK -> '.' */
+ { 0x61, 0x61 }, /* ARMENIAN SMALL LETTER AYB -> 'a' */
+ { 0x62, 0x62 }, /* ARMENIAN SMALL LETTER BEN -> 'b' */
+ { 0x63, 0x67 }, /* ARMENIAN SMALL LETTER GIM -> 'g' */
+ { 0x64, 0x64 }, /* ARMENIAN SMALL LETTER DA -> 'd' */
+ { 0x65, 0x65 }, /* ARMENIAN SMALL LETTER ECH -> 'e' */
+ { 0x66, 0x7A }, /* ARMENIAN SMALL LETTER ZA -> 'z' */
+ { 0x67, 0x65 }, /* ARMENIAN SMALL LETTER EH -> 'e' */
+ { 0x68, 0x65 }, /* ARMENIAN SMALL LETTER ET -> 'e' */
+ { 0x6B, 0x69 }, /* ARMENIAN SMALL LETTER INI -> 'i' */
+ { 0x6C, 0x6C }, /* ARMENIAN SMALL LETTER LIWN -> 'l' */
+ { 0x6F, 0x6B }, /* ARMENIAN SMALL LETTER KEN -> 'k' */
+ { 0x70, 0x68 }, /* ARMENIAN SMALL LETTER HO -> 'h' */
+ { 0x74, 0x6D }, /* ARMENIAN SMALL LETTER MEN -> 'm' */
+ { 0x75, 0x79 }, /* ARMENIAN SMALL LETTER YI -> 'y' */
+ { 0x76, 0x6E }, /* ARMENIAN SMALL LETTER NOW -> 'n' */
+ { 0x78, 0x6F }, /* ARMENIAN SMALL LETTER VO -> 'o' */
+ { 0x7A, 0x70 }, /* ARMENIAN SMALL LETTER PEH -> 'p' */
+ { 0x7B, 0x6A }, /* ARMENIAN SMALL LETTER JHEH -> 'j' */
+ { 0x7D, 0x73 }, /* ARMENIAN SMALL LETTER SEH -> 's' */
+ { 0x7E, 0x76 }, /* ARMENIAN SMALL LETTER VEW -> 'v' */
+ { 0x7F, 0x74 }, /* ARMENIAN SMALL LETTER TIWN -> 't' */
+ { 0x80, 0x72 }, /* ARMENIAN SMALL LETTER REH -> 'r' */
+ { 0x82, 0x77 }, /* ARMENIAN SMALL LETTER YIWN -> 'w' */
+ { 0x85, 0x6F }, /* ARMENIAN SMALL LETTER OH -> 'o' */
+ { 0x86, 0x66 }, /* ARMENIAN SMALL LETTER FEH -> 'f' */
+ { 0x89, 0x3A }, /* ARMENIAN FULL STOP -> ':' */
+ { 0x8A, 0x2D }, /* ARMENIAN HYPHEN -> '-' */
+ { 0xB1, 0x65 }, /* HEBREW POINT HATAF SEGOL -> 'e' */
+ { 0xB2, 0x61 }, /* HEBREW POINT HATAF PATAH -> 'a' */
+ { 0xB3, 0x6F }, /* HEBREW POINT HATAF QAMATS -> 'o' */
+ { 0xB4, 0x69 }, /* HEBREW POINT HIRIQ -> 'i' */
+ { 0xB5, 0x65 }, /* HEBREW POINT TSERE -> 'e' */
+ { 0xB6, 0x65 }, /* HEBREW POINT SEGOL -> 'e' */
+ { 0xB7, 0x61 }, /* HEBREW POINT PATAH -> 'a' */
+ { 0xB8, 0x61 }, /* HEBREW POINT QAMATS -> 'a' */
+ { 0xB9, 0x6F }, /* HEBREW POINT HOLAM -> 'o' */
+ { 0xBA, 0x6F }, /* HEBREW POINT HOLAM HASER FOR VAV -> 'o' */
+ { 0xBB, 0x75 }, /* HEBREW POINT QUBUTS -> 'u' */
+ { 0xBE, 0x2D }, /* HEBREW PUNCTUATION MAQAF -> '-' */
+ { 0xC0, 0x7C }, /* HEBREW PUNCTUATION PASEQ -> '|' */
+ { 0xC3, 0x2E }, /* HEBREW PUNCTUATION SOF PASUQ -> '.' */
+ { 0xC6, 0x6E }, /* HEBREW PUNCTUATION NUN HAFUKHA -> 'n' */
+ { 0xC7, 0x6F }, /* HEBREW POINT QAMATS QATAN -> 'o' */
+ { 0xD0, 0x41 }, /* HEBREW LETTER ALEF -> 'A' */
+ { 0xD1, 0x62 }, /* HEBREW LETTER BET -> 'b' */
+ { 0xD2, 0x67 }, /* HEBREW LETTER GIMEL -> 'g' */
+ { 0xD3, 0x64 }, /* HEBREW LETTER DALET -> 'd' */
+ { 0xD4, 0x68 }, /* HEBREW LETTER HE -> 'h' */
+ { 0xD5, 0x76 }, /* HEBREW LETTER VAV -> 'v' */
+ { 0xD6, 0x7A }, /* HEBREW LETTER ZAYIN -> 'z' */
+ { 0xD7, 0x48 }, /* HEBREW LETTER HET -> 'H' */
+ { 0xD8, 0x54 }, /* HEBREW LETTER TET -> 'T' */
+ { 0xD9, 0x79 }, /* HEBREW LETTER YOD -> 'y' */
+ { 0xDC, 0x6C }, /* HEBREW LETTER LAMED -> 'l' */
+ { 0xDD, 0x6D }, /* HEBREW LETTER FINAL MEM -> 'm' */
+ { 0xDE, 0x6D }, /* HEBREW LETTER MEM -> 'm' */
+ { 0xDF, 0x6E }, /* HEBREW LETTER FINAL NUN -> 'n' */
+ { 0xE0, 0x6E }, /* HEBREW LETTER NUN -> 'n' */
+ { 0xE1, 0x73 }, /* HEBREW LETTER SAMEKH -> 's' */
+ { 0xE2, 0x60 }, /* HEBREW LETTER AYIN -> '`' */
+ { 0xE3, 0x70 }, /* HEBREW LETTER FINAL PE -> 'p' */
+ { 0xE4, 0x70 }, /* HEBREW LETTER PE -> 'p' */
+ { 0xE7, 0x6B }, /* HEBREW LETTER QOF -> 'k' */
+ { 0xE8, 0x72 }, /* HEBREW LETTER RESH -> 'r' */
+ { 0xEA, 0x74 }, /* HEBREW LETTER TAV -> 't' */
+ { 0xF0, 0x56 }, /* HEBREW LIGATURE YIDDISH DOUBLE VAV -> 'V' */
+ { 0xF3, 0x27 }, /* HEBREW PUNCTUATION GERESH -> ''' */
+ { 0xF4, 0x22 }, /* HEBREW PUNCTUATION GERSHAYIM -> '"' */
+ /* Entries for page 0x06 */
+ { 0x0C, 0x2C }, /* ARABIC COMMA -> ',' */
+ { 0x1B, 0x3B }, /* ARABIC SEMICOLON -> ';' */
+ { 0x1F, 0x3F }, /* ARABIC QUESTION MARK -> '?' */
+ { 0x22, 0x61 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE -> 'a' */
+ { 0x23, 0x27 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE -> ''' */
+ { 0x28, 0x62 }, /* ARABIC LETTER BEH -> 'b' */
+ { 0x29, 0x40 }, /* ARABIC LETTER TEH MARBUTA -> '@' */
+ { 0x2A, 0x74 }, /* ARABIC LETTER TEH -> 't' */
+ { 0x2C, 0x6A }, /* ARABIC LETTER JEEM -> 'j' */
+ { 0x2D, 0x48 }, /* ARABIC LETTER HAH -> 'H' */
+ { 0x2F, 0x64 }, /* ARABIC LETTER DAL -> 'd' */
+ { 0x31, 0x72 }, /* ARABIC LETTER REH -> 'r' */
+ { 0x32, 0x7A }, /* ARABIC LETTER ZAIN -> 'z' */
+ { 0x33, 0x73 }, /* ARABIC LETTER SEEN -> 's' */
+ { 0x35, 0x53 }, /* ARABIC LETTER SAD -> 'S' */
+ { 0x36, 0x44 }, /* ARABIC LETTER DAD -> 'D' */
+ { 0x37, 0x54 }, /* ARABIC LETTER TAH -> 'T' */
+ { 0x38, 0x5A }, /* ARABIC LETTER ZAH -> 'Z' */
+ { 0x39, 0x60 }, /* ARABIC LETTER AIN -> '`' */
+ { 0x3A, 0x47 }, /* ARABIC LETTER GHAIN -> 'G' */
+ { 0x41, 0x66 }, /* ARABIC LETTER FEH -> 'f' */
+ { 0x42, 0x71 }, /* ARABIC LETTER QAF -> 'q' */
+ { 0x43, 0x6B }, /* ARABIC LETTER KAF -> 'k' */
+ { 0x44, 0x6C }, /* ARABIC LETTER LAM -> 'l' */
+ { 0x45, 0x6D }, /* ARABIC LETTER MEEM -> 'm' */
+ { 0x46, 0x6E }, /* ARABIC LETTER NOON -> 'n' */
+ { 0x47, 0x68 }, /* ARABIC LETTER HEH -> 'h' */
+ { 0x48, 0x77 }, /* ARABIC LETTER WAW -> 'w' */
+ { 0x49, 0x7E }, /* ARABIC LETTER ALEF MAKSURA -> '~' */
+ { 0x4A, 0x79 }, /* ARABIC LETTER YEH -> 'y' */
+ { 0x4E, 0x61 }, /* ARABIC FATHA -> 'a' */
+ { 0x4F, 0x75 }, /* ARABIC DAMMA -> 'u' */
+ { 0x50, 0x69 }, /* ARABIC KASRA -> 'i' */
+ { 0x51, 0x57 }, /* ARABIC SHADDA -> 'W' */
+ { 0x54, 0x27 }, /* ARABIC HAMZA ABOVE -> ''' */
+ { 0x55, 0x27 }, /* ARABIC HAMZA BELOW -> ''' */
+ { 0x60, 0x30 }, /* ARABIC-INDIC DIGIT ZERO -> '0' */
+ { 0x61, 0x31 }, /* ARABIC-INDIC DIGIT ONE -> '1' */
+ { 0x62, 0x32 }, /* ARABIC-INDIC DIGIT TWO -> '2' */
+ { 0x63, 0x33 }, /* ARABIC-INDIC DIGIT THREE -> '3' */
+ { 0x64, 0x34 }, /* ARABIC-INDIC DIGIT FOUR -> '4' */
+ { 0x65, 0x35 }, /* ARABIC-INDIC DIGIT FIVE -> '5' */
+ { 0x66, 0x36 }, /* ARABIC-INDIC DIGIT SIX -> '6' */
+ { 0x67, 0x37 }, /* ARABIC-INDIC DIGIT SEVEN -> '7' */
+ { 0x68, 0x38 }, /* ARABIC-INDIC DIGIT EIGHT -> '8' */
+ { 0x69, 0x39 }, /* ARABIC-INDIC DIGIT NINE -> '9' */
+ { 0x6A, 0x25 }, /* ARABIC PERCENT SIGN -> '%' */
+ { 0x6B, 0x2E }, /* ARABIC DECIMAL SEPARATOR -> '.' */
+ { 0x6C, 0x2C }, /* ARABIC THOUSANDS SEPARATOR -> ',' */
+ { 0x6D, 0x2A }, /* ARABIC FIVE POINTED STAR -> '*' */
+ { 0x71, 0x00 }, /* ARABIC LETTER ALEF WASLA -> ... */
+ { 0x73, 0x27 }, /* ARABIC LETTER ALEF WITH WAVY HAMZA BELOW -> ''' */
+ { 0x75, 0x27 }, /* ARABIC LETTER HIGH HAMZA ALEF -> ''' */
+ { 0x7B, 0x62 }, /* ARABIC LETTER BEEH -> 'b' */
+ { 0x7C, 0x74 }, /* ARABIC LETTER TEH WITH RING -> 't' */
+ { 0x7D, 0x54 }, /* ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS -> 'T' */
+ { 0x7E, 0x70 }, /* ARABIC LETTER PEH -> 'p' */
+ { 0x82, 0x48 }, /* ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE -> 'H' */
+ { 0x85, 0x48 }, /* ARABIC LETTER HAH WITH THREE DOTS ABOVE -> 'H' */
+ { 0x89, 0x44 }, /* ARABIC LETTER DAL WITH RING -> 'D' */
+ { 0x8A, 0x44 }, /* ARABIC LETTER DAL WITH DOT BELOW -> 'D' */
+ { 0x8E, 0x64 }, /* ARABIC LETTER DUL -> 'd' */
+ { 0x8F, 0x44 }, /* ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS -> 'D' */
+ { 0x90, 0x44 }, /* ARABIC LETTER DAL WITH FOUR DOTS ABOVE -> 'D' */
+ { 0x92, 0x00 }, /* ARABIC LETTER REH WITH SMALL V -> ... */
+ { 0x97, 0x52 }, /* ARABIC LETTER REH WITH TWO DOTS ABOVE -> 'R' */
+ { 0x98, 0x6A }, /* ARABIC LETTER JEH -> 'j' */
+ { 0x99, 0x52 }, /* ARABIC LETTER REH WITH FOUR DOTS ABOVE -> 'R' */
+ { 0x9A, 0x00 }, /* ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE -> ... */
+ { 0x9E, 0x53 }, /* ARABIC LETTER SAD WITH THREE DOTS ABOVE -> 'S' */
+ { 0x9F, 0x54 }, /* ARABIC LETTER TAH WITH THREE DOTS ABOVE -> 'T' */
+ { 0xA1, 0x00 }, /* ARABIC LETTER DOTLESS FEH -> ... */
+ { 0xA3, 0x46 }, /* ARABIC LETTER FEH WITH DOT BELOW -> 'F' */
+ { 0xA4, 0x76 }, /* ARABIC LETTER VEH -> 'v' */
+ { 0xA5, 0x66 }, /* ARABIC LETTER FEH WITH THREE DOTS BELOW -> 'f' */
+ { 0xA7, 0x51 }, /* ARABIC LETTER QAF WITH DOT ABOVE -> 'Q' */
+ { 0xA8, 0x51 }, /* ARABIC LETTER QAF WITH THREE DOTS ABOVE -> 'Q' */
+ { 0xAA, 0x6B }, /* ARABIC LETTER SWASH KAF -> 'k' */
+ { 0xAB, 0x4B }, /* ARABIC LETTER KAF WITH RING -> 'K' */
+ { 0xAC, 0x4B }, /* ARABIC LETTER KAF WITH DOT ABOVE -> 'K' */
+ { 0xAE, 0x4B }, /* ARABIC LETTER KAF WITH THREE DOTS BELOW -> 'K' */
+ { 0xAF, 0x67 }, /* ARABIC LETTER GAF -> 'g' */
+ { 0xB0, 0x47 }, /* ARABIC LETTER GAF WITH RING -> 'G' */
+ { 0xB1, 0x4E }, /* ARABIC LETTER NGOEH -> 'N' */
+ { 0xB2, 0x00 }, /* ARABIC LETTER GAF WITH TWO DOTS BELOW -> ... */
+ { 0xB4, 0x47 }, /* ARABIC LETTER GAF WITH THREE DOTS ABOVE -> 'G' */
+ { 0xB5, 0x00 }, /* ARABIC LETTER LAM WITH SMALL V -> ... */
+ { 0xB8, 0x4C }, /* ARABIC LETTER LAM WITH THREE DOTS BELOW -> 'L' */
+ { 0xB9, 0x00 }, /* ARABIC LETTER NOON WITH DOT BELOW -> ... */
+ { 0xBD, 0x4E }, /* ARABIC LETTER NOON WITH THREE DOTS ABOVE -> 'N' */
+ { 0xBE, 0x68 }, /* ARABIC LETTER HEH DOACHASHMEE -> 'h' */
+ { 0xC1, 0x68 }, /* ARABIC LETTER HEH GOAL -> 'h' */
+ { 0xC2, 0x48 }, /* ARABIC LETTER HEH GOAL WITH HAMZA ABOVE -> 'H' */
+ { 0xC3, 0x40 }, /* ARABIC LETTER TEH MARBUTA GOAL -> '@' */
+ { 0xC4, 0x57 }, /* ARABIC LETTER WAW WITH RING -> 'W' */
+ { 0xC7, 0x75 }, /* ARABIC LETTER U -> 'u' */
+ { 0xCA, 0x57 }, /* ARABIC LETTER WAW WITH TWO DOTS ABOVE -> 'W' */
+ { 0xCB, 0x76 }, /* ARABIC LETTER VE -> 'v' */
+ { 0xCC, 0x79 }, /* ARABIC LETTER FARSI YEH -> 'y' */
+ { 0xCD, 0x59 }, /* ARABIC LETTER YEH WITH TAIL -> 'Y' */
+ { 0xCE, 0x59 }, /* ARABIC LETTER YEH WITH SMALL V -> 'Y' */
+ { 0xCF, 0x57 }, /* ARABIC LETTER WAW WITH DOT ABOVE -> 'W' */
+ { 0xD2, 0x79 }, /* ARABIC LETTER YEH BARREE -> 'y' */
+ { 0xD4, 0x2E }, /* ARABIC FULL STOP -> '.' */
+ { 0xDD, 0x40 }, /* ARABIC END OF AYAH -> '@' */
+ { 0xDE, 0x23 }, /* ARABIC START OF RUB EL HIZB -> '#' */
+ { 0xE9, 0x5E }, /* ARABIC PLACE OF SAJDAH -> '^' */
+ { 0xF0, 0x30 }, /* EXTENDED ARABIC-INDIC DIGIT ZERO -> '0' */
+ { 0xF1, 0x31 }, /* EXTENDED ARABIC-INDIC DIGIT ONE -> '1' */
+ { 0xF2, 0x32 }, /* EXTENDED ARABIC-INDIC DIGIT TWO -> '2' */
+ { 0xF3, 0x33 }, /* EXTENDED ARABIC-INDIC DIGIT THREE -> '3' */
+ { 0xF4, 0x34 }, /* EXTENDED ARABIC-INDIC DIGIT FOUR -> '4' */
+ { 0xF5, 0x35 }, /* EXTENDED ARABIC-INDIC DIGIT FIVE -> '5' */
+ { 0xF6, 0x36 }, /* EXTENDED ARABIC-INDIC DIGIT SIX -> '6' */
+ { 0xF7, 0x37 }, /* EXTENDED ARABIC-INDIC DIGIT SEVEN -> '7' */
+ { 0xF8, 0x38 }, /* EXTENDED ARABIC-INDIC DIGIT EIGHT -> '8' */
+ { 0xF9, 0x39 }, /* EXTENDED ARABIC-INDIC DIGIT NINE -> '9' */
+ { 0xFB, 0x44 }, /* ARABIC LETTER DAD WITH DOT BELOW -> 'D' */
+ { 0xFD, 0x26 }, /* ARABIC SIGN SINDHI AMPERSAND -> '&' */
+ /* Entries for page 0x07 */
+ { 0x01, 0x2F }, /* SYRIAC SUPRALINEAR FULL STOP -> '/' */
+ { 0x02, 0x2C }, /* SYRIAC SUBLINEAR FULL STOP -> ',' */
+ { 0x03, 0x21 }, /* SYRIAC SUPRALINEAR COLON -> '!' */
+ { 0x04, 0x21 }, /* SYRIAC SUBLINEAR COLON -> '!' */
+ { 0x05, 0x2D }, /* SYRIAC HORIZONTAL COLON -> '-' */
+ { 0x06, 0x2C }, /* SYRIAC COLON SKEWED LEFT -> ',' */
+ { 0x07, 0x2C }, /* SYRIAC COLON SKEWED RIGHT -> ',' */
+ { 0x08, 0x3B }, /* SYRIAC SUPRALINEAR COLON SKEWED LEFT -> ';' */
+ { 0x09, 0x3F }, /* SYRIAC SUBLINEAR COLON SKEWED RIGHT -> '?' */
+ { 0x0A, 0x7E }, /* SYRIAC CONTRACTION -> '~' */
+ { 0x0B, 0x7B }, /* SYRIAC HARKLEAN OBELUS -> '{' */
+ { 0x0C, 0x7D }, /* SYRIAC HARKLEAN METOBELUS -> '}' */
+ { 0x0D, 0x2A }, /* SYRIAC HARKLEAN ASTERISCUS -> '*' */
+ { 0x10, 0x27 }, /* SYRIAC LETTER ALAPH -> ''' */
+ { 0x12, 0x62 }, /* SYRIAC LETTER BETH -> 'b' */
+ { 0x13, 0x67 }, /* SYRIAC LETTER GAMAL -> 'g' */
+ { 0x14, 0x67 }, /* SYRIAC LETTER GAMAL GARSHUNI -> 'g' */
+ { 0x15, 0x64 }, /* SYRIAC LETTER DALATH -> 'd' */
+ { 0x16, 0x64 }, /* SYRIAC LETTER DOTLESS DALATH RISH -> 'd' */
+ { 0x17, 0x68 }, /* SYRIAC LETTER HE -> 'h' */
+ { 0x18, 0x77 }, /* SYRIAC LETTER WAW -> 'w' */
+ { 0x19, 0x7A }, /* SYRIAC LETTER ZAIN -> 'z' */
+ { 0x1A, 0x48 }, /* SYRIAC LETTER HETH -> 'H' */
+ { 0x1B, 0x74 }, /* SYRIAC LETTER TETH -> 't' */
+ { 0x1C, 0x74 }, /* SYRIAC LETTER TETH GARSHUNI -> 't' */
+ { 0x1D, 0x79 }, /* SYRIAC LETTER YUDH -> 'y' */
+ { 0x1F, 0x6B }, /* SYRIAC LETTER KAPH -> 'k' */
+ { 0x20, 0x6C }, /* SYRIAC LETTER LAMADH -> 'l' */
+ { 0x21, 0x6D }, /* SYRIAC LETTER MIM -> 'm' */
+ { 0x22, 0x6E }, /* SYRIAC LETTER NUN -> 'n' */
+ { 0x23, 0x73 }, /* SYRIAC LETTER SEMKATH -> 's' */
+ { 0x24, 0x73 }, /* SYRIAC LETTER FINAL SEMKATH -> 's' */
+ { 0x25, 0x60 }, /* SYRIAC LETTER E -> '`' */
+ { 0x26, 0x70 }, /* SYRIAC LETTER PE -> 'p' */
+ { 0x27, 0x70 }, /* SYRIAC LETTER REVERSED PE -> 'p' */
+ { 0x28, 0x53 }, /* SYRIAC LETTER SADHE -> 'S' */
+ { 0x29, 0x71 }, /* SYRIAC LETTER QAPH -> 'q' */
+ { 0x2A, 0x72 }, /* SYRIAC LETTER RISH -> 'r' */
+ { 0x2C, 0x74 }, /* SYRIAC LETTER TAW -> 't' */
+ { 0x30, 0x00 }, /* SYRIAC PTHAHA ABOVE -> ... */
+ { 0x32, 0x61 }, /* SYRIAC PTHAHA DOTTED -> 'a' */
+ { 0x33, 0x00 }, /* SYRIAC ZQAPHA ABOVE -> ... */
+ { 0x35, 0x41 }, /* SYRIAC ZQAPHA DOTTED -> 'A' */
+ { 0x36, 0x00 }, /* SYRIAC RBASA ABOVE -> ... */
+ { 0x38, 0x65 }, /* SYRIAC DOTTED ZLAMA HORIZONTAL -> 'e' */
+ { 0x39, 0x45 }, /* SYRIAC DOTTED ZLAMA ANGULAR -> 'E' */
+ { 0x3A, 0x69 }, /* SYRIAC HBASA ABOVE -> 'i' */
+ { 0x3B, 0x69 }, /* SYRIAC HBASA BELOW -> 'i' */
+ { 0x3C, 0x00 }, /* SYRIAC HBASA-ESASA DOTTED -> ... */
+ { 0x3E, 0x75 }, /* SYRIAC ESASA BELOW -> 'u' */
+ { 0x3F, 0x6F }, /* SYRIAC RWAHA -> 'o' */
+ { 0x41, 0x60 }, /* SYRIAC QUSHSHAYA -> '`' */
+ { 0x42, 0x27 }, /* SYRIAC RUKKAKHA -> ''' */
+ { 0x45, 0x58 }, /* SYRIAC THREE DOTS ABOVE -> 'X' */
+ { 0x46, 0x51 }, /* SYRIAC THREE DOTS BELOW -> 'Q' */
+ { 0x47, 0x40 }, /* SYRIAC OBLIQUE LINE ABOVE -> '@' */
+ { 0x48, 0x40 }, /* SYRIAC OBLIQUE LINE BELOW -> '@' */
+ { 0x49, 0x7C }, /* SYRIAC MUSIC -> '|' */
+ { 0x4A, 0x2B }, /* SYRIAC BARREKH -> '+' */
+ { 0x80, 0x68 }, /* THAANA LETTER HAA -> 'h' */
+ { 0x82, 0x6E }, /* THAANA LETTER NOONU -> 'n' */
+ { 0x83, 0x72 }, /* THAANA LETTER RAA -> 'r' */
+ { 0x84, 0x62 }, /* THAANA LETTER BAA -> 'b' */
+ { 0x85, 0x4C }, /* THAANA LETTER LHAVIYANI -> 'L' */
+ { 0x86, 0x6B }, /* THAANA LETTER KAAFU -> 'k' */
+ { 0x87, 0x27 }, /* THAANA LETTER ALIFU -> ''' */
+ { 0x88, 0x76 }, /* THAANA LETTER VAAVU -> 'v' */
+ { 0x89, 0x6D }, /* THAANA LETTER MEEMU -> 'm' */
+ { 0x8A, 0x66 }, /* THAANA LETTER FAAFU -> 'f' */
+ { 0x8D, 0x6C }, /* THAANA LETTER LAAMU -> 'l' */
+ { 0x8E, 0x67 }, /* THAANA LETTER GAAFU -> 'g' */
+ { 0x90, 0x73 }, /* THAANA LETTER SEENU -> 's' */
+ { 0x91, 0x64 }, /* THAANA LETTER DAVIYANI -> 'd' */
+ { 0x92, 0x7A }, /* THAANA LETTER ZAVIYANI -> 'z' */
+ { 0x93, 0x74 }, /* THAANA LETTER TAVIYANI -> 't' */
+ { 0x94, 0x79 }, /* THAANA LETTER YAA -> 'y' */
+ { 0x95, 0x70 }, /* THAANA LETTER PAVIYANI -> 'p' */
+ { 0x96, 0x6A }, /* THAANA LETTER JAVIYANI -> 'j' */
+ { 0x9C, 0x7A }, /* THAANA LETTER ZAA -> 'z' */
+ { 0x9E, 0x73 }, /* THAANA LETTER SAADHU -> 's' */
+ { 0x9F, 0x64 }, /* THAANA LETTER DAADHU -> 'd' */
+ { 0xA0, 0x74 }, /* THAANA LETTER TO -> 't' */
+ { 0xA1, 0x7A }, /* THAANA LETTER ZO -> 'z' */
+ { 0xA2, 0x60 }, /* THAANA LETTER AINU -> '`' */
+ { 0xA4, 0x71 }, /* THAANA LETTER QAAFU -> 'q' */
+ { 0xA5, 0x77 }, /* THAANA LETTER WAAVU -> 'w' */
+ { 0xA6, 0x61 }, /* THAANA ABAFILI -> 'a' */
+ { 0xA8, 0x69 }, /* THAANA IBIFILI -> 'i' */
+ { 0xAA, 0x75 }, /* THAANA UBUFILI -> 'u' */
+ { 0xAC, 0x65 }, /* THAANA EBEFILI -> 'e' */
+ { 0xAE, 0x6F }, /* THAANA OBOFILI -> 'o' */
+ /* Entries for page 0x09 */
+ { 0x01, 0x4E }, /* DEVANAGARI SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* DEVANAGARI SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* DEVANAGARI SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* DEVANAGARI LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* DEVANAGARI LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* DEVANAGARI LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* DEVANAGARI LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* DEVANAGARI LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* DEVANAGARI LETTER SHORT E -> 'e' */
+ { 0x0F, 0x65 }, /* DEVANAGARI LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* DEVANAGARI LETTER SHORT O -> 'o' */
+ { 0x13, 0x6F }, /* DEVANAGARI LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* DEVANAGARI LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* DEVANAGARI LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* DEVANAGARI LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* DEVANAGARI LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* DEVANAGARI LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* DEVANAGARI LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* DEVANAGARI LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* DEVANAGARI LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* DEVANAGARI LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* DEVANAGARI LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* DEVANAGARI LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* DEVANAGARI LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* DEVANAGARI LETTER LA -> 'l' */
+ { 0x33, 0x6C }, /* DEVANAGARI LETTER LLA -> 'l' */
+ { 0x35, 0x76 }, /* DEVANAGARI LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* DEVANAGARI LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* DEVANAGARI LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* DEVANAGARI SIGN NUKTA -> ''' */
+ { 0x3D, 0x27 }, /* DEVANAGARI SIGN AVAGRAHA -> ''' */
+ { 0x3F, 0x69 }, /* DEVANAGARI VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* DEVANAGARI VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* DEVANAGARI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* DEVANAGARI VOWEL SIGN SHORT E -> 'e' */
+ { 0x47, 0x65 }, /* DEVANAGARI VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* DEVANAGARI VOWEL SIGN SHORT O -> 'o' */
+ { 0x4B, 0x6F }, /* DEVANAGARI VOWEL SIGN O -> 'o' */
+ { 0x51, 0x27 }, /* DEVANAGARI STRESS SIGN UDATTA -> ''' */
+ { 0x52, 0x27 }, /* DEVANAGARI STRESS SIGN ANUDATTA -> ''' */
+ { 0x53, 0x60 }, /* DEVANAGARI GRAVE ACCENT -> '`' */
+ { 0x54, 0x27 }, /* DEVANAGARI ACUTE ACCENT -> ''' */
+ { 0x58, 0x71 }, /* DEVANAGARI LETTER QA -> 'q' */
+ { 0x5B, 0x7A }, /* DEVANAGARI LETTER ZA -> 'z' */
+ { 0x5E, 0x66 }, /* DEVANAGARI LETTER FA -> 'f' */
+ { 0x62, 0x4C }, /* DEVANAGARI VOWEL SIGN VOCALIC L -> 'L' */
+ { 0x66, 0x30 }, /* DEVANAGARI DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* DEVANAGARI DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* DEVANAGARI DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* DEVANAGARI DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* DEVANAGARI DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* DEVANAGARI DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* DEVANAGARI DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* DEVANAGARI DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* DEVANAGARI DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* DEVANAGARI DIGIT NINE -> '9' */
+ { 0x70, 0x2E }, /* DEVANAGARI ABBREVIATION SIGN -> '.' */
+ { 0x81, 0x4E }, /* BENGALI SIGN CANDRABINDU -> 'N' */
+ { 0x82, 0x4E }, /* BENGALI SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* BENGALI SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* BENGALI LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* BENGALI LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* BENGALI LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* BENGALI LETTER VOCALIC R -> 'R' */
+ { 0x8F, 0x65 }, /* BENGALI LETTER E -> 'e' */
+ { 0x93, 0x6F }, /* BENGALI LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* BENGALI LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* BENGALI LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* BENGALI LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* BENGALI LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* BENGALI LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* BENGALI LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* BENGALI LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* BENGALI LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* BENGALI LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* BENGALI LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* BENGALI LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* BENGALI LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* BENGALI LETTER LA -> 'l' */
+ { 0xB8, 0x73 }, /* BENGALI LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* BENGALI LETTER HA -> 'h' */
+ { 0xBC, 0x27 }, /* BENGALI SIGN NUKTA -> ''' */
+ { 0xBF, 0x69 }, /* BENGALI VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* BENGALI VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* BENGALI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC7, 0x65 }, /* BENGALI VOWEL SIGN E -> 'e' */
+ { 0xCB, 0x6F }, /* BENGALI VOWEL SIGN O -> 'o' */
+ { 0xD7, 0x2B }, /* BENGALI AU LENGTH MARK -> '+' */
+ { 0xE2, 0x4C }, /* BENGALI VOWEL SIGN VOCALIC L -> 'L' */
+ { 0xE6, 0x30 }, /* BENGALI DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* BENGALI DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* BENGALI DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* BENGALI DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* BENGALI DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* BENGALI DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* BENGALI DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* BENGALI DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* BENGALI DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* BENGALI DIGIT NINE -> '9' */
+ /* Entries for page 0x0A */
+ { 0x02, 0x4E }, /* GURMUKHI SIGN BINDI -> 'N' */
+ { 0x05, 0x61 }, /* GURMUKHI LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* GURMUKHI LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* GURMUKHI LETTER U -> 'u' */
+ { 0x15, 0x6B }, /* GURMUKHI LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* GURMUKHI LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* GURMUKHI LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* GURMUKHI LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* GURMUKHI LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* GURMUKHI LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* GURMUKHI LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* GURMUKHI LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* GURMUKHI LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* GURMUKHI LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* GURMUKHI LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* GURMUKHI LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* GURMUKHI LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* GURMUKHI LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* GURMUKHI LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* GURMUKHI LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* GURMUKHI SIGN NUKTA -> ''' */
+ { 0x3F, 0x69 }, /* GURMUKHI VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* GURMUKHI VOWEL SIGN U -> 'u' */
+ { 0x5B, 0x7A }, /* GURMUKHI LETTER ZA -> 'z' */
+ { 0x5E, 0x66 }, /* GURMUKHI LETTER FA -> 'f' */
+ { 0x66, 0x30 }, /* GURMUKHI DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* GURMUKHI DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* GURMUKHI DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* GURMUKHI DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* GURMUKHI DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* GURMUKHI DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* GURMUKHI DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* GURMUKHI DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* GURMUKHI DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* GURMUKHI DIGIT NINE -> '9' */
+ { 0x70, 0x4E }, /* GURMUKHI TIPPI -> 'N' */
+ { 0x71, 0x48 }, /* GURMUKHI ADDAK -> 'H' */
+ { 0x81, 0x4E }, /* GUJARATI SIGN CANDRABINDU -> 'N' */
+ { 0x82, 0x4E }, /* GUJARATI SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* GUJARATI SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* GUJARATI LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* GUJARATI LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* GUJARATI LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* GUJARATI LETTER VOCALIC R -> 'R' */
+ { 0x8F, 0x65 }, /* GUJARATI LETTER E -> 'e' */
+ { 0x93, 0x6F }, /* GUJARATI LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* GUJARATI LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* GUJARATI LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* GUJARATI LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* GUJARATI LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* GUJARATI LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* GUJARATI LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* GUJARATI LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* GUJARATI LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* GUJARATI LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* GUJARATI LETTER MA -> 'm' */
+ { 0xB0, 0x72 }, /* GUJARATI LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* GUJARATI LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* GUJARATI LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* GUJARATI LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* GUJARATI LETTER HA -> 'h' */
+ { 0xBC, 0x27 }, /* GUJARATI SIGN NUKTA -> ''' */
+ { 0xBD, 0x27 }, /* GUJARATI SIGN AVAGRAHA -> ''' */
+ { 0xBF, 0x69 }, /* GUJARATI VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* GUJARATI VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* GUJARATI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC7, 0x65 }, /* GUJARATI VOWEL SIGN E -> 'e' */
+ { 0xCB, 0x6F }, /* GUJARATI VOWEL SIGN O -> 'o' */
+ { 0xE6, 0x30 }, /* GUJARATI DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* GUJARATI DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* GUJARATI DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* GUJARATI DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* GUJARATI DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* GUJARATI DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* GUJARATI DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* GUJARATI DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* GUJARATI DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* GUJARATI DIGIT NINE -> '9' */
+ /* Entries for page 0x0B */
+ { 0x01, 0x4E }, /* ORIYA SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* ORIYA SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* ORIYA SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* ORIYA LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* ORIYA LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* ORIYA LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* ORIYA LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* ORIYA LETTER VOCALIC L -> 'L' */
+ { 0x0F, 0x65 }, /* ORIYA LETTER E -> 'e' */
+ { 0x13, 0x6F }, /* ORIYA LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* ORIYA LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* ORIYA LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* ORIYA LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* ORIYA LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* ORIYA LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* ORIYA LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* ORIYA LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* ORIYA LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* ORIYA LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* ORIYA LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* ORIYA LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* ORIYA LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* ORIYA LETTER LA -> 'l' */
+ { 0x38, 0x73 }, /* ORIYA LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* ORIYA LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* ORIYA SIGN NUKTA -> ''' */
+ { 0x3D, 0x27 }, /* ORIYA SIGN AVAGRAHA -> ''' */
+ { 0x3F, 0x69 }, /* ORIYA VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* ORIYA VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* ORIYA VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x47, 0x65 }, /* ORIYA VOWEL SIGN E -> 'e' */
+ { 0x4B, 0x6F }, /* ORIYA VOWEL SIGN O -> 'o' */
+ { 0x56, 0x2B }, /* ORIYA AI LENGTH MARK -> '+' */
+ { 0x57, 0x2B }, /* ORIYA AU LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* ORIYA DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* ORIYA DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* ORIYA DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* ORIYA DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* ORIYA DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* ORIYA DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* ORIYA DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* ORIYA DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* ORIYA DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* ORIYA DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* TAMIL SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* TAMIL SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* TAMIL LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* TAMIL LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* TAMIL LETTER U -> 'u' */
+ { 0x8E, 0x65 }, /* TAMIL LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* TAMIL LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* TAMIL LETTER KA -> 'k' */
+ { 0x9A, 0x63 }, /* TAMIL LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* TAMIL LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* TAMIL LETTER TA -> 't' */
+ { 0xA8, 0x6E }, /* TAMIL LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* TAMIL LETTER PA -> 'p' */
+ { 0xAE, 0x6D }, /* TAMIL LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* TAMIL LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* TAMIL LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* TAMIL LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* TAMIL LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* TAMIL LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* TAMIL LETTER HA -> 'h' */
+ { 0xBF, 0x69 }, /* TAMIL VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* TAMIL VOWEL SIGN U -> 'u' */
+ { 0xC6, 0x65 }, /* TAMIL VOWEL SIGN E -> 'e' */
+ { 0xCA, 0x6F }, /* TAMIL VOWEL SIGN O -> 'o' */
+ { 0xD7, 0x2B }, /* TAMIL AU LENGTH MARK -> '+' */
+ { 0xE6, 0x30 }, /* TAMIL DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* TAMIL DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* TAMIL DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* TAMIL DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* TAMIL DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* TAMIL DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* TAMIL DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* TAMIL DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* TAMIL DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* TAMIL DIGIT NINE -> '9' */
+ /* Entries for page 0x0C */
+ { 0x01, 0x4E }, /* TELUGU SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* TELUGU SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* TELUGU SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* TELUGU LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* TELUGU LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* TELUGU LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* TELUGU LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* TELUGU LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* TELUGU LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* TELUGU LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* TELUGU LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* TELUGU LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* TELUGU LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* TELUGU LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* TELUGU LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* TELUGU LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* TELUGU LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* TELUGU LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* TELUGU LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* TELUGU LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* TELUGU LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* TELUGU LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* TELUGU LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* TELUGU LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* TELUGU LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* TELUGU LETTER HA -> 'h' */
+ { 0x3F, 0x69 }, /* TELUGU VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* TELUGU VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* TELUGU VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* TELUGU VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* TELUGU VOWEL SIGN O -> 'o' */
+ { 0x55, 0x2B }, /* TELUGU LENGTH MARK -> '+' */
+ { 0x56, 0x2B }, /* TELUGU AI LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* TELUGU DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* TELUGU DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* TELUGU DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* TELUGU DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* TELUGU DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* TELUGU DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* TELUGU DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* TELUGU DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* TELUGU DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* TELUGU DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* KANNADA SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* KANNADA SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* KANNADA LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* KANNADA LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* KANNADA LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* KANNADA LETTER VOCALIC R -> 'R' */
+ { 0x8C, 0x4C }, /* KANNADA LETTER VOCALIC L -> 'L' */
+ { 0x8E, 0x65 }, /* KANNADA LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* KANNADA LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* KANNADA LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* KANNADA LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* KANNADA LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* KANNADA LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* KANNADA LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* KANNADA LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* KANNADA LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* KANNADA LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* KANNADA LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* KANNADA LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* KANNADA LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* KANNADA LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* KANNADA LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* KANNADA LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* KANNADA LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* KANNADA LETTER HA -> 'h' */
+ { 0xBF, 0x69 }, /* KANNADA VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* KANNADA VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* KANNADA VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC6, 0x65 }, /* KANNADA VOWEL SIGN E -> 'e' */
+ { 0xCA, 0x6F }, /* KANNADA VOWEL SIGN O -> 'o' */
+ { 0xD5, 0x2B }, /* KANNADA LENGTH MARK -> '+' */
+ { 0xD6, 0x2B }, /* KANNADA AI LENGTH MARK -> '+' */
+ { 0xE6, 0x30 }, /* KANNADA DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* KANNADA DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* KANNADA DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* KANNADA DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* KANNADA DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* KANNADA DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* KANNADA DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* KANNADA DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* KANNADA DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* KANNADA DIGIT NINE -> '9' */
+ /* Entries for page 0x0D */
+ { 0x02, 0x4E }, /* MALAYALAM SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* MALAYALAM SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* MALAYALAM LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* MALAYALAM LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* MALAYALAM LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* MALAYALAM LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* MALAYALAM LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* MALAYALAM LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* MALAYALAM LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* MALAYALAM LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* MALAYALAM LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* MALAYALAM LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* MALAYALAM LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* MALAYALAM LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* MALAYALAM LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* MALAYALAM LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* MALAYALAM LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* MALAYALAM LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* MALAYALAM LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* MALAYALAM LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* MALAYALAM LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* MALAYALAM LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* MALAYALAM LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* MALAYALAM LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* MALAYALAM LETTER HA -> 'h' */
+ { 0x3F, 0x69 }, /* MALAYALAM VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* MALAYALAM VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* MALAYALAM VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* MALAYALAM VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* MALAYALAM VOWEL SIGN O -> 'o' */
+ { 0x57, 0x2B }, /* MALAYALAM AU LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* MALAYALAM DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* MALAYALAM DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* MALAYALAM DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* MALAYALAM DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* MALAYALAM DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* MALAYALAM DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* MALAYALAM DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* MALAYALAM DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* MALAYALAM DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* MALAYALAM DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* SINHALA SIGN ANUSVARAYA -> 'N' */
+ { 0x83, 0x48 }, /* SINHALA SIGN VISARGAYA -> 'H' */
+ { 0x85, 0x61 }, /* SINHALA LETTER AYANNA -> 'a' */
+ { 0x89, 0x69 }, /* SINHALA LETTER IYANNA -> 'i' */
+ { 0x8B, 0x75 }, /* SINHALA LETTER UYANNA -> 'u' */
+ { 0x8D, 0x52 }, /* SINHALA LETTER IRUYANNA -> 'R' */
+ { 0x8F, 0x4C }, /* SINHALA LETTER ILUYANNA -> 'L' */
+ { 0x91, 0x65 }, /* SINHALA LETTER EYANNA -> 'e' */
+ { 0x94, 0x6F }, /* SINHALA LETTER OYANNA -> 'o' */
+ { 0x9A, 0x6B }, /* SINHALA LETTER ALPAPRAANA KAYANNA -> 'k' */
+ { 0x9C, 0x67 }, /* SINHALA LETTER ALPAPRAANA GAYANNA -> 'g' */
+ { 0xA0, 0x63 }, /* SINHALA LETTER ALPAPRAANA CAYANNA -> 'c' */
+ { 0xA2, 0x6A }, /* SINHALA LETTER ALPAPRAANA JAYANNA -> 'j' */
+ { 0xAD, 0x74 }, /* SINHALA LETTER ALPAPRAANA TAYANNA -> 't' */
+ { 0xAF, 0x64 }, /* SINHALA LETTER ALPAPRAANA DAYANNA -> 'd' */
+ { 0xB1, 0x6E }, /* SINHALA LETTER DANTAJA NAYANNA -> 'n' */
+ { 0xB4, 0x70 }, /* SINHALA LETTER ALPAPRAANA PAYANNA -> 'p' */
+ { 0xB6, 0x62 }, /* SINHALA LETTER ALPAPRAANA BAYANNA -> 'b' */
+ { 0xB8, 0x6D }, /* SINHALA LETTER MAYANNA -> 'm' */
+ { 0xBA, 0x79 }, /* SINHALA LETTER YAYANNA -> 'y' */
+ { 0xBB, 0x72 }, /* SINHALA LETTER RAYANNA -> 'r' */
+ { 0xBD, 0x6C }, /* SINHALA LETTER DANTAJA LAYANNA -> 'l' */
+ { 0xC0, 0x76 }, /* SINHALA LETTER VAYANNA -> 'v' */
+ { 0xC3, 0x73 }, /* SINHALA LETTER DANTAJA SAYANNA -> 's' */
+ { 0xC4, 0x68 }, /* SINHALA LETTER HAYANNA -> 'h' */
+ { 0xC6, 0x66 }, /* SINHALA LETTER FAYANNA -> 'f' */
+ { 0xD2, 0x69 }, /* SINHALA VOWEL SIGN KETTI IS-PILLA -> 'i' */
+ { 0xD4, 0x75 }, /* SINHALA VOWEL SIGN KETTI PAA-PILLA -> 'u' */
+ { 0xD8, 0x52 }, /* SINHALA VOWEL SIGN GAETTA-PILLA -> 'R' */
+ { 0xD9, 0x65 }, /* SINHALA VOWEL SIGN KOMBUVA -> 'e' */
+ { 0xDC, 0x6F }, /* SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA -> 'o' */
+ { 0xDF, 0x4C }, /* SINHALA VOWEL SIGN GAYANUKITTA -> 'L' */
+ /* Entries for page 0x0E */
+ { 0x01, 0x6B }, /* THAI CHARACTER KO KAI -> 'k' */
+ { 0x0D, 0x79 }, /* THAI CHARACTER YO YING -> 'y' */
+ { 0x0E, 0x64 }, /* THAI CHARACTER DO CHADA -> 'd' */
+ { 0x0F, 0x74 }, /* THAI CHARACTER TO PATAK -> 't' */
+ { 0x13, 0x6E }, /* THAI CHARACTER NO NEN -> 'n' */
+ { 0x14, 0x64 }, /* THAI CHARACTER DO DEK -> 'd' */
+ { 0x15, 0x74 }, /* THAI CHARACTER TO TAO -> 't' */
+ { 0x19, 0x6E }, /* THAI CHARACTER NO NU -> 'n' */
+ { 0x1A, 0x62 }, /* THAI CHARACTER BO BAIMAI -> 'b' */
+ { 0x1B, 0x70 }, /* THAI CHARACTER PO PLA -> 'p' */
+ { 0x1D, 0x66 }, /* THAI CHARACTER FO FA -> 'f' */
+ { 0x1F, 0x66 }, /* THAI CHARACTER FO FAN -> 'f' */
+ { 0x21, 0x6D }, /* THAI CHARACTER MO MA -> 'm' */
+ { 0x22, 0x79 }, /* THAI CHARACTER YO YAK -> 'y' */
+ { 0x23, 0x72 }, /* THAI CHARACTER RO RUA -> 'r' */
+ { 0x24, 0x52 }, /* THAI CHARACTER RU -> 'R' */
+ { 0x25, 0x6C }, /* THAI CHARACTER LO LING -> 'l' */
+ { 0x26, 0x4C }, /* THAI CHARACTER LU -> 'L' */
+ { 0x27, 0x77 }, /* THAI CHARACTER WO WAEN -> 'w' */
+ { 0x28, 0x00 }, /* THAI CHARACTER SO SALA -> ... */
+ { 0x2A, 0x73 }, /* THAI CHARACTER SO SUA -> 's' */
+ { 0x2B, 0x68 }, /* THAI CHARACTER HO HIP -> 'h' */
+ { 0x2C, 0x6C }, /* THAI CHARACTER LO CHULA -> 'l' */
+ { 0x2D, 0x60 }, /* THAI CHARACTER O ANG -> '`' */
+ { 0x2E, 0x68 }, /* THAI CHARACTER HO NOKHUK -> 'h' */
+ { 0x2F, 0x7E }, /* THAI CHARACTER PAIYANNOI -> '~' */
+ { 0x30, 0x61 }, /* THAI CHARACTER SARA A -> 'a' */
+ { 0x31, 0x61 }, /* THAI CHARACTER MAI HAN-AKAT -> 'a' */
+ { 0x34, 0x69 }, /* THAI CHARACTER SARA I -> 'i' */
+ { 0x38, 0x75 }, /* THAI CHARACTER SARA U -> 'u' */
+ { 0x3A, 0x27 }, /* THAI CHARACTER PHINTHU -> ''' */
+ { 0x40, 0x65 }, /* THAI CHARACTER SARA E -> 'e' */
+ { 0x42, 0x6F }, /* THAI CHARACTER SARA O -> 'o' */
+ { 0x46, 0x2B }, /* THAI CHARACTER MAIYAMOK -> '+' */
+ { 0x4D, 0x4D }, /* THAI CHARACTER NIKHAHIT -> 'M' */
+ { 0x50, 0x30 }, /* THAI DIGIT ZERO -> '0' */
+ { 0x51, 0x31 }, /* THAI DIGIT ONE -> '1' */
+ { 0x52, 0x32 }, /* THAI DIGIT TWO -> '2' */
+ { 0x53, 0x33 }, /* THAI DIGIT THREE -> '3' */
+ { 0x54, 0x34 }, /* THAI DIGIT FOUR -> '4' */
+ { 0x55, 0x35 }, /* THAI DIGIT FIVE -> '5' */
+ { 0x56, 0x36 }, /* THAI DIGIT SIX -> '6' */
+ { 0x57, 0x37 }, /* THAI DIGIT SEVEN -> '7' */
+ { 0x58, 0x38 }, /* THAI DIGIT EIGHT -> '8' */
+ { 0x59, 0x39 }, /* THAI DIGIT NINE -> '9' */
+ { 0x81, 0x6B }, /* LAO LETTER KO -> 'k' */
+ { 0x8A, 0x73 }, /* LAO LETTER SO TAM -> 's' */
+ { 0x94, 0x64 }, /* LAO LETTER DO -> 'd' */
+ { 0x95, 0x68 }, /* LAO LETTER TO -> 'h' */
+ { 0x99, 0x6E }, /* LAO LETTER NO -> 'n' */
+ { 0x9A, 0x62 }, /* LAO LETTER BO -> 'b' */
+ { 0x9B, 0x70 }, /* LAO LETTER PO -> 'p' */
+ { 0x9D, 0x66 }, /* LAO LETTER FO TAM -> 'f' */
+ { 0x9F, 0x66 }, /* LAO LETTER FO SUNG -> 'f' */
+ { 0xA1, 0x6D }, /* LAO LETTER MO -> 'm' */
+ { 0xA2, 0x79 }, /* LAO LETTER YO -> 'y' */
+ { 0xA3, 0x72 }, /* LAO LETTER LO LING -> 'r' */
+ { 0xA5, 0x6C }, /* LAO LETTER LO LOOT -> 'l' */
+ { 0xA7, 0x77 }, /* LAO LETTER WO -> 'w' */
+ { 0xAA, 0x73 }, /* LAO LETTER SO SUNG -> 's' */
+ { 0xAB, 0x68 }, /* LAO LETTER HO SUNG -> 'h' */
+ { 0xAD, 0x60 }, /* LAO LETTER O -> '`' */
+ { 0xAF, 0x7E }, /* LAO ELLIPSIS -> '~' */
+ { 0xB0, 0x61 }, /* LAO VOWEL SIGN A -> 'a' */
+ { 0xB4, 0x69 }, /* LAO VOWEL SIGN I -> 'i' */
+ { 0xB6, 0x79 }, /* LAO VOWEL SIGN Y -> 'y' */
+ { 0xB8, 0x75 }, /* LAO VOWEL SIGN U -> 'u' */
+ { 0xBB, 0x6F }, /* LAO VOWEL SIGN MAI KON -> 'o' */
+ { 0xBC, 0x6C }, /* LAO SEMIVOWEL SIGN LO -> 'l' */
+ { 0xC0, 0x65 }, /* LAO VOWEL SIGN E -> 'e' */
+ { 0xC2, 0x6F }, /* LAO VOWEL SIGN O -> 'o' */
+ { 0xC6, 0x2B }, /* LAO KO LA -> '+' */
+ { 0xCD, 0x4D }, /* LAO NIGGAHITA -> 'M' */
+ { 0xD0, 0x30 }, /* LAO DIGIT ZERO -> '0' */
+ { 0xD1, 0x31 }, /* LAO DIGIT ONE -> '1' */
+ { 0xD2, 0x32 }, /* LAO DIGIT TWO -> '2' */
+ { 0xD3, 0x33 }, /* LAO DIGIT THREE -> '3' */
+ { 0xD4, 0x34 }, /* LAO DIGIT FOUR -> '4' */
+ { 0xD5, 0x35 }, /* LAO DIGIT FIVE -> '5' */
+ { 0xD6, 0x36 }, /* LAO DIGIT SIX -> '6' */
+ { 0xD7, 0x37 }, /* LAO DIGIT SEVEN -> '7' */
+ { 0xD8, 0x38 }, /* LAO DIGIT EIGHT -> '8' */
+ { 0xD9, 0x39 }, /* LAO DIGIT NINE -> '9' */
+ /* Entries for page 0x0F */
+ { 0x0B, 0x2D }, /* TIBETAN MARK INTERSYLLABIC TSHEG -> '-' */
+ { 0x20, 0x30 }, /* TIBETAN DIGIT ZERO -> '0' */
+ { 0x21, 0x31 }, /* TIBETAN DIGIT ONE -> '1' */
+ { 0x22, 0x32 }, /* TIBETAN DIGIT TWO -> '2' */
+ { 0x23, 0x33 }, /* TIBETAN DIGIT THREE -> '3' */
+ { 0x24, 0x34 }, /* TIBETAN DIGIT FOUR -> '4' */
+ { 0x25, 0x35 }, /* TIBETAN DIGIT FIVE -> '5' */
+ { 0x26, 0x36 }, /* TIBETAN DIGIT SIX -> '6' */
+ { 0x27, 0x37 }, /* TIBETAN DIGIT SEVEN -> '7' */
+ { 0x28, 0x38 }, /* TIBETAN DIGIT EIGHT -> '8' */
+ { 0x29, 0x39 }, /* TIBETAN DIGIT NINE -> '9' */
+ { 0x34, 0x2B }, /* TIBETAN MARK BSDUS RTAGS -> '+' */
+ { 0x35, 0x2A }, /* TIBETAN MARK NGAS BZUNG NYI ZLA -> '*' */
+ { 0x36, 0x5E }, /* TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN -> '^' */
+ { 0x37, 0x5F }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS -> '_' */
+ { 0x39, 0x7E }, /* TIBETAN MARK TSA -PHRU -> '~' */
+ { 0x3B, 0x5D }, /* TIBETAN MARK GUG RTAGS GYAS -> ']' */
+ { 0x40, 0x6B }, /* TIBETAN LETTER KA -> 'k' */
+ { 0x42, 0x67 }, /* TIBETAN LETTER GA -> 'g' */
+ { 0x45, 0x63 }, /* TIBETAN LETTER CA -> 'c' */
+ { 0x47, 0x6A }, /* TIBETAN LETTER JA -> 'j' */
+ { 0x4F, 0x74 }, /* TIBETAN LETTER TA -> 't' */
+ { 0x51, 0x64 }, /* TIBETAN LETTER DA -> 'd' */
+ { 0x53, 0x6E }, /* TIBETAN LETTER NA -> 'n' */
+ { 0x54, 0x70 }, /* TIBETAN LETTER PA -> 'p' */
+ { 0x56, 0x62 }, /* TIBETAN LETTER BA -> 'b' */
+ { 0x58, 0x6D }, /* TIBETAN LETTER MA -> 'm' */
+ { 0x5D, 0x77 }, /* TIBETAN LETTER WA -> 'w' */
+ { 0x5F, 0x7A }, /* TIBETAN LETTER ZA -> 'z' */
+ { 0x60, 0x27 }, /* TIBETAN LETTER -A -> ''' */
+ { 0x61, 0x79 }, /* TIBETAN LETTER YA -> 'y' */
+ { 0x62, 0x72 }, /* TIBETAN LETTER RA -> 'r' */
+ { 0x63, 0x6C }, /* TIBETAN LETTER LA -> 'l' */
+ { 0x66, 0x73 }, /* TIBETAN LETTER SA -> 's' */
+ { 0x67, 0x68 }, /* TIBETAN LETTER HA -> 'h' */
+ { 0x68, 0x61 }, /* TIBETAN LETTER A -> 'a' */
+ { 0x6A, 0x72 }, /* TIBETAN LETTER FIXED-FORM RA -> 'r' */
+ { 0x72, 0x69 }, /* TIBETAN VOWEL SIGN I -> 'i' */
+ { 0x74, 0x75 }, /* TIBETAN VOWEL SIGN U -> 'u' */
+ { 0x76, 0x52 }, /* TIBETAN VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x78, 0x4C }, /* TIBETAN VOWEL SIGN VOCALIC L -> 'L' */
+ { 0x7A, 0x65 }, /* TIBETAN VOWEL SIGN E -> 'e' */
+ { 0x7C, 0x6F }, /* TIBETAN VOWEL SIGN O -> 'o' */
+ { 0x7E, 0x4D }, /* TIBETAN SIGN RJES SU NGA RO -> 'M' */
+ { 0x7F, 0x48 }, /* TIBETAN SIGN RNAM BCAD -> 'H' */
+ { 0x80, 0x69 }, /* TIBETAN VOWEL SIGN REVERSED I -> 'i' */
+ { 0x90, 0x6B }, /* TIBETAN SUBJOINED LETTER KA -> 'k' */
+ { 0x92, 0x67 }, /* TIBETAN SUBJOINED LETTER GA -> 'g' */
+ { 0x95, 0x63 }, /* TIBETAN SUBJOINED LETTER CA -> 'c' */
+ { 0x97, 0x6A }, /* TIBETAN SUBJOINED LETTER JA -> 'j' */
+ { 0x9F, 0x74 }, /* TIBETAN SUBJOINED LETTER TA -> 't' */
+ { 0xA1, 0x64 }, /* TIBETAN SUBJOINED LETTER DA -> 'd' */
+ { 0xA3, 0x6E }, /* TIBETAN SUBJOINED LETTER NA -> 'n' */
+ { 0xA4, 0x70 }, /* TIBETAN SUBJOINED LETTER PA -> 'p' */
+ { 0xA6, 0x62 }, /* TIBETAN SUBJOINED LETTER BA -> 'b' */
+ { 0xA8, 0x6D }, /* TIBETAN SUBJOINED LETTER MA -> 'm' */
+ { 0xAD, 0x77 }, /* TIBETAN SUBJOINED LETTER WA -> 'w' */
+ { 0xAF, 0x7A }, /* TIBETAN SUBJOINED LETTER ZA -> 'z' */
+ { 0xB0, 0x27 }, /* TIBETAN SUBJOINED LETTER -A -> ''' */
+ { 0xB1, 0x79 }, /* TIBETAN SUBJOINED LETTER YA -> 'y' */
+ { 0xB2, 0x72 }, /* TIBETAN SUBJOINED LETTER RA -> 'r' */
+ { 0xB3, 0x6C }, /* TIBETAN SUBJOINED LETTER LA -> 'l' */
+ { 0xB6, 0x73 }, /* TIBETAN SUBJOINED LETTER SA -> 's' */
+ { 0xB7, 0x68 }, /* TIBETAN SUBJOINED LETTER HA -> 'h' */
+ { 0xB8, 0x61 }, /* TIBETAN SUBJOINED LETTER A -> 'a' */
+ { 0xBA, 0x77 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM WA -> 'w' */
+ { 0xBB, 0x79 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM YA -> 'y' */
+ { 0xBC, 0x72 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM RA -> 'r' */
+ { 0xBE, 0x58 }, /* TIBETAN KU RU KHA -> 'X' */
+ /* Entries for page 0x10 */
+ { 0x00, 0x6B }, /* MYANMAR LETTER KA -> 'k' */
+ { 0x02, 0x67 }, /* MYANMAR LETTER GA -> 'g' */
+ { 0x05, 0x63 }, /* MYANMAR LETTER CA -> 'c' */
+ { 0x07, 0x6A }, /* MYANMAR LETTER JA -> 'j' */
+ { 0x12, 0x64 }, /* MYANMAR LETTER DA -> 'd' */
+ { 0x14, 0x6E }, /* MYANMAR LETTER NA -> 'n' */
+ { 0x15, 0x70 }, /* MYANMAR LETTER PA -> 'p' */
+ { 0x17, 0x62 }, /* MYANMAR LETTER BA -> 'b' */
+ { 0x19, 0x6D }, /* MYANMAR LETTER MA -> 'm' */
+ { 0x1A, 0x79 }, /* MYANMAR LETTER YA -> 'y' */
+ { 0x1B, 0x72 }, /* MYANMAR LETTER RA -> 'r' */
+ { 0x1C, 0x6C }, /* MYANMAR LETTER LA -> 'l' */
+ { 0x1D, 0x77 }, /* MYANMAR LETTER WA -> 'w' */
+ { 0x1E, 0x73 }, /* MYANMAR LETTER SA -> 's' */
+ { 0x1F, 0x68 }, /* MYANMAR LETTER HA -> 'h' */
+ { 0x21, 0x61 }, /* MYANMAR LETTER A -> 'a' */
+ { 0x23, 0x69 }, /* MYANMAR LETTER I -> 'i' */
+ { 0x25, 0x75 }, /* MYANMAR LETTER U -> 'u' */
+ { 0x27, 0x65 }, /* MYANMAR LETTER E -> 'e' */
+ { 0x29, 0x6F }, /* MYANMAR LETTER O -> 'o' */
+ { 0x2D, 0x69 }, /* MYANMAR VOWEL SIGN I -> 'i' */
+ { 0x2F, 0x75 }, /* MYANMAR VOWEL SIGN U -> 'u' */
+ { 0x31, 0x65 }, /* MYANMAR VOWEL SIGN E -> 'e' */
+ { 0x36, 0x4E }, /* MYANMAR SIGN ANUSVARA -> 'N' */
+ { 0x37, 0x27 }, /* MYANMAR SIGN DOT BELOW -> ''' */
+ { 0x38, 0x3A }, /* MYANMAR SIGN VISARGA -> ':' */
+ { 0x40, 0x30 }, /* MYANMAR DIGIT ZERO -> '0' */
+ { 0x41, 0x31 }, /* MYANMAR DIGIT ONE -> '1' */
+ { 0x42, 0x32 }, /* MYANMAR DIGIT TWO -> '2' */
+ { 0x43, 0x33 }, /* MYANMAR DIGIT THREE -> '3' */
+ { 0x44, 0x34 }, /* MYANMAR DIGIT FOUR -> '4' */
+ { 0x45, 0x35 }, /* MYANMAR DIGIT FIVE -> '5' */
+ { 0x46, 0x36 }, /* MYANMAR DIGIT SIX -> '6' */
+ { 0x47, 0x37 }, /* MYANMAR DIGIT SEVEN -> '7' */
+ { 0x48, 0x38 }, /* MYANMAR DIGIT EIGHT -> '8' */
+ { 0x49, 0x39 }, /* MYANMAR DIGIT NINE -> '9' */
+ { 0x52, 0x52 }, /* MYANMAR LETTER VOCALIC R -> 'R' */
+ { 0x54, 0x4C }, /* MYANMAR LETTER VOCALIC L -> 'L' */
+ { 0x56, 0x52 }, /* MYANMAR VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x58, 0x4C }, /* MYANMAR VOWEL SIGN VOCALIC L -> 'L' */
+ { 0xA0, 0x41 }, /* GEORGIAN CAPITAL LETTER AN -> 'A' */
+ { 0xA1, 0x42 }, /* GEORGIAN CAPITAL LETTER BAN -> 'B' */
+ { 0xA2, 0x47 }, /* GEORGIAN CAPITAL LETTER GAN -> 'G' */
+ { 0xA3, 0x44 }, /* GEORGIAN CAPITAL LETTER DON -> 'D' */
+ { 0xA4, 0x45 }, /* GEORGIAN CAPITAL LETTER EN -> 'E' */
+ { 0xA5, 0x56 }, /* GEORGIAN CAPITAL LETTER VIN -> 'V' */
+ { 0xA6, 0x5A }, /* GEORGIAN CAPITAL LETTER ZEN -> 'Z' */
+ { 0xA8, 0x49 }, /* GEORGIAN CAPITAL LETTER IN -> 'I' */
+ { 0xA9, 0x4B }, /* GEORGIAN CAPITAL LETTER KAN -> 'K' */
+ { 0xAA, 0x4C }, /* GEORGIAN CAPITAL LETTER LAS -> 'L' */
+ { 0xAB, 0x4D }, /* GEORGIAN CAPITAL LETTER MAN -> 'M' */
+ { 0xAC, 0x4E }, /* GEORGIAN CAPITAL LETTER NAR -> 'N' */
+ { 0xAD, 0x4F }, /* GEORGIAN CAPITAL LETTER ON -> 'O' */
+ { 0xAE, 0x50 }, /* GEORGIAN CAPITAL LETTER PAR -> 'P' */
+ { 0xB0, 0x52 }, /* GEORGIAN CAPITAL LETTER RAE -> 'R' */
+ { 0xB1, 0x53 }, /* GEORGIAN CAPITAL LETTER SAN -> 'S' */
+ { 0xB2, 0x54 }, /* GEORGIAN CAPITAL LETTER TAR -> 'T' */
+ { 0xB3, 0x55 }, /* GEORGIAN CAPITAL LETTER UN -> 'U' */
+ { 0xB7, 0x51 }, /* GEORGIAN CAPITAL LETTER QAR -> 'Q' */
+ { 0xBC, 0x43 }, /* GEORGIAN CAPITAL LETTER CIL -> 'C' */
+ { 0xBE, 0x58 }, /* GEORGIAN CAPITAL LETTER XAN -> 'X' */
+ { 0xBF, 0x4A }, /* GEORGIAN CAPITAL LETTER JHAN -> 'J' */
+ { 0xC0, 0x48 }, /* GEORGIAN CAPITAL LETTER HAE -> 'H' */
+ { 0xC1, 0x45 }, /* GEORGIAN CAPITAL LETTER HE -> 'E' */
+ { 0xC2, 0x59 }, /* GEORGIAN CAPITAL LETTER HIE -> 'Y' */
+ { 0xC3, 0x57 }, /* GEORGIAN CAPITAL LETTER WE -> 'W' */
+ { 0xD0, 0x61 }, /* GEORGIAN LETTER AN -> 'a' */
+ { 0xD1, 0x62 }, /* GEORGIAN LETTER BAN -> 'b' */
+ { 0xD2, 0x67 }, /* GEORGIAN LETTER GAN -> 'g' */
+ { 0xD3, 0x64 }, /* GEORGIAN LETTER DON -> 'd' */
+ { 0xD4, 0x65 }, /* GEORGIAN LETTER EN -> 'e' */
+ { 0xD5, 0x76 }, /* GEORGIAN LETTER VIN -> 'v' */
+ { 0xD6, 0x7A }, /* GEORGIAN LETTER ZEN -> 'z' */
+ { 0xD8, 0x69 }, /* GEORGIAN LETTER IN -> 'i' */
+ { 0xD9, 0x6B }, /* GEORGIAN LETTER KAN -> 'k' */
+ { 0xDA, 0x6C }, /* GEORGIAN LETTER LAS -> 'l' */
+ { 0xDB, 0x6D }, /* GEORGIAN LETTER MAN -> 'm' */
+ { 0xDC, 0x6E }, /* GEORGIAN LETTER NAR -> 'n' */
+ { 0xDD, 0x6F }, /* GEORGIAN LETTER ON -> 'o' */
+ { 0xDE, 0x70 }, /* GEORGIAN LETTER PAR -> 'p' */
+ { 0xE0, 0x72 }, /* GEORGIAN LETTER RAE -> 'r' */
+ { 0xE1, 0x73 }, /* GEORGIAN LETTER SAN -> 's' */
+ { 0xE2, 0x74 }, /* GEORGIAN LETTER TAR -> 't' */
+ { 0xE3, 0x75 }, /* GEORGIAN LETTER UN -> 'u' */
+ { 0xE7, 0x71 }, /* GEORGIAN LETTER QAR -> 'q' */
+ { 0xEC, 0x63 }, /* GEORGIAN LETTER CIL -> 'c' */
+ { 0xEE, 0x78 }, /* GEORGIAN LETTER XAN -> 'x' */
+ { 0xEF, 0x6A }, /* GEORGIAN LETTER JHAN -> 'j' */
+ { 0xF0, 0x68 }, /* GEORGIAN LETTER HAE -> 'h' */
+ { 0xF1, 0x65 }, /* GEORGIAN LETTER HE -> 'e' */
+ { 0xF2, 0x79 }, /* GEORGIAN LETTER HIE -> 'y' */
+ { 0xF3, 0x77 }, /* GEORGIAN LETTER WE -> 'w' */
+ { 0xF6, 0x66 }, /* GEORGIAN LETTER FI -> 'f' */
+ /* Entries for page 0x11 */
+ { 0x00, 0x67 }, /* HANGUL CHOSEONG KIYEOK -> 'g' */
+ { 0x02, 0x6E }, /* HANGUL CHOSEONG NIEUN -> 'n' */
+ { 0x03, 0x64 }, /* HANGUL CHOSEONG TIKEUT -> 'd' */
+ { 0x05, 0x72 }, /* HANGUL CHOSEONG RIEUL -> 'r' */
+ { 0x06, 0x6D }, /* HANGUL CHOSEONG MIEUM -> 'm' */
+ { 0x07, 0x62 }, /* HANGUL CHOSEONG PIEUP -> 'b' */
+ { 0x09, 0x73 }, /* HANGUL CHOSEONG SIOS -> 's' */
+ { 0x0C, 0x6A }, /* HANGUL CHOSEONG CIEUC -> 'j' */
+ { 0x0E, 0x63 }, /* HANGUL CHOSEONG CHIEUCH -> 'c' */
+ { 0x0F, 0x6B }, /* HANGUL CHOSEONG KHIEUKH -> 'k' */
+ { 0x10, 0x74 }, /* HANGUL CHOSEONG THIEUTH -> 't' */
+ { 0x11, 0x70 }, /* HANGUL CHOSEONG PHIEUPH -> 'p' */
+ { 0x12, 0x68 }, /* HANGUL CHOSEONG HIEUH -> 'h' */
+ { 0x35, 0x73 }, /* HANGUL CHOSEONG SIOS-IEUNG -> 's' */
+ { 0x40, 0x5A }, /* HANGUL CHOSEONG PANSIOS -> 'Z' */
+ { 0x41, 0x67 }, /* HANGUL CHOSEONG IEUNG-KIYEOK -> 'g' */
+ { 0x42, 0x64 }, /* HANGUL CHOSEONG IEUNG-TIKEUT -> 'd' */
+ { 0x43, 0x6D }, /* HANGUL CHOSEONG IEUNG-MIEUM -> 'm' */
+ { 0x44, 0x62 }, /* HANGUL CHOSEONG IEUNG-PIEUP -> 'b' */
+ { 0x45, 0x73 }, /* HANGUL CHOSEONG IEUNG-SIOS -> 's' */
+ { 0x46, 0x5A }, /* HANGUL CHOSEONG IEUNG-PANSIOS -> 'Z' */
+ { 0x48, 0x6A }, /* HANGUL CHOSEONG IEUNG-CIEUC -> 'j' */
+ { 0x49, 0x63 }, /* HANGUL CHOSEONG IEUNG-CHIEUCH -> 'c' */
+ { 0x4A, 0x74 }, /* HANGUL CHOSEONG IEUNG-THIEUTH -> 't' */
+ { 0x4B, 0x70 }, /* HANGUL CHOSEONG IEUNG-PHIEUPH -> 'p' */
+ { 0x4C, 0x4E }, /* HANGUL CHOSEONG YESIEUNG -> 'N' */
+ { 0x4D, 0x6A }, /* HANGUL CHOSEONG CIEUC-IEUNG -> 'j' */
+ { 0x59, 0x51 }, /* HANGUL CHOSEONG YEORINHIEUH -> 'Q' */
+ { 0x61, 0x61 }, /* HANGUL JUNGSEONG A -> 'a' */
+ { 0x66, 0x65 }, /* HANGUL JUNGSEONG E -> 'e' */
+ { 0x69, 0x6F }, /* HANGUL JUNGSEONG O -> 'o' */
+ { 0x6E, 0x75 }, /* HANGUL JUNGSEONG U -> 'u' */
+ { 0x75, 0x69 }, /* HANGUL JUNGSEONG I -> 'i' */
+ { 0x9E, 0x55 }, /* HANGUL JUNGSEONG ARAEA -> 'U' */
+ { 0xA8, 0x67 }, /* HANGUL JONGSEONG KIYEOK -> 'g' */
+ { 0xAB, 0x6E }, /* HANGUL JONGSEONG NIEUN -> 'n' */
+ { 0xAE, 0x64 }, /* HANGUL JONGSEONG TIKEUT -> 'd' */
+ { 0xAF, 0x6C }, /* HANGUL JONGSEONG RIEUL -> 'l' */
+ { 0xB7, 0x6D }, /* HANGUL JONGSEONG MIEUM -> 'm' */
+ { 0xB8, 0x62 }, /* HANGUL JONGSEONG PIEUP -> 'b' */
+ { 0xBA, 0x73 }, /* HANGUL JONGSEONG SIOS -> 's' */
+ { 0xBD, 0x6A }, /* HANGUL JONGSEONG CIEUC -> 'j' */
+ { 0xBE, 0x63 }, /* HANGUL JONGSEONG CHIEUCH -> 'c' */
+ { 0xBF, 0x6B }, /* HANGUL JONGSEONG KHIEUKH -> 'k' */
+ { 0xC0, 0x74 }, /* HANGUL JONGSEONG THIEUTH -> 't' */
+ { 0xC1, 0x70 }, /* HANGUL JONGSEONG PHIEUPH -> 'p' */
+ { 0xC2, 0x68 }, /* HANGUL JONGSEONG HIEUH -> 'h' */
+ { 0xEB, 0x5A }, /* HANGUL JONGSEONG PANSIOS -> 'Z' */
+ { 0xEC, 0x67 }, /* HANGUL JONGSEONG IEUNG-KIYEOK -> 'g' */
+ { 0xF0, 0x4E }, /* HANGUL JONGSEONG YESIEUNG -> 'N' */
+ { 0xF9, 0x51 }, /* HANGUL JONGSEONG YEORINHIEUH -> 'Q' */
+ /* Entries for page 0x13 */
+ { 0x61, 0x20 }, /* ETHIOPIC WORDSPACE -> ' ' */
+ { 0x62, 0x2E }, /* ETHIOPIC FULL STOP -> '.' */
+ { 0x63, 0x2C }, /* ETHIOPIC COMMA -> ',' */
+ { 0x64, 0x3B }, /* ETHIOPIC SEMICOLON -> ';' */
+ { 0x65, 0x3A }, /* ETHIOPIC COLON -> ':' */
+ { 0x67, 0x3F }, /* ETHIOPIC QUESTION MARK -> '?' */
+ { 0x69, 0x31 }, /* ETHIOPIC DIGIT ONE -> '1' */
+ { 0x6A, 0x32 }, /* ETHIOPIC DIGIT TWO -> '2' */
+ { 0x6B, 0x33 }, /* ETHIOPIC DIGIT THREE -> '3' */
+ { 0x6C, 0x34 }, /* ETHIOPIC DIGIT FOUR -> '4' */
+ { 0x6D, 0x35 }, /* ETHIOPIC DIGIT FIVE -> '5' */
+ { 0x6E, 0x36 }, /* ETHIOPIC DIGIT SIX -> '6' */
+ { 0x6F, 0x37 }, /* ETHIOPIC DIGIT SEVEN -> '7' */
+ { 0x70, 0x38 }, /* ETHIOPIC DIGIT EIGHT -> '8' */
+ { 0x71, 0x39 }, /* ETHIOPIC DIGIT NINE -> '9' */
+ { 0xA0, 0x61 }, /* CHEROKEE LETTER A -> 'a' */
+ { 0xA1, 0x65 }, /* CHEROKEE LETTER E -> 'e' */
+ { 0xA2, 0x69 }, /* CHEROKEE LETTER I -> 'i' */
+ { 0xA3, 0x6F }, /* CHEROKEE LETTER O -> 'o' */
+ { 0xA4, 0x75 }, /* CHEROKEE LETTER U -> 'u' */
+ { 0xA5, 0x76 }, /* CHEROKEE LETTER V -> 'v' */
+ { 0xCD, 0x73 }, /* CHEROKEE LETTER S -> 's' */
+ /* Entries for page 0x14 */
+ { 0x01, 0x65 }, /* CANADIAN SYLLABICS E -> 'e' */
+ { 0x03, 0x69 }, /* CANADIAN SYLLABICS I -> 'i' */
+ { 0x05, 0x6F }, /* CANADIAN SYLLABICS O -> 'o' */
+ { 0x09, 0x69 }, /* CANADIAN SYLLABICS CARRIER I -> 'i' */
+ { 0x0A, 0x61 }, /* CANADIAN SYLLABICS A -> 'a' */
+ { 0x1D, 0x77 }, /* CANADIAN SYLLABICS Y-CREE W -> 'w' */
+ { 0x1E, 0x27 }, /* CANADIAN SYLLABICS GLOTTAL STOP -> ''' */
+ { 0x1F, 0x74 }, /* CANADIAN SYLLABICS FINAL ACUTE -> 't' */
+ { 0x20, 0x6B }, /* CANADIAN SYLLABICS FINAL GRAVE -> 'k' */
+ { 0x22, 0x73 }, /* CANADIAN SYLLABICS FINAL TOP HALF RING -> 's' */
+ { 0x23, 0x6E }, /* CANADIAN SYLLABICS FINAL RIGHT HALF RING -> 'n' */
+ { 0x24, 0x77 }, /* CANADIAN SYLLABICS FINAL RING -> 'w' */
+ { 0x25, 0x6E }, /* CANADIAN SYLLABICS FINAL DOUBLE ACUTE -> 'n' */
+ { 0x27, 0x77 }, /* CANADIAN SYLLABICS FINAL MIDDLE DOT -> 'w' */
+ { 0x28, 0x63 }, /* CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE -> 'c' */
+ { 0x29, 0x3F }, /* CANADIAN SYLLABICS FINAL PLUS -> '?' */
+ { 0x2A, 0x6C }, /* CANADIAN SYLLABICS FINAL DOWN TACK -> 'l' */
+ { 0x49, 0x70 }, /* CANADIAN SYLLABICS P -> 'p' */
+ { 0x4A, 0x70 }, /* CANADIAN SYLLABICS WEST-CREE P -> 'p' */
+ { 0x4B, 0x68 }, /* CANADIAN SYLLABICS CARRIER H -> 'h' */
+ { 0x66, 0x74 }, /* CANADIAN SYLLABICS T -> 't' */
+ { 0x83, 0x6B }, /* CANADIAN SYLLABICS K -> 'k' */
+ { 0xA1, 0x63 }, /* CANADIAN SYLLABICS C -> 'c' */
+ { 0xBB, 0x6D }, /* CANADIAN SYLLABICS M -> 'm' */
+ { 0xBC, 0x6D }, /* CANADIAN SYLLABICS WEST-CREE M -> 'm' */
+ { 0xBE, 0x6D }, /* CANADIAN SYLLABICS ATHAPASCAN M -> 'm' */
+ { 0xBF, 0x6D }, /* CANADIAN SYLLABICS SAYISI M -> 'm' */
+ { 0xD0, 0x6E }, /* CANADIAN SYLLABICS N -> 'n' */
+ { 0xEA, 0x00 }, /* CANADIAN SYLLABICS L -> ... */
+ { 0xEC, 0x6C }, /* CANADIAN SYLLABICS MEDIAL L -> 'l' */
+ /* Entries for page 0x15 */
+ { 0x05, 0x73 }, /* CANADIAN SYLLABICS S -> 's' */
+ { 0x06, 0x73 }, /* CANADIAN SYLLABICS ATHAPASCAN S -> 's' */
+ { 0x08, 0x73 }, /* CANADIAN SYLLABICS BLACKFOOT S -> 's' */
+ { 0x3E, 0x00 }, /* CANADIAN SYLLABICS Y -> ... */
+ { 0x40, 0x79 }, /* CANADIAN SYLLABICS WEST-CREE Y -> 'y' */
+ { 0x50, 0x00 }, /* CANADIAN SYLLABICS R -> ... */
+ { 0x52, 0x72 }, /* CANADIAN SYLLABICS MEDIAL R -> 'r' */
+ { 0x5D, 0x66 }, /* CANADIAN SYLLABICS F -> 'f' */
+ { 0x7B, 0x68 }, /* CANADIAN SYLLABICS NUNAVIK H -> 'h' */
+ { 0x7C, 0x68 }, /* CANADIAN SYLLABICS NUNAVUT H -> 'h' */
+ { 0x85, 0x71 }, /* CANADIAN SYLLABICS Q -> 'q' */
+ { 0xAF, 0x62 }, /* CANADIAN SYLLABICS AIVILIK B -> 'b' */
+ { 0xB0, 0x65 }, /* CANADIAN SYLLABICS BLACKFOOT E -> 'e' */
+ { 0xB1, 0x69 }, /* CANADIAN SYLLABICS BLACKFOOT I -> 'i' */
+ { 0xB2, 0x6F }, /* CANADIAN SYLLABICS BLACKFOOT O -> 'o' */
+ { 0xB3, 0x61 }, /* CANADIAN SYLLABICS BLACKFOOT A -> 'a' */
+ { 0xEE, 0x70 }, /* CANADIAN SYLLABICS CARRIER P -> 'p' */
+ /* Entries for page 0x16 */
+ { 0x46, 0x7A }, /* CANADIAN SYLLABICS CARRIER Z -> 'z' */
+ { 0x47, 0x7A }, /* CANADIAN SYLLABICS CARRIER INITIAL Z -> 'z' */
+ { 0x6D, 0x58 }, /* CANADIAN SYLLABICS CHI SIGN -> 'X' */
+ { 0x6E, 0x2E }, /* CANADIAN SYLLABICS FULL STOP -> '.' */
+ { 0x80, 0x20 }, /* OGHAM SPACE MARK -> ' ' */
+ { 0x81, 0x62 }, /* OGHAM LETTER BEITH -> 'b' */
+ { 0x82, 0x6C }, /* OGHAM LETTER LUIS -> 'l' */
+ { 0x83, 0x66 }, /* OGHAM LETTER FEARN -> 'f' */
+ { 0x84, 0x73 }, /* OGHAM LETTER SAIL -> 's' */
+ { 0x85, 0x6E }, /* OGHAM LETTER NION -> 'n' */
+ { 0x86, 0x68 }, /* OGHAM LETTER UATH -> 'h' */
+ { 0x87, 0x64 }, /* OGHAM LETTER DAIR -> 'd' */
+ { 0x88, 0x74 }, /* OGHAM LETTER TINNE -> 't' */
+ { 0x89, 0x63 }, /* OGHAM LETTER COLL -> 'c' */
+ { 0x8A, 0x71 }, /* OGHAM LETTER CEIRT -> 'q' */
+ { 0x8B, 0x6D }, /* OGHAM LETTER MUIN -> 'm' */
+ { 0x8C, 0x67 }, /* OGHAM LETTER GORT -> 'g' */
+ { 0x8E, 0x7A }, /* OGHAM LETTER STRAIF -> 'z' */
+ { 0x8F, 0x72 }, /* OGHAM LETTER RUIS -> 'r' */
+ { 0x90, 0x61 }, /* OGHAM LETTER AILM -> 'a' */
+ { 0x91, 0x6F }, /* OGHAM LETTER ONN -> 'o' */
+ { 0x92, 0x75 }, /* OGHAM LETTER UR -> 'u' */
+ { 0x93, 0x65 }, /* OGHAM LETTER EADHADH -> 'e' */
+ { 0x94, 0x69 }, /* OGHAM LETTER IODHADH -> 'i' */
+ { 0x98, 0x70 }, /* OGHAM LETTER IFIN -> 'p' */
+ { 0x99, 0x78 }, /* OGHAM LETTER EAMHANCHOLL -> 'x' */
+ { 0x9A, 0x70 }, /* OGHAM LETTER PEITH -> 'p' */
+ { 0x9B, 0x3C }, /* OGHAM FEATHER MARK -> '<' */
+ { 0x9C, 0x3E }, /* OGHAM REVERSED FEATHER MARK -> '>' */
+ { 0xA0, 0x66 }, /* RUNIC LETTER FEHU FEOH FE F -> 'f' */
+ { 0xA1, 0x76 }, /* RUNIC LETTER V -> 'v' */
+ { 0xA2, 0x75 }, /* RUNIC LETTER URUZ UR U -> 'u' */
+ { 0xA4, 0x79 }, /* RUNIC LETTER Y -> 'y' */
+ { 0xA5, 0x77 }, /* RUNIC LETTER W -> 'w' */
+ { 0xA8, 0x61 }, /* RUNIC LETTER ANSUZ A -> 'a' */
+ { 0xA9, 0x6F }, /* RUNIC LETTER OS O -> 'o' */
+ { 0xAC, 0x00 }, /* RUNIC LETTER LONG-BRANCH-OSS O -> ... */
+ { 0xAE, 0x6F }, /* RUNIC LETTER O -> 'o' */
+ { 0xB1, 0x72 }, /* RUNIC LETTER RAIDO RAD REID R -> 'r' */
+ { 0xB2, 0x6B }, /* RUNIC LETTER KAUNA -> 'k' */
+ { 0xB3, 0x63 }, /* RUNIC LETTER CEN -> 'c' */
+ { 0xB4, 0x6B }, /* RUNIC LETTER KAUN K -> 'k' */
+ { 0xB5, 0x67 }, /* RUNIC LETTER G -> 'g' */
+ { 0xB7, 0x67 }, /* RUNIC LETTER GEBO GYFU G -> 'g' */
+ { 0xB8, 0x67 }, /* RUNIC LETTER GAR -> 'g' */
+ { 0xB9, 0x77 }, /* RUNIC LETTER WUNJO WYNN W -> 'w' */
+ { 0xBA, 0x00 }, /* RUNIC LETTER HAGLAZ H -> ... */
+ { 0xBD, 0x68 }, /* RUNIC LETTER SHORT-TWIG-HAGALL H -> 'h' */
+ { 0xBE, 0x00 }, /* RUNIC LETTER NAUDIZ NYD NAUD N -> ... */
+ { 0xC0, 0x6E }, /* RUNIC LETTER DOTTED-N -> 'n' */
+ { 0xC1, 0x69 }, /* RUNIC LETTER ISAZ IS ISS I -> 'i' */
+ { 0xC2, 0x65 }, /* RUNIC LETTER E -> 'e' */
+ { 0xC3, 0x6A }, /* RUNIC LETTER JERAN J -> 'j' */
+ { 0xC4, 0x67 }, /* RUNIC LETTER GER -> 'g' */
+ { 0xC6, 0x61 }, /* RUNIC LETTER SHORT-TWIG-AR A -> 'a' */
+ { 0xC8, 0x70 }, /* RUNIC LETTER PERTHO PEORTH P -> 'p' */
+ { 0xC9, 0x7A }, /* RUNIC LETTER ALGIZ EOLHX -> 'z' */
+ { 0xCA, 0x00 }, /* RUNIC LETTER SOWILO S -> ... */
+ { 0xCC, 0x73 }, /* RUNIC LETTER SHORT-TWIG-SOL S -> 's' */
+ { 0xCD, 0x63 }, /* RUNIC LETTER C -> 'c' */
+ { 0xCE, 0x7A }, /* RUNIC LETTER Z -> 'z' */
+ { 0xCF, 0x74 }, /* RUNIC LETTER TIWAZ TIR TYR T -> 't' */
+ { 0xD0, 0x74 }, /* RUNIC LETTER SHORT-TWIG-TYR T -> 't' */
+ { 0xD1, 0x64 }, /* RUNIC LETTER D -> 'd' */
+ { 0xD2, 0x62 }, /* RUNIC LETTER BERKANAN BEORC BJARKAN B -> 'b' */
+ { 0xD3, 0x62 }, /* RUNIC LETTER SHORT-TWIG-BJARKAN B -> 'b' */
+ { 0xD4, 0x70 }, /* RUNIC LETTER DOTTED-P -> 'p' */
+ { 0xD5, 0x70 }, /* RUNIC LETTER OPEN-P -> 'p' */
+ { 0xD6, 0x65 }, /* RUNIC LETTER EHWAZ EH E -> 'e' */
+ { 0xD7, 0x00 }, /* RUNIC LETTER MANNAZ MAN M -> ... */
+ { 0xD9, 0x6D }, /* RUNIC LETTER SHORT-TWIG-MADR M -> 'm' */
+ { 0xDA, 0x6C }, /* RUNIC LETTER LAUKAZ LAGU LOGR L -> 'l' */
+ { 0xDB, 0x6C }, /* RUNIC LETTER DOTTED-L -> 'l' */
+ { 0xDE, 0x64 }, /* RUNIC LETTER DAGAZ DAEG D -> 'd' */
+ { 0xDF, 0x6F }, /* RUNIC LETTER OTHALAN ETHEL O -> 'o' */
+ { 0xE5, 0x73 }, /* RUNIC LETTER STAN -> 's' */
+ { 0xE9, 0x71 }, /* RUNIC LETTER Q -> 'q' */
+ { 0xEA, 0x78 }, /* RUNIC LETTER X -> 'x' */
+ { 0xEB, 0x2E }, /* RUNIC SINGLE PUNCTUATION -> '.' */
+ { 0xEC, 0x3A }, /* RUNIC MULTIPLE PUNCTUATION -> ':' */
+ { 0xED, 0x2B }, /* RUNIC CROSS PUNCTUATION -> '+' */
+ /* Entries for page 0x17 */
+ { 0x80, 0x6B }, /* KHMER LETTER KA -> 'k' */
+ { 0x82, 0x67 }, /* KHMER LETTER KO -> 'g' */
+ { 0x85, 0x63 }, /* KHMER LETTER CA -> 'c' */
+ { 0x87, 0x6A }, /* KHMER LETTER CO -> 'j' */
+ { 0x8A, 0x74 }, /* KHMER LETTER DA -> 't' */
+ { 0x8C, 0x64 }, /* KHMER LETTER DO -> 'd' */
+ { 0x8F, 0x74 }, /* KHMER LETTER TA -> 't' */
+ { 0x91, 0x64 }, /* KHMER LETTER TO -> 'd' */
+ { 0x93, 0x6E }, /* KHMER LETTER NO -> 'n' */
+ { 0x94, 0x70 }, /* KHMER LETTER BA -> 'p' */
+ { 0x96, 0x62 }, /* KHMER LETTER PO -> 'b' */
+ { 0x98, 0x6D }, /* KHMER LETTER MO -> 'm' */
+ { 0x99, 0x79 }, /* KHMER LETTER YO -> 'y' */
+ { 0x9A, 0x72 }, /* KHMER LETTER RO -> 'r' */
+ { 0x9B, 0x6C }, /* KHMER LETTER LO -> 'l' */
+ { 0x9C, 0x76 }, /* KHMER LETTER VO -> 'v' */
+ { 0x9F, 0x73 }, /* KHMER LETTER SA -> 's' */
+ { 0xA0, 0x68 }, /* KHMER LETTER HA -> 'h' */
+ { 0xA1, 0x6C }, /* KHMER LETTER LA -> 'l' */
+ { 0xA2, 0x71 }, /* KHMER LETTER QA -> 'q' */
+ { 0xA3, 0x61 }, /* KHMER INDEPENDENT VOWEL QAQ -> 'a' */
+ { 0xA5, 0x69 }, /* KHMER INDEPENDENT VOWEL QI -> 'i' */
+ { 0xA7, 0x75 }, /* KHMER INDEPENDENT VOWEL QU -> 'u' */
+ { 0xAF, 0x65 }, /* KHMER INDEPENDENT VOWEL QE -> 'e' */
+ { 0xB4, 0x61 }, /* KHMER VOWEL INHERENT AQ -> 'a' */
+ { 0xB7, 0x69 }, /* KHMER VOWEL SIGN I -> 'i' */
+ { 0xB9, 0x79 }, /* KHMER VOWEL SIGN Y -> 'y' */
+ { 0xBB, 0x75 }, /* KHMER VOWEL SIGN U -> 'u' */
+ { 0xC1, 0x65 }, /* KHMER VOWEL SIGN E -> 'e' */
+ { 0xC6, 0x4D }, /* KHMER SIGN NIKAHIT -> 'M' */
+ { 0xC7, 0x48 }, /* KHMER SIGN REAHMUK -> 'H' */
+ { 0xCC, 0x72 }, /* KHMER SIGN ROBAT -> 'r' */
+ { 0xCE, 0x21 }, /* KHMER SIGN KAKABAT -> '!' */
+ { 0xD4, 0x2E }, /* KHMER SIGN KHAN -> '.' */
+ { 0xD6, 0x3A }, /* KHMER SIGN CAMNUC PII KUUH -> ':' */
+ { 0xD7, 0x2B }, /* KHMER SIGN LEK TOO -> '+' */
+ { 0xDC, 0x27 }, /* KHMER SIGN AVAKRAHASANYA -> ''' */
+ { 0xE0, 0x30 }, /* KHMER DIGIT ZERO -> '0' */
+ { 0xE1, 0x31 }, /* KHMER DIGIT ONE -> '1' */
+ { 0xE2, 0x32 }, /* KHMER DIGIT TWO -> '2' */
+ { 0xE3, 0x33 }, /* KHMER DIGIT THREE -> '3' */
+ { 0xE4, 0x34 }, /* KHMER DIGIT FOUR -> '4' */
+ { 0xE5, 0x35 }, /* KHMER DIGIT FIVE -> '5' */
+ { 0xE6, 0x36 }, /* KHMER DIGIT SIX -> '6' */
+ { 0xE7, 0x37 }, /* KHMER DIGIT SEVEN -> '7' */
+ { 0xE8, 0x38 }, /* KHMER DIGIT EIGHT -> '8' */
+ { 0xE9, 0x39 }, /* KHMER DIGIT NINE -> '9' */
+ /* Entries for page 0x18 */
+ { 0x07, 0x2D }, /* MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER -> '-' */
+ { 0x10, 0x30 }, /* MONGOLIAN DIGIT ZERO -> '0' */
+ { 0x11, 0x31 }, /* MONGOLIAN DIGIT ONE -> '1' */
+ { 0x12, 0x32 }, /* MONGOLIAN DIGIT TWO -> '2' */
+ { 0x13, 0x33 }, /* MONGOLIAN DIGIT THREE -> '3' */
+ { 0x14, 0x34 }, /* MONGOLIAN DIGIT FOUR -> '4' */
+ { 0x15, 0x35 }, /* MONGOLIAN DIGIT FIVE -> '5' */
+ { 0x16, 0x36 }, /* MONGOLIAN DIGIT SIX -> '6' */
+ { 0x17, 0x37 }, /* MONGOLIAN DIGIT SEVEN -> '7' */
+ { 0x18, 0x38 }, /* MONGOLIAN DIGIT EIGHT -> '8' */
+ { 0x19, 0x39 }, /* MONGOLIAN DIGIT NINE -> '9' */
+ { 0x20, 0x61 }, /* MONGOLIAN LETTER A -> 'a' */
+ { 0x21, 0x65 }, /* MONGOLIAN LETTER E -> 'e' */
+ { 0x22, 0x69 }, /* MONGOLIAN LETTER I -> 'i' */
+ { 0x23, 0x6F }, /* MONGOLIAN LETTER O -> 'o' */
+ { 0x24, 0x75 }, /* MONGOLIAN LETTER U -> 'u' */
+ { 0x25, 0x4F }, /* MONGOLIAN LETTER OE -> 'O' */
+ { 0x26, 0x55 }, /* MONGOLIAN LETTER UE -> 'U' */
+ { 0x28, 0x6E }, /* MONGOLIAN LETTER NA -> 'n' */
+ { 0x2A, 0x62 }, /* MONGOLIAN LETTER BA -> 'b' */
+ { 0x2B, 0x70 }, /* MONGOLIAN LETTER PA -> 'p' */
+ { 0x2C, 0x71 }, /* MONGOLIAN LETTER QA -> 'q' */
+ { 0x2D, 0x67 }, /* MONGOLIAN LETTER GA -> 'g' */
+ { 0x2E, 0x6D }, /* MONGOLIAN LETTER MA -> 'm' */
+ { 0x2F, 0x6C }, /* MONGOLIAN LETTER LA -> 'l' */
+ { 0x30, 0x73 }, /* MONGOLIAN LETTER SA -> 's' */
+ { 0x32, 0x74 }, /* MONGOLIAN LETTER TA -> 't' */
+ { 0x33, 0x64 }, /* MONGOLIAN LETTER DA -> 'd' */
+ { 0x35, 0x6A }, /* MONGOLIAN LETTER JA -> 'j' */
+ { 0x36, 0x79 }, /* MONGOLIAN LETTER YA -> 'y' */
+ { 0x37, 0x72 }, /* MONGOLIAN LETTER RA -> 'r' */
+ { 0x38, 0x77 }, /* MONGOLIAN LETTER WA -> 'w' */
+ { 0x39, 0x66 }, /* MONGOLIAN LETTER FA -> 'f' */
+ { 0x3A, 0x6B }, /* MONGOLIAN LETTER KA -> 'k' */
+ { 0x3D, 0x7A }, /* MONGOLIAN LETTER ZA -> 'z' */
+ { 0x3E, 0x68 }, /* MONGOLIAN LETTER HAA -> 'h' */
+ { 0x43, 0x2D }, /* MONGOLIAN LETTER TODO LONG VOWEL SIGN -> '-' */
+ { 0x44, 0x65 }, /* MONGOLIAN LETTER TODO E -> 'e' */
+ { 0x45, 0x69 }, /* MONGOLIAN LETTER TODO I -> 'i' */
+ { 0x46, 0x6F }, /* MONGOLIAN LETTER TODO O -> 'o' */
+ { 0x47, 0x75 }, /* MONGOLIAN LETTER TODO U -> 'u' */
+ { 0x48, 0x4F }, /* MONGOLIAN LETTER TODO OE -> 'O' */
+ { 0x49, 0x55 }, /* MONGOLIAN LETTER TODO UE -> 'U' */
+ { 0x4B, 0x62 }, /* MONGOLIAN LETTER TODO BA -> 'b' */
+ { 0x4C, 0x70 }, /* MONGOLIAN LETTER TODO PA -> 'p' */
+ { 0x4D, 0x71 }, /* MONGOLIAN LETTER TODO QA -> 'q' */
+ { 0x4E, 0x67 }, /* MONGOLIAN LETTER TODO GA -> 'g' */
+ { 0x4F, 0x6D }, /* MONGOLIAN LETTER TODO MA -> 'm' */
+ { 0x50, 0x74 }, /* MONGOLIAN LETTER TODO TA -> 't' */
+ { 0x51, 0x64 }, /* MONGOLIAN LETTER TODO DA -> 'd' */
+ { 0x53, 0x6A }, /* MONGOLIAN LETTER TODO JA -> 'j' */
+ { 0x55, 0x79 }, /* MONGOLIAN LETTER TODO YA -> 'y' */
+ { 0x56, 0x77 }, /* MONGOLIAN LETTER TODO WA -> 'w' */
+ { 0x57, 0x6B }, /* MONGOLIAN LETTER TODO KA -> 'k' */
+ { 0x58, 0x67 }, /* MONGOLIAN LETTER TODO GAA -> 'g' */
+ { 0x59, 0x68 }, /* MONGOLIAN LETTER TODO HAA -> 'h' */
+ { 0x5D, 0x65 }, /* MONGOLIAN LETTER SIBE E -> 'e' */
+ { 0x5E, 0x69 }, /* MONGOLIAN LETTER SIBE I -> 'i' */
+ { 0x60, 0x55 }, /* MONGOLIAN LETTER SIBE UE -> 'U' */
+ { 0x61, 0x75 }, /* MONGOLIAN LETTER SIBE U -> 'u' */
+ { 0x63, 0x6B }, /* MONGOLIAN LETTER SIBE KA -> 'k' */
+ { 0x64, 0x67 }, /* MONGOLIAN LETTER SIBE GA -> 'g' */
+ { 0x65, 0x68 }, /* MONGOLIAN LETTER SIBE HA -> 'h' */
+ { 0x66, 0x70 }, /* MONGOLIAN LETTER SIBE PA -> 'p' */
+ { 0x68, 0x74 }, /* MONGOLIAN LETTER SIBE TA -> 't' */
+ { 0x69, 0x64 }, /* MONGOLIAN LETTER SIBE DA -> 'd' */
+ { 0x6A, 0x6A }, /* MONGOLIAN LETTER SIBE JA -> 'j' */
+ { 0x6B, 0x66 }, /* MONGOLIAN LETTER SIBE FA -> 'f' */
+ { 0x6C, 0x67 }, /* MONGOLIAN LETTER SIBE GAA -> 'g' */
+ { 0x6D, 0x68 }, /* MONGOLIAN LETTER SIBE HAA -> 'h' */
+ { 0x6F, 0x7A }, /* MONGOLIAN LETTER SIBE ZA -> 'z' */
+ { 0x70, 0x72 }, /* MONGOLIAN LETTER SIBE RAA -> 'r' */
+ { 0x73, 0x69 }, /* MONGOLIAN LETTER MANCHU I -> 'i' */
+ { 0x74, 0x6B }, /* MONGOLIAN LETTER MANCHU KA -> 'k' */
+ { 0x75, 0x72 }, /* MONGOLIAN LETTER MANCHU RA -> 'r' */
+ { 0x76, 0x66 }, /* MONGOLIAN LETTER MANCHU FA -> 'f' */
+ { 0x81, 0x48 }, /* MONGOLIAN LETTER ALI GALI VISARGA ONE -> 'H' */
+ { 0x82, 0x58 }, /* MONGOLIAN LETTER ALI GALI DAMARU -> 'X' */
+ { 0x83, 0x57 }, /* MONGOLIAN LETTER ALI GALI UBADAMA -> 'W' */
+ { 0x84, 0x4D }, /* MONGOLIAN LETTER ALI GALI INVERTED UBADAMA -> 'M' */
+ { 0x87, 0x61 }, /* MONGOLIAN LETTER ALI GALI A -> 'a' */
+ { 0x88, 0x69 }, /* MONGOLIAN LETTER ALI GALI I -> 'i' */
+ { 0x89, 0x6B }, /* MONGOLIAN LETTER ALI GALI KA -> 'k' */
+ { 0x8B, 0x63 }, /* MONGOLIAN LETTER ALI GALI CA -> 'c' */
+ { 0x90, 0x74 }, /* MONGOLIAN LETTER ALI GALI TA -> 't' */
+ { 0x91, 0x64 }, /* MONGOLIAN LETTER ALI GALI DA -> 'd' */
+ { 0x92, 0x70 }, /* MONGOLIAN LETTER ALI GALI PA -> 'p' */
+ { 0x96, 0x7A }, /* MONGOLIAN LETTER ALI GALI ZA -> 'z' */
+ { 0x97, 0x61 }, /* MONGOLIAN LETTER ALI GALI AH -> 'a' */
+ { 0x98, 0x74 }, /* MONGOLIAN LETTER TODO ALI GALI TA -> 't' */
+ { 0x9C, 0x63 }, /* MONGOLIAN LETTER MANCHU ALI GALI CA -> 'c' */
+ { 0xA0, 0x74 }, /* MONGOLIAN LETTER MANCHU ALI GALI TA -> 't' */
+ { 0xA5, 0x7A }, /* MONGOLIAN LETTER MANCHU ALI GALI ZA -> 'z' */
+ { 0xA6, 0x75 }, /* MONGOLIAN LETTER ALI GALI HALF U -> 'u' */
+ { 0xA7, 0x79 }, /* MONGOLIAN LETTER ALI GALI HALF YA -> 'y' */
+ { 0xA9, 0x27 }, /* MONGOLIAN LETTER ALI GALI DAGALGA -> ''' */
+ /* Entries for page 0x1D */
+ { 0x00, 0x41 }, /* LATIN LETTER SMALL CAPITAL A -> 'A' */
+ { 0x03, 0x42 }, /* LATIN LETTER SMALL CAPITAL BARRED B -> 'B' */
+ { 0x04, 0x43 }, /* LATIN LETTER SMALL CAPITAL C -> 'C' */
+ { 0x05, 0x44 }, /* LATIN LETTER SMALL CAPITAL D -> 'D' */
+ { 0x06, 0x44 }, /* LATIN LETTER SMALL CAPITAL ETH -> 'D' */
+ { 0x07, 0x45 }, /* LATIN LETTER SMALL CAPITAL E -> 'E' */
+ { 0x08, 0x65 }, /* LATIN SMALL LETTER TURNED OPEN E -> 'e' */
+ { 0x09, 0x69 }, /* LATIN SMALL LETTER TURNED I -> 'i' */
+ { 0x0A, 0x4A }, /* LATIN LETTER SMALL CAPITAL J -> 'J' */
+ { 0x0B, 0x4B }, /* LATIN LETTER SMALL CAPITAL K -> 'K' */
+ { 0x0C, 0x4C }, /* LATIN LETTER SMALL CAPITAL L WITH STROKE -> 'L' */
+ { 0x0D, 0x4D }, /* LATIN LETTER SMALL CAPITAL M -> 'M' */
+ { 0x0E, 0x4E }, /* LATIN LETTER SMALL CAPITAL REVERSED N -> 'N' */
+ { 0x0F, 0x4F }, /* LATIN LETTER SMALL CAPITAL O -> 'O' */
+ { 0x11, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O -> 'O' */
+ { 0x13, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O WITH STROKE -> 'O' */
+ { 0x18, 0x50 }, /* LATIN LETTER SMALL CAPITAL P -> 'P' */
+ { 0x19, 0x52 }, /* LATIN LETTER SMALL CAPITAL REVERSED R -> 'R' */
+ { 0x1A, 0x52 }, /* LATIN LETTER SMALL CAPITAL TURNED R -> 'R' */
+ { 0x1B, 0x54 }, /* LATIN LETTER SMALL CAPITAL T -> 'T' */
+ { 0x1C, 0x55 }, /* LATIN LETTER SMALL CAPITAL U -> 'U' */
+ { 0x1D, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS U -> 'u' */
+ { 0x1E, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS DIAERESIZED U -> 'u' */
+ { 0x1F, 0x6D }, /* LATIN SMALL LETTER SIDEWAYS TURNED M -> 'm' */
+ { 0x20, 0x56 }, /* LATIN LETTER SMALL CAPITAL V -> 'V' */
+ { 0x21, 0x57 }, /* LATIN LETTER SMALL CAPITAL W -> 'W' */
+ { 0x22, 0x5A }, /* LATIN LETTER SMALL CAPITAL Z -> 'Z' */
+ { 0x2C, 0x41 }, /* MODIFIER LETTER CAPITAL A -> 'A' */
+ { 0x2E, 0x42 }, /* MODIFIER LETTER CAPITAL B -> 'B' */
+ { 0x2F, 0x42 }, /* MODIFIER LETTER CAPITAL BARRED B -> 'B' */
+ { 0x30, 0x44 }, /* MODIFIER LETTER CAPITAL D -> 'D' */
+ { 0x31, 0x45 }, /* MODIFIER LETTER CAPITAL E -> 'E' */
+ { 0x32, 0x45 }, /* MODIFIER LETTER CAPITAL REVERSED E -> 'E' */
+ { 0x33, 0x47 }, /* MODIFIER LETTER CAPITAL G -> 'G' */
+ { 0x34, 0x48 }, /* MODIFIER LETTER CAPITAL H -> 'H' */
+ { 0x35, 0x49 }, /* MODIFIER LETTER CAPITAL I -> 'I' */
+ { 0x36, 0x4A }, /* MODIFIER LETTER CAPITAL J -> 'J' */
+ { 0x37, 0x4B }, /* MODIFIER LETTER CAPITAL K -> 'K' */
+ { 0x38, 0x4C }, /* MODIFIER LETTER CAPITAL L -> 'L' */
+ { 0x39, 0x4D }, /* MODIFIER LETTER CAPITAL M -> 'M' */
+ { 0x3A, 0x4E }, /* MODIFIER LETTER CAPITAL N -> 'N' */
+ { 0x3B, 0x4E }, /* MODIFIER LETTER CAPITAL REVERSED N -> 'N' */
+ { 0x3C, 0x4F }, /* MODIFIER LETTER CAPITAL O -> 'O' */
+ { 0x3E, 0x50 }, /* MODIFIER LETTER CAPITAL P -> 'P' */
+ { 0x3F, 0x52 }, /* MODIFIER LETTER CAPITAL R -> 'R' */
+ { 0x40, 0x54 }, /* MODIFIER LETTER CAPITAL T -> 'T' */
+ { 0x41, 0x55 }, /* MODIFIER LETTER CAPITAL U -> 'U' */
+ { 0x42, 0x57 }, /* MODIFIER LETTER CAPITAL W -> 'W' */
+ { 0x43, 0x00 }, /* MODIFIER LETTER SMALL A -> ... */
+ { 0x45, 0x61 }, /* MODIFIER LETTER SMALL ALPHA -> 'a' */
+ { 0x47, 0x62 }, /* MODIFIER LETTER SMALL B -> 'b' */
+ { 0x48, 0x64 }, /* MODIFIER LETTER SMALL D -> 'd' */
+ { 0x49, 0x65 }, /* MODIFIER LETTER SMALL E -> 'e' */
+ { 0x4B, 0x65 }, /* MODIFIER LETTER SMALL OPEN E -> 'e' */
+ { 0x4C, 0x65 }, /* MODIFIER LETTER SMALL TURNED OPEN E -> 'e' */
+ { 0x4D, 0x67 }, /* MODIFIER LETTER SMALL G -> 'g' */
+ { 0x4E, 0x69 }, /* MODIFIER LETTER SMALL TURNED I -> 'i' */
+ { 0x4F, 0x6B }, /* MODIFIER LETTER SMALL K -> 'k' */
+ { 0x50, 0x6D }, /* MODIFIER LETTER SMALL M -> 'm' */
+ { 0x52, 0x6F }, /* MODIFIER LETTER SMALL O -> 'o' */
+ { 0x56, 0x70 }, /* MODIFIER LETTER SMALL P -> 'p' */
+ { 0x57, 0x74 }, /* MODIFIER LETTER SMALL T -> 't' */
+ { 0x58, 0x75 }, /* MODIFIER LETTER SMALL U -> 'u' */
+ { 0x59, 0x75 }, /* MODIFIER LETTER SMALL SIDEWAYS U -> 'u' */
+ { 0x5A, 0x6D }, /* MODIFIER LETTER SMALL TURNED M -> 'm' */
+ { 0x5B, 0x76 }, /* MODIFIER LETTER SMALL V -> 'v' */
+ { 0x5D, 0x62 }, /* MODIFIER LETTER SMALL BETA -> 'b' */
+ { 0x5E, 0x67 }, /* MODIFIER LETTER SMALL GREEK GAMMA -> 'g' */
+ { 0x5F, 0x64 }, /* MODIFIER LETTER SMALL DELTA -> 'd' */
+ { 0x60, 0x66 }, /* MODIFIER LETTER SMALL GREEK PHI -> 'f' */
+ { 0x62, 0x69 }, /* LATIN SUBSCRIPT SMALL LETTER I -> 'i' */
+ { 0x63, 0x72 }, /* LATIN SUBSCRIPT SMALL LETTER R -> 'r' */
+ { 0x64, 0x75 }, /* LATIN SUBSCRIPT SMALL LETTER U -> 'u' */
+ { 0x65, 0x76 }, /* LATIN SUBSCRIPT SMALL LETTER V -> 'v' */
+ { 0x66, 0x62 }, /* GREEK SUBSCRIPT SMALL LETTER BETA -> 'b' */
+ { 0x67, 0x67 }, /* GREEK SUBSCRIPT SMALL LETTER GAMMA -> 'g' */
+ { 0x68, 0x72 }, /* GREEK SUBSCRIPT SMALL LETTER RHO -> 'r' */
+ { 0x69, 0x66 }, /* GREEK SUBSCRIPT SMALL LETTER PHI -> 'f' */
+ { 0x6C, 0x62 }, /* LATIN SMALL LETTER B WITH MIDDLE TILDE -> 'b' */
+ { 0x6D, 0x64 }, /* LATIN SMALL LETTER D WITH MIDDLE TILDE -> 'd' */
+ { 0x6E, 0x66 }, /* LATIN SMALL LETTER F WITH MIDDLE TILDE -> 'f' */
+ { 0x6F, 0x6D }, /* LATIN SMALL LETTER M WITH MIDDLE TILDE -> 'm' */
+ { 0x70, 0x6E }, /* LATIN SMALL LETTER N WITH MIDDLE TILDE -> 'n' */
+ { 0x71, 0x70 }, /* LATIN SMALL LETTER P WITH MIDDLE TILDE -> 'p' */
+ { 0x72, 0x72 }, /* LATIN SMALL LETTER R WITH MIDDLE TILDE -> 'r' */
+ { 0x73, 0x72 }, /* LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE -> 'r' */
+ { 0x74, 0x73 }, /* LATIN SMALL LETTER S WITH MIDDLE TILDE -> 's' */
+ { 0x75, 0x74 }, /* LATIN SMALL LETTER T WITH MIDDLE TILDE -> 't' */
+ { 0x76, 0x7A }, /* LATIN SMALL LETTER Z WITH MIDDLE TILDE -> 'z' */
+ { 0x77, 0x67 }, /* LATIN SMALL LETTER TURNED G -> 'g' */
+ { 0x7D, 0x70 }, /* LATIN SMALL LETTER P WITH STROKE -> 'p' */
+ { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH PALATAL HOOK -> 'b' */
+ { 0x81, 0x64 }, /* LATIN SMALL LETTER D WITH PALATAL HOOK -> 'd' */
+ { 0x82, 0x66 }, /* LATIN SMALL LETTER F WITH PALATAL HOOK -> 'f' */
+ { 0x83, 0x67 }, /* LATIN SMALL LETTER G WITH PALATAL HOOK -> 'g' */
+ { 0x84, 0x6B }, /* LATIN SMALL LETTER K WITH PALATAL HOOK -> 'k' */
+ { 0x85, 0x6C }, /* LATIN SMALL LETTER L WITH PALATAL HOOK -> 'l' */
+ { 0x86, 0x6D }, /* LATIN SMALL LETTER M WITH PALATAL HOOK -> 'm' */
+ { 0x87, 0x6E }, /* LATIN SMALL LETTER N WITH PALATAL HOOK -> 'n' */
+ { 0x88, 0x70 }, /* LATIN SMALL LETTER P WITH PALATAL HOOK -> 'p' */
+ { 0x89, 0x72 }, /* LATIN SMALL LETTER R WITH PALATAL HOOK -> 'r' */
+ { 0x8A, 0x73 }, /* LATIN SMALL LETTER S WITH PALATAL HOOK -> 's' */
+ { 0x8C, 0x76 }, /* LATIN SMALL LETTER V WITH PALATAL HOOK -> 'v' */
+ { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH PALATAL HOOK -> 'x' */
+ { 0x8E, 0x7A }, /* LATIN SMALL LETTER Z WITH PALATAL HOOK -> 'z' */
+ /* Entries for page 0x1E */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING BELOW -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH RING BELOW -> 'a' */
+ { 0x02, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT ABOVE -> 'B' */
+ { 0x03, 0x62 }, /* LATIN SMALL LETTER B WITH DOT ABOVE -> 'b' */
+ { 0x04, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT BELOW -> 'B' */
+ { 0x05, 0x62 }, /* LATIN SMALL LETTER B WITH DOT BELOW -> 'b' */
+ { 0x06, 0x42 }, /* LATIN CAPITAL LETTER B WITH LINE BELOW -> 'B' */
+ { 0x07, 0x62 }, /* LATIN SMALL LETTER B WITH LINE BELOW -> 'b' */
+ { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE -> 'C' */
+ { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA AND ACUTE -> 'c' */
+ { 0x0A, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT ABOVE -> 'D' */
+ { 0x0B, 0x64 }, /* LATIN SMALL LETTER D WITH DOT ABOVE -> 'd' */
+ { 0x0C, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT BELOW -> 'D' */
+ { 0x0D, 0x64 }, /* LATIN SMALL LETTER D WITH DOT BELOW -> 'd' */
+ { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH LINE BELOW -> 'D' */
+ { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH LINE BELOW -> 'd' */
+ { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH CEDILLA -> 'D' */
+ { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH CEDILLA -> 'd' */
+ { 0x12, 0x44 }, /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW -> 'D' */
+ { 0x13, 0x64 }, /* LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW -> 'd' */
+ { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE -> 'E' */
+ { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND GRAVE -> 'e' */
+ { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE -> 'E' */
+ { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND ACUTE -> 'e' */
+ { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW -> 'E' */
+ { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW -> 'e' */
+ { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE BELOW -> 'E' */
+ { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE BELOW -> 'e' */
+ { 0x1C, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE -> 'E' */
+ { 0x1D, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA AND BREVE -> 'e' */
+ { 0x1E, 0x46 }, /* LATIN CAPITAL LETTER F WITH DOT ABOVE -> 'F' */
+ { 0x1F, 0x66 }, /* LATIN SMALL LETTER F WITH DOT ABOVE -> 'f' */
+ { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH MACRON -> 'G' */
+ { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH MACRON -> 'g' */
+ { 0x22, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT ABOVE -> 'H' */
+ { 0x23, 0x68 }, /* LATIN SMALL LETTER H WITH DOT ABOVE -> 'h' */
+ { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT BELOW -> 'H' */
+ { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH DOT BELOW -> 'h' */
+ { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH DIAERESIS -> 'H' */
+ { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH DIAERESIS -> 'h' */
+ { 0x28, 0x48 }, /* LATIN CAPITAL LETTER H WITH CEDILLA -> 'H' */
+ { 0x29, 0x68 }, /* LATIN SMALL LETTER H WITH CEDILLA -> 'h' */
+ { 0x2A, 0x48 }, /* LATIN CAPITAL LETTER H WITH BREVE BELOW -> 'H' */
+ { 0x2B, 0x68 }, /* LATIN SMALL LETTER H WITH BREVE BELOW -> 'h' */
+ { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE BELOW -> 'I' */
+ { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE BELOW -> 'i' */
+ { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE -> 'I' */
+ { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE -> 'i' */
+ { 0x30, 0x4B }, /* LATIN CAPITAL LETTER K WITH ACUTE -> 'K' */
+ { 0x31, 0x6B }, /* LATIN SMALL LETTER K WITH ACUTE -> 'k' */
+ { 0x32, 0x4B }, /* LATIN CAPITAL LETTER K WITH DOT BELOW -> 'K' */
+ { 0x33, 0x6B }, /* LATIN SMALL LETTER K WITH DOT BELOW -> 'k' */
+ { 0x34, 0x4B }, /* LATIN CAPITAL LETTER K WITH LINE BELOW -> 'K' */
+ { 0x35, 0x6B }, /* LATIN SMALL LETTER K WITH LINE BELOW -> 'k' */
+ { 0x36, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW -> 'L' */
+ { 0x37, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW -> 'l' */
+ { 0x38, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON -> 'L' */
+ { 0x39, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW AND MACRON -> 'l' */
+ { 0x3A, 0x4C }, /* LATIN CAPITAL LETTER L WITH LINE BELOW -> 'L' */
+ { 0x3B, 0x6C }, /* LATIN SMALL LETTER L WITH LINE BELOW -> 'l' */
+ { 0x3C, 0x4C }, /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW -> 'L' */
+ { 0x3D, 0x6C }, /* LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW -> 'l' */
+ { 0x3E, 0x4D }, /* LATIN CAPITAL LETTER M WITH ACUTE -> 'M' */
+ { 0x3F, 0x6D }, /* LATIN SMALL LETTER M WITH ACUTE -> 'm' */
+ { 0x40, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT ABOVE -> 'M' */
+ { 0x41, 0x6D }, /* LATIN SMALL LETTER M WITH DOT ABOVE -> 'm' */
+ { 0x42, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT BELOW -> 'M' */
+ { 0x43, 0x6D }, /* LATIN SMALL LETTER M WITH DOT BELOW -> 'm' */
+ { 0x44, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT ABOVE -> 'N' */
+ { 0x45, 0x6E }, /* LATIN SMALL LETTER N WITH DOT ABOVE -> 'n' */
+ { 0x46, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT BELOW -> 'N' */
+ { 0x47, 0x6E }, /* LATIN SMALL LETTER N WITH DOT BELOW -> 'n' */
+ { 0x48, 0x4E }, /* LATIN CAPITAL LETTER N WITH LINE BELOW -> 'N' */
+ { 0x49, 0x6E }, /* LATIN SMALL LETTER N WITH LINE BELOW -> 'n' */
+ { 0x4A, 0x4E }, /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW -> 'N' */
+ { 0x4B, 0x6E }, /* LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW -> 'n' */
+ { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE -> 'O' */
+ { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND ACUTE -> 'o' */
+ { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS -> 'O' */
+ { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND DIAERESIS -> 'o' */
+ { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE -> 'O' */
+ { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND GRAVE -> 'o' */
+ { 0x52, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE -> 'O' */
+ { 0x53, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND ACUTE -> 'o' */
+ { 0x54, 0x50 }, /* LATIN CAPITAL LETTER P WITH ACUTE -> 'P' */
+ { 0x55, 0x70 }, /* LATIN SMALL LETTER P WITH ACUTE -> 'p' */
+ { 0x56, 0x50 }, /* LATIN CAPITAL LETTER P WITH DOT ABOVE -> 'P' */
+ { 0x57, 0x70 }, /* LATIN SMALL LETTER P WITH DOT ABOVE -> 'p' */
+ { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT ABOVE -> 'R' */
+ { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH DOT ABOVE -> 'r' */
+ { 0x5A, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW -> 'R' */
+ { 0x5B, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW -> 'r' */
+ { 0x5C, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON -> 'R' */
+ { 0x5D, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW AND MACRON -> 'r' */
+ { 0x5E, 0x52 }, /* LATIN CAPITAL LETTER R WITH LINE BELOW -> 'R' */
+ { 0x5F, 0x72 }, /* LATIN SMALL LETTER R WITH LINE BELOW -> 'r' */
+ { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT ABOVE -> 'S' */
+ { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH DOT ABOVE -> 's' */
+ { 0x62, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW -> 'S' */
+ { 0x63, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW -> 's' */
+ { 0x64, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE -> 'S' */
+ { 0x65, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE -> 's' */
+ { 0x66, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE -> 'S' */
+ { 0x67, 0x73 }, /* LATIN SMALL LETTER S WITH CARON AND DOT ABOVE -> 's' */
+ { 0x68, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE -> 'S' */
+ { 0x69, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE -> 's' */
+ { 0x6A, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT ABOVE -> 'T' */
+ { 0x6B, 0x74 }, /* LATIN SMALL LETTER T WITH DOT ABOVE -> 't' */
+ { 0x6C, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT BELOW -> 'T' */
+ { 0x6D, 0x74 }, /* LATIN SMALL LETTER T WITH DOT BELOW -> 't' */
+ { 0x6E, 0x54 }, /* LATIN CAPITAL LETTER T WITH LINE BELOW -> 'T' */
+ { 0x6F, 0x74 }, /* LATIN SMALL LETTER T WITH LINE BELOW -> 't' */
+ { 0x70, 0x54 }, /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW -> 'T' */
+ { 0x71, 0x74 }, /* LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW -> 't' */
+ { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW -> 'U' */
+ { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS BELOW -> 'u' */
+ { 0x74, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE BELOW -> 'U' */
+ { 0x75, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE BELOW -> 'u' */
+ { 0x76, 0x55 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW -> 'U' */
+ { 0x77, 0x75 }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW -> 'u' */
+ { 0x78, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE -> 'U' */
+ { 0x79, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE AND ACUTE -> 'u' */
+ { 0x7A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS -> 'U' */
+ { 0x7B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON AND DIAERESIS -> 'u' */
+ { 0x7C, 0x56 }, /* LATIN CAPITAL LETTER V WITH TILDE -> 'V' */
+ { 0x7D, 0x76 }, /* LATIN SMALL LETTER V WITH TILDE -> 'v' */
+ { 0x7E, 0x56 }, /* LATIN CAPITAL LETTER V WITH DOT BELOW -> 'V' */
+ { 0x7F, 0x76 }, /* LATIN SMALL LETTER V WITH DOT BELOW -> 'v' */
+ { 0x80, 0x57 }, /* LATIN CAPITAL LETTER W WITH GRAVE -> 'W' */
+ { 0x81, 0x77 }, /* LATIN SMALL LETTER W WITH GRAVE -> 'w' */
+ { 0x82, 0x57 }, /* LATIN CAPITAL LETTER W WITH ACUTE -> 'W' */
+ { 0x83, 0x77 }, /* LATIN SMALL LETTER W WITH ACUTE -> 'w' */
+ { 0x84, 0x57 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS -> 'W' */
+ { 0x85, 0x77 }, /* LATIN SMALL LETTER W WITH DIAERESIS -> 'w' */
+ { 0x86, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT ABOVE -> 'W' */
+ { 0x87, 0x77 }, /* LATIN SMALL LETTER W WITH DOT ABOVE -> 'w' */
+ { 0x88, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT BELOW -> 'W' */
+ { 0x89, 0x77 }, /* LATIN SMALL LETTER W WITH DOT BELOW -> 'w' */
+ { 0x8A, 0x58 }, /* LATIN CAPITAL LETTER X WITH DOT ABOVE -> 'X' */
+ { 0x8B, 0x78 }, /* LATIN SMALL LETTER X WITH DOT ABOVE -> 'x' */
+ { 0x8C, 0x58 }, /* LATIN CAPITAL LETTER X WITH DIAERESIS -> 'X' */
+ { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH DIAERESIS -> 'x' */
+ { 0x8E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT ABOVE -> 'Y' */
+ { 0x8F, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT ABOVE -> 'y' */
+ { 0x90, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX -> 'Z' */
+ { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CIRCUMFLEX -> 'z' */
+ { 0x92, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT BELOW -> 'Z' */
+ { 0x93, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT BELOW -> 'z' */
+ { 0x94, 0x5A }, /* LATIN CAPITAL LETTER Z WITH LINE BELOW -> 'Z' */
+ { 0x95, 0x7A }, /* LATIN SMALL LETTER Z WITH LINE BELOW -> 'z' */
+ { 0x96, 0x68 }, /* LATIN SMALL LETTER H WITH LINE BELOW -> 'h' */
+ { 0x97, 0x74 }, /* LATIN SMALL LETTER T WITH DIAERESIS -> 't' */
+ { 0x98, 0x77 }, /* LATIN SMALL LETTER W WITH RING ABOVE -> 'w' */
+ { 0x99, 0x79 }, /* LATIN SMALL LETTER Y WITH RING ABOVE -> 'y' */
+ { 0x9A, 0x61 }, /* LATIN SMALL LETTER A WITH RIGHT HALF RING -> 'a' */
+ { 0x9B, 0x53 }, /* LATIN SMALL LETTER LONG S WITH DOT ABOVE -> 'S' */
+ { 0xA0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT BELOW -> 'A' */
+ { 0xA1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT BELOW -> 'a' */
+ { 0xA2, 0x41 }, /* LATIN CAPITAL LETTER A WITH HOOK ABOVE -> 'A' */
+ { 0xA3, 0x61 }, /* LATIN SMALL LETTER A WITH HOOK ABOVE -> 'a' */
+ { 0xA4, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'A' */
+ { 0xA5, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'a' */
+ { 0xA6, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'A' */
+ { 0xA7, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'a' */
+ { 0xA8, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'A' */
+ { 0xA9, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'a' */
+ { 0xAA, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE -> 'A' */
+ { 0xAB, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE -> 'a' */
+ { 0xAC, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'A' */
+ { 0xAD, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'a' */
+ { 0xAE, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE -> 'A' */
+ { 0xAF, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND ACUTE -> 'a' */
+ { 0xB0, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE -> 'A' */
+ { 0xB1, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND GRAVE -> 'a' */
+ { 0xB2, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE -> 'A' */
+ { 0xB3, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE -> 'a' */
+ { 0xB4, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE -> 'A' */
+ { 0xB5, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND TILDE -> 'a' */
+ { 0xB6, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW -> 'A' */
+ { 0xB7, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND DOT BELOW -> 'a' */
+ { 0xB8, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT BELOW -> 'E' */
+ { 0xB9, 0x65 }, /* LATIN SMALL LETTER E WITH DOT BELOW -> 'e' */
+ { 0xBA, 0x45 }, /* LATIN CAPITAL LETTER E WITH HOOK ABOVE -> 'E' */
+ { 0xBB, 0x65 }, /* LATIN SMALL LETTER E WITH HOOK ABOVE -> 'e' */
+ { 0xBC, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE -> 'E' */
+ { 0xBD, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE -> 'e' */
+ { 0xBE, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'E' */
+ { 0xBF, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'e' */
+ { 0xC0, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'E' */
+ { 0xC1, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'e' */
+ { 0xC2, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'E' */
+ { 0xC3, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'e' */
+ { 0xC4, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE -> 'E' */
+ { 0xC5, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE -> 'e' */
+ { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'E' */
+ { 0xC7, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'e' */
+ { 0xC8, 0x49 }, /* LATIN CAPITAL LETTER I WITH HOOK ABOVE -> 'I' */
+ { 0xC9, 0x69 }, /* LATIN SMALL LETTER I WITH HOOK ABOVE -> 'i' */
+ { 0xCA, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT BELOW -> 'I' */
+ { 0xCB, 0x69 }, /* LATIN SMALL LETTER I WITH DOT BELOW -> 'i' */
+ { 0xCC, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT BELOW -> 'O' */
+ { 0xCD, 0x6F }, /* LATIN SMALL LETTER O WITH DOT BELOW -> 'o' */
+ { 0xCE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HOOK ABOVE -> 'O' */
+ { 0xCF, 0x6F }, /* LATIN SMALL LETTER O WITH HOOK ABOVE -> 'o' */
+ { 0xD0, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'O' */
+ { 0xD1, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'o' */
+ { 0xD2, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'O' */
+ { 0xD3, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'o' */
+ { 0xD4, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'O' */
+ { 0xD5, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'o' */
+ { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE -> 'O' */
+ { 0xD7, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE -> 'o' */
+ { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'O' */
+ { 0xD9, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'o' */
+ { 0xDA, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE -> 'O' */
+ { 0xDB, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND ACUTE -> 'o' */
+ { 0xDC, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE -> 'O' */
+ { 0xDD, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND GRAVE -> 'o' */
+ { 0xDE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE -> 'O' */
+ { 0xDF, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE -> 'o' */
+ { 0xE0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND TILDE -> 'O' */
+ { 0xE1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND TILDE -> 'o' */
+ { 0xE2, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW -> 'O' */
+ { 0xE3, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND DOT BELOW -> 'o' */
+ { 0xE4, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOT BELOW -> 'U' */
+ { 0xE5, 0x75 }, /* LATIN SMALL LETTER U WITH DOT BELOW -> 'u' */
+ { 0xE6, 0x55 }, /* LATIN CAPITAL LETTER U WITH HOOK ABOVE -> 'U' */
+ { 0xE7, 0x75 }, /* LATIN SMALL LETTER U WITH HOOK ABOVE -> 'u' */
+ { 0xE8, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE -> 'U' */
+ { 0xE9, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND ACUTE -> 'u' */
+ { 0xEA, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE -> 'U' */
+ { 0xEB, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND GRAVE -> 'u' */
+ { 0xEC, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE -> 'U' */
+ { 0xED, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE -> 'u' */
+ { 0xEE, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND TILDE -> 'U' */
+ { 0xEF, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND TILDE -> 'u' */
+ { 0xF0, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW -> 'U' */
+ { 0xF1, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND DOT BELOW -> 'u' */
+ { 0xF2, 0x59 }, /* LATIN CAPITAL LETTER Y WITH GRAVE -> 'Y' */
+ { 0xF3, 0x79 }, /* LATIN SMALL LETTER Y WITH GRAVE -> 'y' */
+ { 0xF4, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT BELOW -> 'Y' */
+ { 0xF5, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT BELOW -> 'y' */
+ { 0xF6, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE -> 'Y' */
+ { 0xF7, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK ABOVE -> 'y' */
+ { 0xF8, 0x59 }, /* LATIN CAPITAL LETTER Y WITH TILDE -> 'Y' */
+ { 0xF9, 0x79 }, /* LATIN SMALL LETTER Y WITH TILDE -> 'y' */
+ /* Entries for page 0x1F */
+ { 0x00, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI -> ... */
+ { 0x07, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'a' */
+ { 0x08, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI -> ... */
+ { 0x0F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'A' */
+ { 0x10, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH PSILI -> ... */
+ { 0x15, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA -> 'e' */
+ { 0x18, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH PSILI -> ... */
+ { 0x1D, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA -> 'E' */
+ { 0x20, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI -> ... */
+ { 0x27, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI -> 'e' */
+ { 0x28, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI -> ... */
+ { 0x2F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI -> 'E' */
+ { 0x30, 0x00 }, /* GREEK SMALL LETTER IOTA WITH PSILI -> ... */
+ { 0x37, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'i' */
+ { 0x38, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH PSILI -> ... */
+ { 0x3F, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'I' */
+ { 0x40, 0x00 }, /* GREEK SMALL LETTER OMICRON WITH PSILI -> ... */
+ { 0x45, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA -> 'o' */
+ { 0x48, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH PSILI -> ... */
+ { 0x4D, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -> 'O' */
+ { 0x50, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH PSILI -> ... */
+ { 0x57, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'u' */
+ { 0x59, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA -> 'U' */
+ { 0x5B, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA -> 'U' */
+ { 0x5D, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA -> 'U' */
+ { 0x5F, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'U' */
+ { 0x60, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI -> ... */
+ { 0x67, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'o' */
+ { 0x68, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI -> ... */
+ { 0x6F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'O' */
+ { 0x70, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH VARIA -> 'a' */
+ { 0x71, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA -> 'a' */
+ { 0x72, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH VARIA -> ... */
+ { 0x75, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA -> 'e' */
+ { 0x76, 0x69 }, /* GREEK SMALL LETTER IOTA WITH VARIA -> 'i' */
+ { 0x77, 0x69 }, /* GREEK SMALL LETTER IOTA WITH OXIA -> 'i' */
+ { 0x78, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH VARIA -> 'o' */
+ { 0x79, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH OXIA -> 'o' */
+ { 0x7A, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH VARIA -> 'u' */
+ { 0x7B, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH OXIA -> 'u' */
+ { 0x7C, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH VARIA -> 'o' */
+ { 0x7D, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA -> 'o' */
+ { 0x80, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0x87, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'a' */
+ { 0x88, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0x8F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'A' */
+ { 0x90, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0x97, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'e' */
+ { 0x98, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0x9F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'E' */
+ { 0xA0, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0xA7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'o' */
+ { 0xA8, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0xAF, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'O' */
+ { 0xB0, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH VRACHY -> ... */
+ { 0xB4, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI -> 'a' */
+ { 0xB6, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI -> 'a' */
+ { 0xB7, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'a' */
+ { 0xB8, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH VRACHY -> ... */
+ { 0xBC, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -> 'A' */
+ { 0xBD, 0x27 }, /* GREEK KORONIS -> ''' */
+ { 0xBE, 0x69 }, /* GREEK PROSGEGRAMMENI -> 'i' */
+ { 0xBF, 0x27 }, /* GREEK PSILI -> ''' */
+ { 0xC0, 0x7E }, /* GREEK PERISPOMENI -> '~' */
+ { 0xC2, 0x00 }, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI -> ... */
+ { 0xC4, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI -> 'e' */
+ { 0xC6, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI -> 'e' */
+ { 0xC7, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'e' */
+ { 0xC8, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH VARIA -> ... */
+ { 0xCC, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -> 'E' */
+ { 0xD0, 0x00 }, /* GREEK SMALL LETTER IOTA WITH VRACHY -> ... */
+ { 0xD3, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -> 'i' */
+ { 0xD6, 0x69 }, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI -> 'i' */
+ { 0xD7, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI -> 'i' */
+ { 0xD8, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH VRACHY -> ... */
+ { 0xDB, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH OXIA -> 'I' */
+ { 0xE0, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH VRACHY -> ... */
+ { 0xE3, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA -> 'u' */
+ { 0xE4, 0x52 }, /* GREEK SMALL LETTER RHO WITH PSILI -> 'R' */
+ { 0xE5, 0x52 }, /* GREEK SMALL LETTER RHO WITH DASIA -> 'R' */
+ { 0xE6, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI -> 'u' */
+ { 0xE7, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI -> 'u' */
+ { 0xE8, 0x00 }, /* GREEK CAPITAL LETTER UPSILON WITH VRACHY -> ... */
+ { 0xEB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH OXIA -> 'U' */
+ { 0xEC, 0x52 }, /* GREEK CAPITAL LETTER RHO WITH DASIA -> 'R' */
+ { 0xEF, 0x60 }, /* GREEK VARIA -> '`' */
+ { 0xF2, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI -> ... */
+ { 0xF4, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI -> 'o' */
+ { 0xF6, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI -> 'o' */
+ { 0xF7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'o' */
+ { 0xF8, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH VARIA -> ... */
+ { 0xFC, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -> 'O' */
+ { 0xFD, 0x27 }, /* GREEK OXIA -> ''' */
+ { 0xFE, 0x60 }, /* GREEK DASIA -> '`' */
+ /* Entries for page 0x20 */
+ { 0x00, 0x00 }, /* EN QUAD -> ... */
+ { 0x0B, 0x20 }, /* ZERO WIDTH SPACE -> ' ' */
+ { 0x10, 0x00 }, /* HYPHEN -> ... */
+ { 0x15, 0x2D }, /* HORIZONTAL BAR -> '-' */
+ { 0x17, 0x5F }, /* DOUBLE LOW LINE -> '_' */
+ { 0x18, 0x27 }, /* LEFT SINGLE QUOTATION MARK -> ''' */
+ { 0x19, 0x27 }, /* RIGHT SINGLE QUOTATION MARK -> ''' */
+ { 0x1A, 0x2C }, /* SINGLE LOW-9 QUOTATION MARK -> ',' */
+ { 0x1B, 0x27 }, /* SINGLE HIGH-REVERSED-9 QUOTATION MARK -> ''' */
+ { 0x1C, 0x00 }, /* LEFT DOUBLE QUOTATION MARK -> ... */
+ { 0x1F, 0x22 }, /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK -> '"' */
+ { 0x20, 0x2B }, /* DAGGER -> '+' */
+ { 0x22, 0x2A }, /* BULLET -> '*' */
+ { 0x23, 0x3E }, /* TRIANGULAR BULLET -> '>' */
+ { 0x24, 0x2E }, /* ONE DOT LEADER -> '.' */
+ { 0x26, 0x2E }, /* HORIZONTAL ELLIPSIS -> '.' */
+ { 0x27, 0x2E }, /* HYPHENATION POINT -> '.' */
+ { 0x2F, 0x20 }, /* NARROW NO-BREAK SPACE -> ' ' */
+ { 0x32, 0x27 }, /* PRIME -> ''' */
+ { 0x33, 0x22 }, /* DOUBLE PRIME -> '"' */
+ { 0x35, 0x60 }, /* REVERSED PRIME -> '`' */
+ { 0x38, 0x5E }, /* CARET -> '^' */
+ { 0x39, 0x3C }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK -> '<' */
+ { 0x3A, 0x3E }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -> '>' */
+ { 0x3B, 0x2A }, /* REFERENCE MARK -> '*' */
+ { 0x3C, 0x21 }, /* DOUBLE EXCLAMATION MARK -> '!' */
+ { 0x3D, 0x3F }, /* INTERROBANG -> '?' */
+ { 0x3E, 0x2D }, /* OVERLINE -> '-' */
+ { 0x3F, 0x5F }, /* UNDERTIE -> '_' */
+ { 0x40, 0x2D }, /* CHARACTER TIE -> '-' */
+ { 0x41, 0x5E }, /* CARET INSERTION POINT -> '^' */
+ { 0x42, 0x2A }, /* ASTERISM -> '*' */
+ { 0x43, 0x2D }, /* HYPHEN BULLET -> '-' */
+ { 0x44, 0x2F }, /* FRACTION SLASH -> '/' */
+ { 0x47, 0x3F }, /* DOUBLE QUESTION MARK -> '?' */
+ { 0x48, 0x3F }, /* QUESTION EXCLAMATION MARK -> '?' */
+ { 0x49, 0x21 }, /* EXCLAMATION QUESTION MARK -> '!' */
+ { 0x4A, 0x26 }, /* TIRONIAN SIGN ET -> '&' */
+ { 0x4B, 0x50 }, /* REVERSED PILCROW SIGN -> 'P' */
+ { 0x4C, 0x3C }, /* BLACK LEFTWARDS BULLET -> '<' */
+ { 0x4D, 0x3E }, /* BLACK RIGHTWARDS BULLET -> '>' */
+ { 0x4E, 0x2A }, /* LOW ASTERISK -> '*' */
+ { 0x4F, 0x3B }, /* REVERSED SEMICOLON -> ';' */
+ { 0x51, 0x2A }, /* TWO ASTERISKS ALIGNED VERTICALLY -> '*' */
+ { 0x52, 0x2D }, /* COMMERCIAL MINUS SIGN -> '-' */
+ { 0x53, 0x7E }, /* SWUNG DASH -> '~' */
+ { 0x55, 0x2A }, /* FLOWER PUNCTUATION MARK -> '*' */
+ { 0x5B, 0x3A }, /* FOUR DOT MARK -> ':' */
+ { 0x5F, 0x20 }, /* MEDIUM MATHEMATICAL SPACE -> ' ' */
+ { 0x70, 0x30 }, /* SUPERSCRIPT ZERO -> '0' */
+ { 0x71, 0x69 }, /* SUPERSCRIPT LATIN SMALL LETTER I -> 'i' */
+ { 0x74, 0x34 }, /* SUPERSCRIPT FOUR -> '4' */
+ { 0x75, 0x35 }, /* SUPERSCRIPT FIVE -> '5' */
+ { 0x76, 0x36 }, /* SUPERSCRIPT SIX -> '6' */
+ { 0x77, 0x37 }, /* SUPERSCRIPT SEVEN -> '7' */
+ { 0x78, 0x38 }, /* SUPERSCRIPT EIGHT -> '8' */
+ { 0x79, 0x39 }, /* SUPERSCRIPT NINE -> '9' */
+ { 0x7A, 0x2B }, /* SUPERSCRIPT PLUS SIGN -> '+' */
+ { 0x7B, 0x2D }, /* SUPERSCRIPT MINUS -> '-' */
+ { 0x7C, 0x3D }, /* SUPERSCRIPT EQUALS SIGN -> '=' */
+ { 0x7D, 0x28 }, /* SUPERSCRIPT LEFT PARENTHESIS -> '(' */
+ { 0x7E, 0x29 }, /* SUPERSCRIPT RIGHT PARENTHESIS -> ')' */
+ { 0x7F, 0x6E }, /* SUPERSCRIPT LATIN SMALL LETTER N -> 'n' */
+ { 0x80, 0x30 }, /* SUBSCRIPT ZERO -> '0' */
+ { 0x81, 0x31 }, /* SUBSCRIPT ONE -> '1' */
+ { 0x82, 0x32 }, /* SUBSCRIPT TWO -> '2' */
+ { 0x83, 0x33 }, /* SUBSCRIPT THREE -> '3' */
+ { 0x84, 0x34 }, /* SUBSCRIPT FOUR -> '4' */
+ { 0x85, 0x35 }, /* SUBSCRIPT FIVE -> '5' */
+ { 0x86, 0x36 }, /* SUBSCRIPT SIX -> '6' */
+ { 0x87, 0x37 }, /* SUBSCRIPT SEVEN -> '7' */
+ { 0x88, 0x38 }, /* SUBSCRIPT EIGHT -> '8' */
+ { 0x89, 0x39 }, /* SUBSCRIPT NINE -> '9' */
+ { 0x8A, 0x2B }, /* SUBSCRIPT PLUS SIGN -> '+' */
+ { 0x8B, 0x2D }, /* SUBSCRIPT MINUS -> '-' */
+ { 0x8C, 0x3D }, /* SUBSCRIPT EQUALS SIGN -> '=' */
+ { 0x8D, 0x28 }, /* SUBSCRIPT LEFT PARENTHESIS -> '(' */
+ { 0x8E, 0x29 }, /* SUBSCRIPT RIGHT PARENTHESIS -> ')' */
+ { 0x90, 0x61 }, /* LATIN SUBSCRIPT SMALL LETTER A -> 'a' */
+ { 0x91, 0x65 }, /* LATIN SUBSCRIPT SMALL LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* LATIN SUBSCRIPT SMALL LETTER O -> 'o' */
+ { 0x93, 0x78 }, /* LATIN SUBSCRIPT SMALL LETTER X -> 'x' */
+ { 0x95, 0x68 }, /* LATIN SUBSCRIPT SMALL LETTER H -> 'h' */
+ { 0x96, 0x6B }, /* LATIN SUBSCRIPT SMALL LETTER K -> 'k' */
+ { 0x97, 0x6C }, /* LATIN SUBSCRIPT SMALL LETTER L -> 'l' */
+ { 0x98, 0x6D }, /* LATIN SUBSCRIPT SMALL LETTER M -> 'm' */
+ { 0x99, 0x6E }, /* LATIN SUBSCRIPT SMALL LETTER N -> 'n' */
+ { 0x9A, 0x70 }, /* LATIN SUBSCRIPT SMALL LETTER P -> 'p' */
+ { 0x9B, 0x73 }, /* LATIN SUBSCRIPT SMALL LETTER S -> 's' */
+ { 0x9C, 0x74 }, /* LATIN SUBSCRIPT SMALL LETTER T -> 't' */
+ { 0xA4, 0x4C }, /* LIRA SIGN -> 'L' */
+ { 0xA6, 0x4E }, /* NAIRA SIGN -> 'N' */
+ { 0xA9, 0x57 }, /* WON SIGN -> 'W' */
+ { 0xAB, 0x44 }, /* DONG SIGN -> 'D' */
+ { 0xAC, 0x45 }, /* EURO SIGN -> 'E' */
+ { 0xAD, 0x4B }, /* KIP SIGN -> 'K' */
+ { 0xAE, 0x54 }, /* TUGRIK SIGN -> 'T' */
+ { 0xB1, 0x50 }, /* PESO SIGN -> 'P' */
+ { 0xB2, 0x47 }, /* GUARANI SIGN -> 'G' */
+ { 0xB3, 0x41 }, /* AUSTRAL SIGN -> 'A' */
+ { 0xB6, 0x4C }, /* LIVRE TOURNOIS SIGN -> 'L' */
+ { 0xB8, 0x54 }, /* TENGE SIGN -> 'T' */
+ { 0xBA, 0x4C }, /* TURKISH LIRA SIGN -> 'L' */
+ { 0xBB, 0x4D }, /* NORDIC MARK SIGN -> 'M' */
+ { 0xBC, 0x6D }, /* MANAT SIGN -> 'm' */
+ { 0xBD, 0x52 }, /* RUBLE SIGN -> 'R' */
+ { 0xBE, 0x6C }, /* LARI SIGN -> 'l' */
+ /* Entries for page 0x21 */
+ { 0x02, 0x43 }, /* DOUBLE-STRUCK CAPITAL C -> 'C' */
+ { 0x03, 0x43 }, /* DEGREE CELSIUS -> 'C' */
+ { 0x09, 0x46 }, /* DEGREE FAHRENHEIT -> 'F' */
+ { 0x0A, 0x67 }, /* SCRIPT SMALL G -> 'g' */
+ { 0x0B, 0x00 }, /* SCRIPT CAPITAL H -> ... */
+ { 0x0D, 0x48 }, /* DOUBLE-STRUCK CAPITAL H -> 'H' */
+ { 0x0E, 0x68 }, /* PLANCK CONSTANT -> 'h' */
+ { 0x10, 0x49 }, /* SCRIPT CAPITAL I -> 'I' */
+ { 0x11, 0x49 }, /* BLACK-LETTER CAPITAL I -> 'I' */
+ { 0x12, 0x4C }, /* SCRIPT CAPITAL L -> 'L' */
+ { 0x13, 0x6C }, /* SCRIPT SMALL L -> 'l' */
+ { 0x15, 0x4E }, /* DOUBLE-STRUCK CAPITAL N -> 'N' */
+ { 0x19, 0x50 }, /* DOUBLE-STRUCK CAPITAL P -> 'P' */
+ { 0x1A, 0x51 }, /* DOUBLE-STRUCK CAPITAL Q -> 'Q' */
+ { 0x1B, 0x00 }, /* SCRIPT CAPITAL R -> ... */
+ { 0x1D, 0x52 }, /* DOUBLE-STRUCK CAPITAL R -> 'R' */
+ { 0x22, 0x54 }, /* TRADE MARK SIGN -> 'T' */
+ { 0x24, 0x5A }, /* DOUBLE-STRUCK CAPITAL Z -> 'Z' */
+ { 0x28, 0x5A }, /* BLACK-LETTER CAPITAL Z -> 'Z' */
+ { 0x2A, 0x4B }, /* KELVIN SIGN -> 'K' */
+ { 0x2B, 0x41 }, /* ANGSTROM SIGN -> 'A' */
+ { 0x2C, 0x42 }, /* SCRIPT CAPITAL B -> 'B' */
+ { 0x2D, 0x43 }, /* BLACK-LETTER CAPITAL C -> 'C' */
+ { 0x2E, 0x65 }, /* ESTIMATED SYMBOL -> 'e' */
+ { 0x2F, 0x65 }, /* SCRIPT SMALL E -> 'e' */
+ { 0x30, 0x45 }, /* SCRIPT CAPITAL E -> 'E' */
+ { 0x31, 0x46 }, /* SCRIPT CAPITAL F -> 'F' */
+ { 0x32, 0x46 }, /* TURNED CAPITAL F -> 'F' */
+ { 0x33, 0x4D }, /* SCRIPT CAPITAL M -> 'M' */
+ { 0x34, 0x6F }, /* SCRIPT SMALL O -> 'o' */
+ { 0x39, 0x69 }, /* INFORMATION SOURCE -> 'i' */
+ { 0x45, 0x44 }, /* DOUBLE-STRUCK ITALIC CAPITAL D -> 'D' */
+ { 0x46, 0x64 }, /* DOUBLE-STRUCK ITALIC SMALL D -> 'd' */
+ { 0x47, 0x65 }, /* DOUBLE-STRUCK ITALIC SMALL E -> 'e' */
+ { 0x48, 0x69 }, /* DOUBLE-STRUCK ITALIC SMALL I -> 'i' */
+ { 0x49, 0x6A }, /* DOUBLE-STRUCK ITALIC SMALL J -> 'j' */
+ { 0x4E, 0x46 }, /* TURNED SMALL F -> 'F' */
+ { 0x60, 0x49 }, /* ROMAN NUMERAL ONE -> 'I' */
+ { 0x64, 0x56 }, /* ROMAN NUMERAL FIVE -> 'V' */
+ { 0x69, 0x58 }, /* ROMAN NUMERAL TEN -> 'X' */
+ { 0x6C, 0x4C }, /* ROMAN NUMERAL FIFTY -> 'L' */
+ { 0x6D, 0x43 }, /* ROMAN NUMERAL ONE HUNDRED -> 'C' */
+ { 0x6E, 0x44 }, /* ROMAN NUMERAL FIVE HUNDRED -> 'D' */
+ { 0x6F, 0x4D }, /* ROMAN NUMERAL ONE THOUSAND -> 'M' */
+ { 0x70, 0x69 }, /* SMALL ROMAN NUMERAL ONE -> 'i' */
+ { 0x74, 0x76 }, /* SMALL ROMAN NUMERAL FIVE -> 'v' */
+ { 0x79, 0x78 }, /* SMALL ROMAN NUMERAL TEN -> 'x' */
+ { 0x7C, 0x6C }, /* SMALL ROMAN NUMERAL FIFTY -> 'l' */
+ { 0x7D, 0x63 }, /* SMALL ROMAN NUMERAL ONE HUNDRED -> 'c' */
+ { 0x7E, 0x64 }, /* SMALL ROMAN NUMERAL FIVE HUNDRED -> 'd' */
+ { 0x7F, 0x6D }, /* SMALL ROMAN NUMERAL ONE THOUSAND -> 'm' */
+ { 0x83, 0x29 }, /* ROMAN NUMERAL REVERSED ONE HUNDRED -> ')' */
+ { 0x90, 0x3C }, /* LEFTWARDS ARROW -> '<' */
+ { 0x91, 0x5E }, /* UPWARDS ARROW -> '^' */
+ { 0x92, 0x3E }, /* RIGHTWARDS ARROW -> '>' */
+ { 0x93, 0x76 }, /* DOWNWARDS ARROW -> 'v' */
+ { 0x94, 0x2D }, /* LEFT RIGHT ARROW -> '-' */
+ { 0x95, 0x7C }, /* UP DOWN ARROW -> '|' */
+ { 0x96, 0x5C }, /* NORTH WEST ARROW -> '\' */
+ { 0x97, 0x2F }, /* NORTH EAST ARROW -> '/' */
+ { 0x98, 0x5C }, /* SOUTH EAST ARROW -> '\' */
+ { 0x99, 0x2F }, /* SOUTH WEST ARROW -> '/' */
+ { 0x9A, 0x21 }, /* LEFTWARDS ARROW WITH STROKE -> '!' */
+ { 0x9B, 0x21 }, /* RIGHTWARDS ARROW WITH STROKE -> '!' */
+ { 0x9C, 0x7E }, /* LEFTWARDS WAVE ARROW -> '~' */
+ { 0x9D, 0x7E }, /* RIGHTWARDS WAVE ARROW -> '~' */
+ { 0x9E, 0x2D }, /* LEFTWARDS TWO HEADED ARROW -> '-' */
+ { 0x9F, 0x7C }, /* UPWARDS TWO HEADED ARROW -> '|' */
+ { 0xA0, 0x2D }, /* RIGHTWARDS TWO HEADED ARROW -> '-' */
+ { 0xA1, 0x7C }, /* DOWNWARDS TWO HEADED ARROW -> '|' */
+ { 0xA2, 0x00 }, /* LEFTWARDS ARROW WITH TAIL -> ... */
+ { 0xA4, 0x2D }, /* LEFTWARDS ARROW FROM BAR -> '-' */
+ { 0xA5, 0x7C }, /* UPWARDS ARROW FROM BAR -> '|' */
+ { 0xA6, 0x2D }, /* RIGHTWARDS ARROW FROM BAR -> '-' */
+ { 0xA7, 0x7C }, /* DOWNWARDS ARROW FROM BAR -> '|' */
+ { 0xA8, 0x7C }, /* UP DOWN ARROW WITH BASE -> '|' */
+ { 0xA9, 0x00 }, /* LEFTWARDS ARROW WITH HOOK -> ... */
+ { 0xAD, 0x2D }, /* LEFT RIGHT WAVE ARROW -> '-' */
+ { 0xAE, 0x21 }, /* LEFT RIGHT ARROW WITH STROKE -> '!' */
+ { 0xAF, 0x00 }, /* DOWNWARDS ZIGZAG ARROW -> ... */
+ { 0xB5, 0x7C }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS -> '|' */
+ { 0xB6, 0x5E }, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW -> '^' */
+ { 0xB7, 0x56 }, /* CLOCKWISE TOP SEMICIRCLE ARROW -> 'V' */
+ { 0xB8, 0x5C }, /* NORTH WEST ARROW TO LONG BAR -> '\' */
+ { 0xB9, 0x3D }, /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR -> '=' */
+ { 0xBA, 0x56 }, /* ANTICLOCKWISE OPEN CIRCLE ARROW -> 'V' */
+ { 0xBB, 0x5E }, /* CLOCKWISE OPEN CIRCLE ARROW -> '^' */
+ { 0xBC, 0x2D }, /* LEFTWARDS HARPOON WITH BARB UPWARDS -> '-' */
+ { 0xBD, 0x2D }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */
+ { 0xBE, 0x7C }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */
+ { 0xBF, 0x7C }, /* UPWARDS HARPOON WITH BARB LEFTWARDS -> '|' */
+ { 0xC0, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS -> '-' */
+ { 0xC1, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */
+ { 0xC2, 0x7C }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */
+ { 0xC3, 0x7C }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS -> '|' */
+ { 0xC4, 0x3D }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW -> '=' */
+ { 0xC5, 0x7C }, /* UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW -> '|' */
+ { 0xC6, 0x3D }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW -> '=' */
+ { 0xC7, 0x3D }, /* LEFTWARDS PAIRED ARROWS -> '=' */
+ { 0xC8, 0x7C }, /* UPWARDS PAIRED ARROWS -> '|' */
+ { 0xC9, 0x3D }, /* RIGHTWARDS PAIRED ARROWS -> '=' */
+ { 0xCA, 0x7C }, /* DOWNWARDS PAIRED ARROWS -> '|' */
+ { 0xCB, 0x3D }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON -> '=' */
+ { 0xCC, 0x3D }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON -> '=' */
+ { 0xCD, 0x00 }, /* LEFTWARDS DOUBLE ARROW WITH STROKE -> ... */
+ { 0xCF, 0x21 }, /* RIGHTWARDS DOUBLE ARROW WITH STROKE -> '!' */
+ { 0xD0, 0x3C }, /* LEFTWARDS DOUBLE ARROW -> '<' */
+ { 0xD1, 0x5E }, /* UPWARDS DOUBLE ARROW -> '^' */
+ { 0xD2, 0x3E }, /* RIGHTWARDS DOUBLE ARROW -> '>' */
+ { 0xD3, 0x76 }, /* DOWNWARDS DOUBLE ARROW -> 'v' */
+ { 0xD4, 0x3D }, /* LEFT RIGHT DOUBLE ARROW -> '=' */
+ { 0xD5, 0x7C }, /* UP DOWN DOUBLE ARROW -> '|' */
+ { 0xD6, 0x5C }, /* NORTH WEST DOUBLE ARROW -> '\' */
+ { 0xD7, 0x2F }, /* NORTH EAST DOUBLE ARROW -> '/' */
+ { 0xD8, 0x5C }, /* SOUTH EAST DOUBLE ARROW -> '\' */
+ { 0xD9, 0x2F }, /* SOUTH WEST DOUBLE ARROW -> '/' */
+ { 0xDA, 0x3D }, /* LEFTWARDS TRIPLE ARROW -> '=' */
+ { 0xDB, 0x3D }, /* RIGHTWARDS TRIPLE ARROW -> '=' */
+ { 0xDC, 0x7E }, /* LEFTWARDS SQUIGGLE ARROW -> '~' */
+ { 0xDD, 0x7E }, /* RIGHTWARDS SQUIGGLE ARROW -> '~' */
+ { 0xDE, 0x7C }, /* UPWARDS ARROW WITH DOUBLE STROKE -> '|' */
+ { 0xDF, 0x7C }, /* DOWNWARDS ARROW WITH DOUBLE STROKE -> '|' */
+ { 0xE0, 0x2D }, /* LEFTWARDS DASHED ARROW -> '-' */
+ { 0xE1, 0x7C }, /* UPWARDS DASHED ARROW -> '|' */
+ { 0xE2, 0x2D }, /* RIGHTWARDS DASHED ARROW -> '-' */
+ { 0xE3, 0x7C }, /* DOWNWARDS DASHED ARROW -> '|' */
+ { 0xE4, 0x00 }, /* LEFTWARDS ARROW TO BAR -> ... */
+ { 0xE6, 0x2D }, /* LEFTWARDS WHITE ARROW -> '-' */
+ { 0xE7, 0x7C }, /* UPWARDS WHITE ARROW -> '|' */
+ { 0xE8, 0x2D }, /* RIGHTWARDS WHITE ARROW -> '-' */
+ { 0xE9, 0x00 }, /* DOWNWARDS WHITE ARROW -> ... */
+ { 0xEF, 0x7C }, /* UPWARDS WHITE DOUBLE ARROW ON PEDESTAL -> '|' */
+ { 0xF0, 0x2D }, /* RIGHTWARDS WHITE ARROW FROM WALL -> '-' */
+ { 0xF1, 0x5C }, /* NORTH WEST ARROW TO CORNER -> '\' */
+ { 0xF2, 0x5C }, /* SOUTH EAST ARROW TO CORNER -> '\' */
+ { 0xF3, 0x7C }, /* UP DOWN WHITE ARROW -> '|' */
+ /* Entries for page 0x22 */
+ { 0x04, 0x21 }, /* THERE DOES NOT EXIST -> '!' */
+ { 0x09, 0x21 }, /* NOT AN ELEMENT OF -> '!' */
+ { 0x0C, 0x21 }, /* DOES NOT CONTAIN AS MEMBER -> '!' */
+ { 0x12, 0x2D }, /* MINUS SIGN -> '-' */
+ { 0x15, 0x2F }, /* DIVISION SLASH -> '/' */
+ { 0x16, 0x5C }, /* SET MINUS -> '\' */
+ { 0x17, 0x2A }, /* ASTERISK OPERATOR -> '*' */
+ { 0x18, 0x6F }, /* RING OPERATOR -> 'o' */
+ { 0x19, 0x2E }, /* BULLET OPERATOR -> '.' */
+ { 0x23, 0x7C }, /* DIVIDES -> '|' */
+ { 0x24, 0x21 }, /* DOES NOT DIVIDE -> '!' */
+ { 0x26, 0x21 }, /* NOT PARALLEL TO -> '!' */
+ { 0x36, 0x3A }, /* RATIO -> ':' */
+ { 0x3C, 0x7E }, /* TILDE OPERATOR -> '~' */
+ { 0x41, 0x23 }, /* NOT TILDE -> '#' */
+ { 0x44, 0x23 }, /* NOT ASYMPTOTICALLY EQUAL TO -> '#' */
+ { 0x49, 0x23 }, /* NOT ALMOST EQUAL TO -> '#' */
+ { 0x60, 0x23 }, /* NOT EQUAL TO -> '#' */
+ { 0x62, 0x23 }, /* NOT IDENTICAL TO -> '#' */
+ { 0x64, 0x3C }, /* LESS-THAN OR EQUAL TO -> '<' */
+ { 0x65, 0x3E }, /* GREATER-THAN OR EQUAL TO -> '>' */
+ { 0x68, 0x23 }, /* LESS-THAN BUT NOT EQUAL TO -> '#' */
+ { 0x69, 0x23 }, /* GREATER-THAN BUT NOT EQUAL TO -> '#' */
+ { 0x6D, 0x23 }, /* NOT EQUIVALENT TO -> '#' */
+ { 0x6E, 0x21 }, /* NOT LESS-THAN -> '!' */
+ { 0x6F, 0x21 }, /* NOT GREATER-THAN -> '!' */
+ { 0x80, 0x21 }, /* DOES NOT PRECEDE -> '!' */
+ { 0x81, 0x21 }, /* DOES NOT SUCCEED -> '!' */
+ { 0x84, 0x21 }, /* NOT A SUBSET OF -> '!' */
+ { 0x85, 0x21 }, /* NOT A SUPERSET OF -> '!' */
+ { 0x8A, 0x23 }, /* SUBSET OF WITH NOT EQUAL TO -> '#' */
+ { 0x8B, 0x23 }, /* SUPERSET OF WITH NOT EQUAL TO -> '#' */
+ { 0x9B, 0x2A }, /* CIRCLED ASTERISK OPERATOR -> '*' */
+ { 0xC6, 0x2A }, /* STAR OPERATOR -> '*' */
+ /* Entries for page 0x23 */
+ { 0x03, 0x5E }, /* UP ARROWHEAD -> '^' */
+ { 0x29, 0x3C }, /* LEFT-POINTING ANGLE BRACKET -> '<' */
+ { 0x5F, 0x2A }, /* APL FUNCTIONAL SYMBOL CIRCLE STAR -> '*' */
+ { 0x63, 0x2A }, /* APL FUNCTIONAL SYMBOL STAR DIAERESIS -> '*' */
+ /* Entries for page 0x24 */
+ { 0x60, 0x31 }, /* CIRCLED DIGIT ONE -> '1' */
+ { 0x61, 0x32 }, /* CIRCLED DIGIT TWO -> '2' */
+ { 0x62, 0x33 }, /* CIRCLED DIGIT THREE -> '3' */
+ { 0x63, 0x34 }, /* CIRCLED DIGIT FOUR -> '4' */
+ { 0x64, 0x35 }, /* CIRCLED DIGIT FIVE -> '5' */
+ { 0x65, 0x36 }, /* CIRCLED DIGIT SIX -> '6' */
+ { 0x66, 0x37 }, /* CIRCLED DIGIT SEVEN -> '7' */
+ { 0x67, 0x38 }, /* CIRCLED DIGIT EIGHT -> '8' */
+ { 0x68, 0x39 }, /* CIRCLED DIGIT NINE -> '9' */
+ { 0xB6, 0x41 }, /* CIRCLED LATIN CAPITAL LETTER A -> 'A' */
+ { 0xB7, 0x42 }, /* CIRCLED LATIN CAPITAL LETTER B -> 'B' */
+ { 0xB8, 0x43 }, /* CIRCLED LATIN CAPITAL LETTER C -> 'C' */
+ { 0xB9, 0x44 }, /* CIRCLED LATIN CAPITAL LETTER D -> 'D' */
+ { 0xBA, 0x45 }, /* CIRCLED LATIN CAPITAL LETTER E -> 'E' */
+ { 0xBB, 0x46 }, /* CIRCLED LATIN CAPITAL LETTER F -> 'F' */
+ { 0xBC, 0x47 }, /* CIRCLED LATIN CAPITAL LETTER G -> 'G' */
+ { 0xBD, 0x48 }, /* CIRCLED LATIN CAPITAL LETTER H -> 'H' */
+ { 0xBE, 0x49 }, /* CIRCLED LATIN CAPITAL LETTER I -> 'I' */
+ { 0xBF, 0x4A }, /* CIRCLED LATIN CAPITAL LETTER J -> 'J' */
+ { 0xC0, 0x4B }, /* CIRCLED LATIN CAPITAL LETTER K -> 'K' */
+ { 0xC1, 0x4C }, /* CIRCLED LATIN CAPITAL LETTER L -> 'L' */
+ { 0xC2, 0x4D }, /* CIRCLED LATIN CAPITAL LETTER M -> 'M' */
+ { 0xC3, 0x4E }, /* CIRCLED LATIN CAPITAL LETTER N -> 'N' */
+ { 0xC4, 0x4F }, /* CIRCLED LATIN CAPITAL LETTER O -> 'O' */
+ { 0xC5, 0x50 }, /* CIRCLED LATIN CAPITAL LETTER P -> 'P' */
+ { 0xC6, 0x51 }, /* CIRCLED LATIN CAPITAL LETTER Q -> 'Q' */
+ { 0xC7, 0x52 }, /* CIRCLED LATIN CAPITAL LETTER R -> 'R' */
+ { 0xC8, 0x53 }, /* CIRCLED LATIN CAPITAL LETTER S -> 'S' */
+ { 0xC9, 0x54 }, /* CIRCLED LATIN CAPITAL LETTER T -> 'T' */
+ { 0xCA, 0x55 }, /* CIRCLED LATIN CAPITAL LETTER U -> 'U' */
+ { 0xCB, 0x56 }, /* CIRCLED LATIN CAPITAL LETTER V -> 'V' */
+ { 0xCC, 0x57 }, /* CIRCLED LATIN CAPITAL LETTER W -> 'W' */
+ { 0xCD, 0x58 }, /* CIRCLED LATIN CAPITAL LETTER X -> 'X' */
+ { 0xCE, 0x59 }, /* CIRCLED LATIN CAPITAL LETTER Y -> 'Y' */
+ { 0xCF, 0x5A }, /* CIRCLED LATIN CAPITAL LETTER Z -> 'Z' */
+ { 0xD0, 0x61 }, /* CIRCLED LATIN SMALL LETTER A -> 'a' */
+ { 0xD1, 0x62 }, /* CIRCLED LATIN SMALL LETTER B -> 'b' */
+ { 0xD2, 0x63 }, /* CIRCLED LATIN SMALL LETTER C -> 'c' */
+ { 0xD3, 0x64 }, /* CIRCLED LATIN SMALL LETTER D -> 'd' */
+ { 0xD4, 0x65 }, /* CIRCLED LATIN SMALL LETTER E -> 'e' */
+ { 0xD5, 0x66 }, /* CIRCLED LATIN SMALL LETTER F -> 'f' */
+ { 0xD6, 0x67 }, /* CIRCLED LATIN SMALL LETTER G -> 'g' */
+ { 0xD7, 0x68 }, /* CIRCLED LATIN SMALL LETTER H -> 'h' */
+ { 0xD8, 0x69 }, /* CIRCLED LATIN SMALL LETTER I -> 'i' */
+ { 0xD9, 0x6A }, /* CIRCLED LATIN SMALL LETTER J -> 'j' */
+ { 0xDA, 0x6B }, /* CIRCLED LATIN SMALL LETTER K -> 'k' */
+ { 0xDB, 0x6C }, /* CIRCLED LATIN SMALL LETTER L -> 'l' */
+ { 0xDC, 0x6D }, /* CIRCLED LATIN SMALL LETTER M -> 'm' */
+ { 0xDD, 0x6E }, /* CIRCLED LATIN SMALL LETTER N -> 'n' */
+ { 0xDE, 0x6F }, /* CIRCLED LATIN SMALL LETTER O -> 'o' */
+ { 0xDF, 0x70 }, /* CIRCLED LATIN SMALL LETTER P -> 'p' */
+ { 0xE0, 0x71 }, /* CIRCLED LATIN SMALL LETTER Q -> 'q' */
+ { 0xE1, 0x72 }, /* CIRCLED LATIN SMALL LETTER R -> 'r' */
+ { 0xE2, 0x73 }, /* CIRCLED LATIN SMALL LETTER S -> 's' */
+ { 0xE3, 0x74 }, /* CIRCLED LATIN SMALL LETTER T -> 't' */
+ { 0xE4, 0x75 }, /* CIRCLED LATIN SMALL LETTER U -> 'u' */
+ { 0xE5, 0x76 }, /* CIRCLED LATIN SMALL LETTER V -> 'v' */
+ { 0xE6, 0x77 }, /* CIRCLED LATIN SMALL LETTER W -> 'w' */
+ { 0xE7, 0x78 }, /* CIRCLED LATIN SMALL LETTER X -> 'x' */
+ { 0xE8, 0x79 }, /* CIRCLED LATIN SMALL LETTER Y -> 'y' */
+ { 0xE9, 0x7A }, /* CIRCLED LATIN SMALL LETTER Z -> 'z' */
+ { 0xEA, 0x30 }, /* CIRCLED DIGIT ZERO -> '0' */
+ { 0xF5, 0x31 }, /* DOUBLE CIRCLED DIGIT ONE -> '1' */
+ { 0xF6, 0x32 }, /* DOUBLE CIRCLED DIGIT TWO -> '2' */
+ { 0xF7, 0x33 }, /* DOUBLE CIRCLED DIGIT THREE -> '3' */
+ { 0xF8, 0x34 }, /* DOUBLE CIRCLED DIGIT FOUR -> '4' */
+ { 0xF9, 0x35 }, /* DOUBLE CIRCLED DIGIT FIVE -> '5' */
+ { 0xFA, 0x36 }, /* DOUBLE CIRCLED DIGIT SIX -> '6' */
+ { 0xFB, 0x37 }, /* DOUBLE CIRCLED DIGIT SEVEN -> '7' */
+ { 0xFC, 0x38 }, /* DOUBLE CIRCLED DIGIT EIGHT -> '8' */
+ { 0xFD, 0x39 }, /* DOUBLE CIRCLED DIGIT NINE -> '9' */
+ { 0xFF, 0x30 }, /* NEGATIVE CIRCLED DIGIT ZERO -> '0' */
+ /* Entries for page 0x25 */
+ { 0x00, 0x2D }, /* BOX DRAWINGS LIGHT HORIZONTAL -> '-' */
+ { 0x01, 0x2D }, /* BOX DRAWINGS HEAVY HORIZONTAL -> '-' */
+ { 0x02, 0x7C }, /* BOX DRAWINGS LIGHT VERTICAL -> '|' */
+ { 0x03, 0x7C }, /* BOX DRAWINGS HEAVY VERTICAL -> '|' */
+ { 0x04, 0x2D }, /* BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL -> '-' */
+ { 0x05, 0x2D }, /* BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL -> '-' */
+ { 0x06, 0x7C }, /* BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL -> '|' */
+ { 0x07, 0x7C }, /* BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL -> '|' */
+ { 0x08, 0x2D }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL -> '-' */
+ { 0x09, 0x2D }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL -> '-' */
+ { 0x0A, 0x7C }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL -> '|' */
+ { 0x0B, 0x7C }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL -> '|' */
+ { 0x0C, 0x00 }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT -> ... */
+ { 0x4B, 0x2B }, /* BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL -> '+' */
+ { 0x4C, 0x2D }, /* BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL -> '-' */
+ { 0x4D, 0x2D }, /* BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL -> '-' */
+ { 0x4E, 0x7C }, /* BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL -> '|' */
+ { 0x4F, 0x7C }, /* BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL -> '|' */
+ { 0x50, 0x2D }, /* BOX DRAWINGS DOUBLE HORIZONTAL -> '-' */
+ { 0x51, 0x7C }, /* BOX DRAWINGS DOUBLE VERTICAL -> '|' */
+ { 0x52, 0x00 }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -> ... */
+ { 0x70, 0x2B }, /* BOX DRAWINGS LIGHT ARC UP AND RIGHT -> '+' */
+ { 0x71, 0x2F }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT -> '/' */
+ { 0x72, 0x5C }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT -> '\' */
+ { 0x73, 0x58 }, /* BOX DRAWINGS LIGHT DIAGONAL CROSS -> 'X' */
+ { 0x74, 0x2D }, /* BOX DRAWINGS LIGHT LEFT -> '-' */
+ { 0x75, 0x7C }, /* BOX DRAWINGS LIGHT UP -> '|' */
+ { 0x76, 0x2D }, /* BOX DRAWINGS LIGHT RIGHT -> '-' */
+ { 0x77, 0x7C }, /* BOX DRAWINGS LIGHT DOWN -> '|' */
+ { 0x78, 0x2D }, /* BOX DRAWINGS HEAVY LEFT -> '-' */
+ { 0x79, 0x7C }, /* BOX DRAWINGS HEAVY UP -> '|' */
+ { 0x7A, 0x2D }, /* BOX DRAWINGS HEAVY RIGHT -> '-' */
+ { 0x7B, 0x7C }, /* BOX DRAWINGS HEAVY DOWN -> '|' */
+ { 0x7C, 0x2D }, /* BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT -> '-' */
+ { 0x7D, 0x7C }, /* BOX DRAWINGS LIGHT UP AND HEAVY DOWN -> '|' */
+ { 0x7E, 0x2D }, /* BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT -> '-' */
+ { 0x7F, 0x7C }, /* BOX DRAWINGS HEAVY UP AND LIGHT DOWN -> '|' */
+ { 0x80, 0x00 }, /* UPPER HALF BLOCK -> ... */
+ { 0x93, 0x23 }, /* DARK SHADE -> '#' */
+ { 0x94, 0x2D }, /* UPPER ONE EIGHTH BLOCK -> '-' */
+ { 0x95, 0x7C }, /* RIGHT ONE EIGHTH BLOCK -> '|' */
+ { 0x96, 0x00 }, /* QUADRANT LOWER LEFT -> ... */
+ { 0xB1, 0x23 }, /* WHITE PARALLELOGRAM -> '#' */
+ { 0xB2, 0x00 }, /* BLACK UP-POINTING TRIANGLE -> ... */
+ { 0xB5, 0x5E }, /* WHITE UP-POINTING SMALL TRIANGLE -> '^' */
+ { 0xB6, 0x00 }, /* BLACK RIGHT-POINTING TRIANGLE -> ... */
+ { 0xBB, 0x3E }, /* WHITE RIGHT-POINTING POINTER -> '>' */
+ { 0xBC, 0x00 }, /* BLACK DOWN-POINTING TRIANGLE -> ... */
+ { 0xBF, 0x56 }, /* WHITE DOWN-POINTING SMALL TRIANGLE -> 'V' */
+ { 0xC0, 0x00 }, /* BLACK LEFT-POINTING TRIANGLE -> ... */
+ { 0xC5, 0x3C }, /* WHITE LEFT-POINTING POINTER -> '<' */
+ { 0xC6, 0x00 }, /* BLACK DIAMOND -> ... */
+ { 0xE6, 0x2A }, /* WHITE BULLET -> '*' */
+ { 0xE7, 0x00 }, /* SQUARE WITH LEFT HALF BLACK -> ... */
+ { 0xEB, 0x23 }, /* WHITE SQUARE WITH VERTICAL BISECTING LINE -> '#' */
+ { 0xEC, 0x00 }, /* WHITE UP-POINTING TRIANGLE WITH DOT -> ... */
+ { 0xEE, 0x5E }, /* UP-POINTING TRIANGLE WITH RIGHT HALF BLACK -> '^' */
+ { 0xEF, 0x4F }, /* LARGE CIRCLE -> 'O' */
+ { 0xF0, 0x00 }, /* WHITE SQUARE WITH UPPER LEFT QUADRANT -> ... */
+ { 0xF7, 0x23 }, /* WHITE CIRCLE WITH UPPER RIGHT QUADRANT -> '#' */
+ /* Entries for page 0x26 */
+ { 0x05, 0x2A }, /* BLACK STAR -> '*' */
+ { 0x06, 0x2A }, /* WHITE STAR -> '*' */
+ { 0x2A, 0x2A }, /* STAR AND CRESCENT -> '*' */
+ { 0x6F, 0x23 }, /* MUSIC SHARP SIGN -> '#' */
+ { 0x98, 0x2A }, /* FLOWER -> '*' */
+ { 0x9D, 0x2A }, /* OUTLINED WHITE STAR -> '*' */
+ /* Entries for page 0x27 */
+ { 0x13, 0x76 }, /* CHECK MARK -> 'v' */
+ { 0x14, 0x56 }, /* HEAVY CHECK MARK -> 'V' */
+ { 0x15, 0x78 }, /* MULTIPLICATION X -> 'x' */
+ { 0x16, 0x58 }, /* HEAVY MULTIPLICATION X -> 'X' */
+ { 0x17, 0x78 }, /* BALLOT X -> 'x' */
+ { 0x18, 0x58 }, /* HEAVY BALLOT X -> 'X' */
+ { 0x21, 0x00 }, /* STAR OF DAVID -> ... */
+ { 0x46, 0x2A }, /* HEAVY CHEVRON SNOWFLAKE -> '*' */
+ { 0x49, 0x00 }, /* BALLOON-SPOKED ASTERISK -> ... */
+ { 0x4B, 0x2A }, /* HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK -> '*' */
+ { 0x58, 0x7C }, /* LIGHT VERTICAL BAR -> '|' */
+ { 0x5C, 0x27 }, /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT -> ''' */
+ { 0x5D, 0x22 }, /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT -> '"' */
+ { 0x5E, 0x22 }, /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT -> '"' */
+ { 0x5F, 0x2C }, /* HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT -> ',' */
+ { 0x62, 0x21 }, /* HEAVY EXCLAMATION MARK ORNAMENT -> '!' */
+ { 0xE6, 0x5B }, /* MATHEMATICAL LEFT WHITE SQUARE BRACKET -> '[' */
+ { 0xE8, 0x3C }, /* MATHEMATICAL LEFT ANGLE BRACKET -> '<' */
+ /* Entries for page 0x28 */
+ { 0x00, 0x20 }, /* BRAILLE PATTERN BLANK -> ' ' */
+ { 0x01, 0x61 }, /* BRAILLE PATTERN DOTS-1 -> 'a' */
+ { 0x02, 0x31 }, /* BRAILLE PATTERN DOTS-2 -> '1' */
+ { 0x03, 0x62 }, /* BRAILLE PATTERN DOTS-12 -> 'b' */
+ { 0x04, 0x27 }, /* BRAILLE PATTERN DOTS-3 -> ''' */
+ { 0x05, 0x6B }, /* BRAILLE PATTERN DOTS-13 -> 'k' */
+ { 0x06, 0x32 }, /* BRAILLE PATTERN DOTS-23 -> '2' */
+ { 0x07, 0x6C }, /* BRAILLE PATTERN DOTS-123 -> 'l' */
+ { 0x08, 0x40 }, /* BRAILLE PATTERN DOTS-4 -> '@' */
+ { 0x09, 0x63 }, /* BRAILLE PATTERN DOTS-14 -> 'c' */
+ { 0x0A, 0x69 }, /* BRAILLE PATTERN DOTS-24 -> 'i' */
+ { 0x0B, 0x66 }, /* BRAILLE PATTERN DOTS-124 -> 'f' */
+ { 0x0C, 0x2F }, /* BRAILLE PATTERN DOTS-34 -> '/' */
+ { 0x0D, 0x6D }, /* BRAILLE PATTERN DOTS-134 -> 'm' */
+ { 0x0E, 0x73 }, /* BRAILLE PATTERN DOTS-234 -> 's' */
+ { 0x0F, 0x70 }, /* BRAILLE PATTERN DOTS-1234 -> 'p' */
+ { 0x10, 0x22 }, /* BRAILLE PATTERN DOTS-5 -> '"' */
+ { 0x11, 0x65 }, /* BRAILLE PATTERN DOTS-15 -> 'e' */
+ { 0x12, 0x33 }, /* BRAILLE PATTERN DOTS-25 -> '3' */
+ { 0x13, 0x68 }, /* BRAILLE PATTERN DOTS-125 -> 'h' */
+ { 0x14, 0x39 }, /* BRAILLE PATTERN DOTS-35 -> '9' */
+ { 0x15, 0x6F }, /* BRAILLE PATTERN DOTS-135 -> 'o' */
+ { 0x16, 0x36 }, /* BRAILLE PATTERN DOTS-235 -> '6' */
+ { 0x17, 0x72 }, /* BRAILLE PATTERN DOTS-1235 -> 'r' */
+ { 0x18, 0x5E }, /* BRAILLE PATTERN DOTS-45 -> '^' */
+ { 0x19, 0x64 }, /* BRAILLE PATTERN DOTS-145 -> 'd' */
+ { 0x1A, 0x6A }, /* BRAILLE PATTERN DOTS-245 -> 'j' */
+ { 0x1B, 0x67 }, /* BRAILLE PATTERN DOTS-1245 -> 'g' */
+ { 0x1C, 0x3E }, /* BRAILLE PATTERN DOTS-345 -> '>' */
+ { 0x1D, 0x6E }, /* BRAILLE PATTERN DOTS-1345 -> 'n' */
+ { 0x1E, 0x74 }, /* BRAILLE PATTERN DOTS-2345 -> 't' */
+ { 0x1F, 0x71 }, /* BRAILLE PATTERN DOTS-12345 -> 'q' */
+ { 0x20, 0x2C }, /* BRAILLE PATTERN DOTS-6 -> ',' */
+ { 0x21, 0x2A }, /* BRAILLE PATTERN DOTS-16 -> '*' */
+ { 0x22, 0x35 }, /* BRAILLE PATTERN DOTS-26 -> '5' */
+ { 0x23, 0x3C }, /* BRAILLE PATTERN DOTS-126 -> '<' */
+ { 0x24, 0x2D }, /* BRAILLE PATTERN DOTS-36 -> '-' */
+ { 0x25, 0x75 }, /* BRAILLE PATTERN DOTS-136 -> 'u' */
+ { 0x26, 0x38 }, /* BRAILLE PATTERN DOTS-236 -> '8' */
+ { 0x27, 0x76 }, /* BRAILLE PATTERN DOTS-1236 -> 'v' */
+ { 0x28, 0x2E }, /* BRAILLE PATTERN DOTS-46 -> '.' */
+ { 0x29, 0x25 }, /* BRAILLE PATTERN DOTS-146 -> '%' */
+ { 0x2A, 0x5B }, /* BRAILLE PATTERN DOTS-246 -> '[' */
+ { 0x2B, 0x24 }, /* BRAILLE PATTERN DOTS-1246 -> '$' */
+ { 0x2C, 0x2B }, /* BRAILLE PATTERN DOTS-346 -> '+' */
+ { 0x2D, 0x78 }, /* BRAILLE PATTERN DOTS-1346 -> 'x' */
+ { 0x2E, 0x21 }, /* BRAILLE PATTERN DOTS-2346 -> '!' */
+ { 0x2F, 0x26 }, /* BRAILLE PATTERN DOTS-12346 -> '&' */
+ { 0x30, 0x3B }, /* BRAILLE PATTERN DOTS-56 -> ';' */
+ { 0x31, 0x3A }, /* BRAILLE PATTERN DOTS-156 -> ':' */
+ { 0x32, 0x34 }, /* BRAILLE PATTERN DOTS-256 -> '4' */
+ { 0x33, 0x5C }, /* BRAILLE PATTERN DOTS-1256 -> '\' */
+ { 0x34, 0x30 }, /* BRAILLE PATTERN DOTS-356 -> '0' */
+ { 0x35, 0x7A }, /* BRAILLE PATTERN DOTS-1356 -> 'z' */
+ { 0x36, 0x37 }, /* BRAILLE PATTERN DOTS-2356 -> '7' */
+ { 0x37, 0x28 }, /* BRAILLE PATTERN DOTS-12356 -> '(' */
+ { 0x38, 0x5F }, /* BRAILLE PATTERN DOTS-456 -> '_' */
+ { 0x39, 0x3F }, /* BRAILLE PATTERN DOTS-1456 -> '?' */
+ { 0x3A, 0x77 }, /* BRAILLE PATTERN DOTS-2456 -> 'w' */
+ { 0x3B, 0x5D }, /* BRAILLE PATTERN DOTS-12456 -> ']' */
+ { 0x3C, 0x23 }, /* BRAILLE PATTERN DOTS-3456 -> '#' */
+ { 0x3D, 0x79 }, /* BRAILLE PATTERN DOTS-13456 -> 'y' */
+ { 0x3E, 0x29 }, /* BRAILLE PATTERN DOTS-23456 -> ')' */
+ { 0x3F, 0x3D }, /* BRAILLE PATTERN DOTS-123456 -> '=' */
+ /* Entries for page 0x29 */
+ { 0x83, 0x7B }, /* LEFT WHITE CURLY BRACKET -> '{' */
+ /* Entries for page 0x2C */
+ { 0x60, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOUBLE BAR -> 'L' */
+ { 0x61, 0x6C }, /* LATIN SMALL LETTER L WITH DOUBLE BAR -> 'l' */
+ { 0x62, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE -> 'L' */
+ { 0x63, 0x50 }, /* LATIN CAPITAL LETTER P WITH STROKE -> 'P' */
+ { 0x64, 0x52 }, /* LATIN CAPITAL LETTER R WITH TAIL -> 'R' */
+ { 0x65, 0x61 }, /* LATIN SMALL LETTER A WITH STROKE -> 'a' */
+ { 0x66, 0x74 }, /* LATIN SMALL LETTER T WITH DIAGONAL STROKE -> 't' */
+ { 0x67, 0x48 }, /* LATIN CAPITAL LETTER H WITH DESCENDER -> 'H' */
+ { 0x68, 0x68 }, /* LATIN SMALL LETTER H WITH DESCENDER -> 'h' */
+ { 0x69, 0x4B }, /* LATIN CAPITAL LETTER K WITH DESCENDER -> 'K' */
+ { 0x6A, 0x6B }, /* LATIN SMALL LETTER K WITH DESCENDER -> 'k' */
+ { 0x6B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DESCENDER -> 'Z' */
+ { 0x6C, 0x7A }, /* LATIN SMALL LETTER Z WITH DESCENDER -> 'z' */
+ { 0x6E, 0x4D }, /* LATIN CAPITAL LETTER M WITH HOOK -> 'M' */
+ { 0x6F, 0x41 }, /* LATIN CAPITAL LETTER TURNED A -> 'A' */
+ /* Entries for page 0x2E */
+ { 0x00, 0x72 }, /* RIGHT ANGLE SUBSTITUTION MARKER -> 'r' */
+ { 0x06, 0x54 }, /* RAISED INTERPOLATION MARKER -> 'T' */
+ { 0x09, 0x73 }, /* LEFT TRANSPOSITION BRACKET -> 's' */
+ { 0x0C, 0x5C }, /* LEFT RAISED OMISSION BRACKET -> '\' */
+ { 0x0D, 0x2F }, /* RIGHT RAISED OMISSION BRACKET -> '/' */
+ { 0x12, 0x3E }, /* HYPODIASTOLE -> '>' */
+ { 0x13, 0x25 }, /* DOTTED OBELOS -> '%' */
+ { 0x16, 0x3E }, /* DOTTED RIGHT-POINTING ANGLE -> '>' */
+ { 0x17, 0x3D }, /* DOUBLE OBLIQUE HYPHEN -> '=' */
+ { 0x19, 0x2F }, /* PALM BRANCH -> '/' */
+ { 0x1A, 0x2D }, /* HYPHEN WITH DIAERESIS -> '-' */
+ { 0x1B, 0x7E }, /* TILDE WITH RING ABOVE -> '~' */
+ { 0x1C, 0x5C }, /* LEFT LOW PARAPHRASE BRACKET -> '\' */
+ { 0x1D, 0x2F }, /* RIGHT LOW PARAPHRASE BRACKET -> '/' */
+ { 0x1E, 0x7E }, /* TILDE WITH DOT ABOVE -> '~' */
+ { 0x1F, 0x7E }, /* TILDE WITH DOT BELOW -> '~' */
+ { 0x2E, 0x3F }, /* REVERSED QUESTION MARK -> '?' */
+ { 0x2F, 0x27 }, /* VERTICAL TILDE -> ''' */
+ { 0x30, 0x6F }, /* RING POINT -> 'o' */
+ { 0x31, 0x2E }, /* WORD SEPARATOR MIDDLE DOT -> '.' */
+ { 0x32, 0x2C }, /* TURNED COMMA -> ',' */
+ { 0x33, 0x2E }, /* RAISED DOT -> '.' */
+ { 0x34, 0x2C }, /* RAISED COMMA -> ',' */
+ { 0x35, 0x3B }, /* TURNED SEMICOLON -> ';' */
+ { 0x3C, 0x78 }, /* STENOGRAPHIC FULL STOP -> 'x' */
+ { 0x3D, 0x7C }, /* VERTICAL SIX DOTS -> '|' */
+ { 0x40, 0x3D }, /* DOUBLE HYPHEN -> '=' */
+ { 0x41, 0x2C }, /* REVERSED COMMA -> ',' */
+ { 0x42, 0x22 }, /* DOUBLE LOW-REVERSED-9 QUOTATION MARK -> '"' */
+ /* Entries for page 0x30 */
+ { 0x00, 0x20 }, /* IDEOGRAPHIC SPACE -> ' ' */
+ { 0x03, 0x22 }, /* DITTO MARK -> '"' */
+ { 0x05, 0x22 }, /* IDEOGRAPHIC ITERATION MARK -> '"' */
+ { 0x06, 0x2F }, /* IDEOGRAPHIC CLOSING MARK -> '/' */
+ { 0x07, 0x30 }, /* IDEOGRAPHIC NUMBER ZERO -> '0' */
+ { 0x08, 0x3C }, /* LEFT ANGLE BRACKET -> '<' */
+ { 0x0C, 0x5B }, /* LEFT CORNER BRACKET -> '[' */
+ { 0x0E, 0x7B }, /* LEFT WHITE CORNER BRACKET -> '{' */
+ { 0x12, 0x40 }, /* POSTAL MARK -> '@' */
+ { 0x14, 0x5B }, /* LEFT TORTOISE SHELL BRACKET -> '[' */
+ { 0x20, 0x40 }, /* POSTAL MARK FACE -> '@' */
+ { 0x21, 0x31 }, /* HANGZHOU NUMERAL ONE -> '1' */
+ { 0x22, 0x32 }, /* HANGZHOU NUMERAL TWO -> '2' */
+ { 0x23, 0x33 }, /* HANGZHOU NUMERAL THREE -> '3' */
+ { 0x24, 0x34 }, /* HANGZHOU NUMERAL FOUR -> '4' */
+ { 0x25, 0x35 }, /* HANGZHOU NUMERAL FIVE -> '5' */
+ { 0x26, 0x36 }, /* HANGZHOU NUMERAL SIX -> '6' */
+ { 0x27, 0x37 }, /* HANGZHOU NUMERAL SEVEN -> '7' */
+ { 0x28, 0x38 }, /* HANGZHOU NUMERAL EIGHT -> '8' */
+ { 0x29, 0x39 }, /* HANGZHOU NUMERAL NINE -> '9' */
+ { 0x30, 0x7E }, /* WAVY DASH -> '~' */
+ { 0x31, 0x00 }, /* VERTICAL KANA REPEAT MARK -> ... */
+ { 0x34, 0x2B }, /* VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF -> '+' */
+ { 0x36, 0x40 }, /* CIRCLED POSTAL MARK -> '@' */
+ { 0x41, 0x61 }, /* HIRAGANA LETTER SMALL A -> 'a' */
+ { 0x42, 0x61 }, /* HIRAGANA LETTER A -> 'a' */
+ { 0x43, 0x69 }, /* HIRAGANA LETTER SMALL I -> 'i' */
+ { 0x44, 0x69 }, /* HIRAGANA LETTER I -> 'i' */
+ { 0x45, 0x75 }, /* HIRAGANA LETTER SMALL U -> 'u' */
+ { 0x46, 0x75 }, /* HIRAGANA LETTER U -> 'u' */
+ { 0x47, 0x65 }, /* HIRAGANA LETTER SMALL E -> 'e' */
+ { 0x48, 0x65 }, /* HIRAGANA LETTER E -> 'e' */
+ { 0x49, 0x6F }, /* HIRAGANA LETTER SMALL O -> 'o' */
+ { 0x4A, 0x6F }, /* HIRAGANA LETTER O -> 'o' */
+ { 0x93, 0x6E }, /* HIRAGANA LETTER N -> 'n' */
+ { 0x9D, 0x22 }, /* HIRAGANA ITERATION MARK -> '"' */
+ { 0x9E, 0x22 }, /* HIRAGANA VOICED ITERATION MARK -> '"' */
+ { 0xA0, 0x3D }, /* KATAKANA-HIRAGANA DOUBLE HYPHEN -> '=' */
+ { 0xA1, 0x61 }, /* KATAKANA LETTER SMALL A -> 'a' */
+ { 0xA2, 0x61 }, /* KATAKANA LETTER A -> 'a' */
+ { 0xA3, 0x69 }, /* KATAKANA LETTER SMALL I -> 'i' */
+ { 0xA4, 0x69 }, /* KATAKANA LETTER I -> 'i' */
+ { 0xA5, 0x75 }, /* KATAKANA LETTER SMALL U -> 'u' */
+ { 0xA6, 0x75 }, /* KATAKANA LETTER U -> 'u' */
+ { 0xA7, 0x65 }, /* KATAKANA LETTER SMALL E -> 'e' */
+ { 0xA8, 0x65 }, /* KATAKANA LETTER E -> 'e' */
+ { 0xA9, 0x6F }, /* KATAKANA LETTER SMALL O -> 'o' */
+ { 0xAA, 0x6F }, /* KATAKANA LETTER O -> 'o' */
+ { 0xF3, 0x6E }, /* KATAKANA LETTER N -> 'n' */
+ { 0xFB, 0x2A }, /* KATAKANA MIDDLE DOT -> '*' */
+ { 0xFC, 0x2D }, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '-' */
+ { 0xFD, 0x22 }, /* KATAKANA ITERATION MARK -> '"' */
+ { 0xFE, 0x22 }, /* KATAKANA VOICED ITERATION MARK -> '"' */
+ /* Entries for page 0x31 */
+ { 0x05, 0x42 }, /* BOPOMOFO LETTER B -> 'B' */
+ { 0x06, 0x50 }, /* BOPOMOFO LETTER P -> 'P' */
+ { 0x07, 0x4D }, /* BOPOMOFO LETTER M -> 'M' */
+ { 0x08, 0x46 }, /* BOPOMOFO LETTER F -> 'F' */
+ { 0x09, 0x44 }, /* BOPOMOFO LETTER D -> 'D' */
+ { 0x0A, 0x54 }, /* BOPOMOFO LETTER T -> 'T' */
+ { 0x0B, 0x4E }, /* BOPOMOFO LETTER N -> 'N' */
+ { 0x0C, 0x4C }, /* BOPOMOFO LETTER L -> 'L' */
+ { 0x0D, 0x47 }, /* BOPOMOFO LETTER G -> 'G' */
+ { 0x0E, 0x4B }, /* BOPOMOFO LETTER K -> 'K' */
+ { 0x0F, 0x48 }, /* BOPOMOFO LETTER H -> 'H' */
+ { 0x10, 0x4A }, /* BOPOMOFO LETTER J -> 'J' */
+ { 0x11, 0x51 }, /* BOPOMOFO LETTER Q -> 'Q' */
+ { 0x12, 0x58 }, /* BOPOMOFO LETTER X -> 'X' */
+ { 0x16, 0x52 }, /* BOPOMOFO LETTER R -> 'R' */
+ { 0x17, 0x5A }, /* BOPOMOFO LETTER Z -> 'Z' */
+ { 0x18, 0x43 }, /* BOPOMOFO LETTER C -> 'C' */
+ { 0x19, 0x53 }, /* BOPOMOFO LETTER S -> 'S' */
+ { 0x1A, 0x41 }, /* BOPOMOFO LETTER A -> 'A' */
+ { 0x1B, 0x4F }, /* BOPOMOFO LETTER O -> 'O' */
+ { 0x1C, 0x45 }, /* BOPOMOFO LETTER E -> 'E' */
+ { 0x27, 0x49 }, /* BOPOMOFO LETTER I -> 'I' */
+ { 0x28, 0x55 }, /* BOPOMOFO LETTER U -> 'U' */
+ { 0x2A, 0x56 }, /* BOPOMOFO LETTER V -> 'V' */
+ { 0x31, 0x67 }, /* HANGUL LETTER KIYEOK -> 'g' */
+ { 0x34, 0x6E }, /* HANGUL LETTER NIEUN -> 'n' */
+ { 0x37, 0x64 }, /* HANGUL LETTER TIKEUT -> 'd' */
+ { 0x39, 0x72 }, /* HANGUL LETTER RIEUL -> 'r' */
+ { 0x41, 0x6D }, /* HANGUL LETTER MIEUM -> 'm' */
+ { 0x42, 0x62 }, /* HANGUL LETTER PIEUP -> 'b' */
+ { 0x45, 0x73 }, /* HANGUL LETTER SIOS -> 's' */
+ { 0x48, 0x6A }, /* HANGUL LETTER CIEUC -> 'j' */
+ { 0x4A, 0x63 }, /* HANGUL LETTER CHIEUCH -> 'c' */
+ { 0x4B, 0x6B }, /* HANGUL LETTER KHIEUKH -> 'k' */
+ { 0x4C, 0x74 }, /* HANGUL LETTER THIEUTH -> 't' */
+ { 0x4D, 0x70 }, /* HANGUL LETTER PHIEUPH -> 'p' */
+ { 0x4E, 0x68 }, /* HANGUL LETTER HIEUH -> 'h' */
+ { 0x4F, 0x61 }, /* HANGUL LETTER A -> 'a' */
+ { 0x54, 0x65 }, /* HANGUL LETTER E -> 'e' */
+ { 0x57, 0x6F }, /* HANGUL LETTER O -> 'o' */
+ { 0x5C, 0x75 }, /* HANGUL LETTER U -> 'u' */
+ { 0x63, 0x69 }, /* HANGUL LETTER I -> 'i' */
+ { 0x7F, 0x5A }, /* HANGUL LETTER PANSIOS -> 'Z' */
+ { 0x81, 0x4E }, /* HANGUL LETTER YESIEUNG -> 'N' */
+ { 0x86, 0x51 }, /* HANGUL LETTER YEORINHIEUH -> 'Q' */
+ { 0x8D, 0x55 }, /* HANGUL LETTER ARAEA -> 'U' */
+ { 0xB4, 0x50 }, /* BOPOMOFO FINAL LETTER P -> 'P' */
+ { 0xB5, 0x54 }, /* BOPOMOFO FINAL LETTER T -> 'T' */
+ { 0xB6, 0x4B }, /* BOPOMOFO FINAL LETTER K -> 'K' */
+ { 0xB7, 0x48 }, /* BOPOMOFO FINAL LETTER H -> 'H' */
+ /* Entries for page 0x32 */
+ { 0xD0, 0x61 }, /* CIRCLED KATAKANA A -> 'a' */
+ { 0xD1, 0x69 }, /* CIRCLED KATAKANA I -> 'i' */
+ { 0xD2, 0x75 }, /* CIRCLED KATAKANA U -> 'u' */
+ { 0xD3, 0x75 }, /* CIRCLED KATAKANA E -> 'u' */
+ { 0xD4, 0x6F }, /* CIRCLED KATAKANA O -> 'o' */
+ /* Entries for page 0xA0 */
+ { 0x02, 0x69 }, /* YI SYLLABLE I -> 'i' */
+ { 0x0A, 0x61 }, /* YI SYLLABLE A -> 'a' */
+ { 0x11, 0x6F }, /* YI SYLLABLE O -> 'o' */
+ { 0x14, 0x65 }, /* YI SYLLABLE E -> 'e' */
+ /* Entries for page 0xC5 */
+ { 0x44, 0x61 }, /* HANGUL SYLLABLE A -> 'a' */
+ { 0xD0, 0x65 }, /* HANGUL SYLLABLE E -> 'e' */
+ /* Entries for page 0xC6 */
+ { 0x24, 0x6F }, /* HANGUL SYLLABLE O -> 'o' */
+ { 0xB0, 0x75 }, /* HANGUL SYLLABLE U -> 'u' */
+ /* Entries for page 0xC7 */
+ { 0x74, 0x69 }, /* HANGUL SYLLABLE I -> 'i' */
+ /* Entries for page 0xFB */
+ { 0x1D, 0x69 }, /* HEBREW LETTER YOD WITH HIRIQ -> 'i' */
+ { 0x20, 0x60 }, /* HEBREW LETTER ALTERNATIVE AYIN -> '`' */
+ { 0x21, 0x41 }, /* HEBREW LETTER WIDE ALEF -> 'A' */
+ { 0x22, 0x64 }, /* HEBREW LETTER WIDE DALET -> 'd' */
+ { 0x23, 0x68 }, /* HEBREW LETTER WIDE HE -> 'h' */
+ { 0x25, 0x6C }, /* HEBREW LETTER WIDE LAMED -> 'l' */
+ { 0x26, 0x6D }, /* HEBREW LETTER WIDE FINAL MEM -> 'm' */
+ { 0x27, 0x72 }, /* HEBREW LETTER WIDE RESH -> 'r' */
+ { 0x28, 0x74 }, /* HEBREW LETTER WIDE TAV -> 't' */
+ { 0x29, 0x2B }, /* HEBREW LETTER ALTERNATIVE PLUS SIGN -> '+' */
+ { 0x2B, 0x53 }, /* HEBREW LETTER SHIN WITH SIN DOT -> 'S' */
+ { 0x2D, 0x53 }, /* HEBREW LETTER SHIN WITH DAGESH AND SIN DOT -> 'S' */
+ { 0x2E, 0x61 }, /* HEBREW LETTER ALEF WITH PATAH -> 'a' */
+ { 0x2F, 0x61 }, /* HEBREW LETTER ALEF WITH QAMATS -> 'a' */
+ { 0x30, 0x41 }, /* HEBREW LETTER ALEF WITH MAPIQ -> 'A' */
+ { 0x31, 0x62 }, /* HEBREW LETTER BET WITH DAGESH -> 'b' */
+ { 0x32, 0x67 }, /* HEBREW LETTER GIMEL WITH DAGESH -> 'g' */
+ { 0x33, 0x64 }, /* HEBREW LETTER DALET WITH DAGESH -> 'd' */
+ { 0x34, 0x68 }, /* HEBREW LETTER HE WITH MAPIQ -> 'h' */
+ { 0x35, 0x76 }, /* HEBREW LETTER VAV WITH DAGESH -> 'v' */
+ { 0x36, 0x7A }, /* HEBREW LETTER ZAYIN WITH DAGESH -> 'z' */
+ { 0x38, 0x74 }, /* HEBREW LETTER TET WITH DAGESH -> 't' */
+ { 0x39, 0x79 }, /* HEBREW LETTER YOD WITH DAGESH -> 'y' */
+ { 0x3C, 0x6C }, /* HEBREW LETTER LAMED WITH DAGESH -> 'l' */
+ { 0x3E, 0x6D }, /* HEBREW LETTER MEM WITH DAGESH -> 'm' */
+ { 0x40, 0x6E }, /* HEBREW LETTER NUN WITH DAGESH -> 'n' */
+ { 0x41, 0x73 }, /* HEBREW LETTER SAMEKH WITH DAGESH -> 's' */
+ { 0x43, 0x70 }, /* HEBREW LETTER FINAL PE WITH DAGESH -> 'p' */
+ { 0x44, 0x70 }, /* HEBREW LETTER PE WITH DAGESH -> 'p' */
+ { 0x47, 0x6B }, /* HEBREW LETTER QOF WITH DAGESH -> 'k' */
+ { 0x48, 0x72 }, /* HEBREW LETTER RESH WITH DAGESH -> 'r' */
+ { 0x4A, 0x74 }, /* HEBREW LETTER TAV WITH DAGESH -> 't' */
+ { 0x4B, 0x6F }, /* HEBREW LETTER VAV WITH HOLAM -> 'o' */
+ { 0x4C, 0x76 }, /* HEBREW LETTER BET WITH RAFE -> 'v' */
+ { 0x4E, 0x66 }, /* HEBREW LETTER PE WITH RAFE -> 'f' */
+ /* Entries for page 0xFE */
+ { 0x23, 0x7E }, /* COMBINING DOUBLE TILDE RIGHT HALF -> '~' */
+ { 0x32, 0x2D }, /* PRESENTATION FORM FOR VERTICAL EN DASH -> '-' */
+ { 0x33, 0x5F }, /* PRESENTATION FORM FOR VERTICAL LOW LINE -> '_' */
+ { 0x34, 0x5F }, /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE -> '_' */
+ { 0x35, 0x28 }, /* PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS -> '(' */
+ { 0x37, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET -> '{' */
+ { 0x39, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET -> '[' */
+ { 0x3F, 0x3C }, /* PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET -> '<' */
+ { 0x41, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET -> '[' */
+ { 0x43, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET -> '{' */
+ { 0x44, 0x7D }, /* PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET -> '}' */
+ { 0x50, 0x2C }, /* SMALL COMMA -> ',' */
+ { 0x51, 0x2C }, /* SMALL IDEOGRAPHIC COMMA -> ',' */
+ { 0x52, 0x2E }, /* SMALL FULL STOP -> '.' */
+ { 0x54, 0x3B }, /* SMALL SEMICOLON -> ';' */
+ { 0x55, 0x3A }, /* SMALL COLON -> ':' */
+ { 0x56, 0x3F }, /* SMALL QUESTION MARK -> '?' */
+ { 0x57, 0x21 }, /* SMALL EXCLAMATION MARK -> '!' */
+ { 0x58, 0x2D }, /* SMALL EM DASH -> '-' */
+ { 0x59, 0x28 }, /* SMALL LEFT PARENTHESIS -> '(' */
+ { 0x5A, 0x29 }, /* SMALL RIGHT PARENTHESIS -> ')' */
+ { 0x5B, 0x7B }, /* SMALL LEFT CURLY BRACKET -> '{' */
+ { 0x5C, 0x7D }, /* SMALL RIGHT CURLY BRACKET -> '}' */
+ { 0x5D, 0x7B }, /* SMALL LEFT TORTOISE SHELL BRACKET -> '{' */
+ { 0x5E, 0x7D }, /* SMALL RIGHT TORTOISE SHELL BRACKET -> '}' */
+ { 0x5F, 0x23 }, /* SMALL NUMBER SIGN -> '#' */
+ { 0x60, 0x26 }, /* SMALL AMPERSAND -> '&' */
+ { 0x61, 0x2A }, /* SMALL ASTERISK -> '*' */
+ { 0x62, 0x2B }, /* SMALL PLUS SIGN -> '+' */
+ { 0x63, 0x2D }, /* SMALL HYPHEN-MINUS -> '-' */
+ { 0x64, 0x3C }, /* SMALL LESS-THAN SIGN -> '<' */
+ { 0x65, 0x3E }, /* SMALL GREATER-THAN SIGN -> '>' */
+ { 0x66, 0x3D }, /* SMALL EQUALS SIGN -> '=' */
+ { 0x68, 0x5C }, /* SMALL REVERSE SOLIDUS -> '\' */
+ { 0x69, 0x24 }, /* SMALL DOLLAR SIGN -> '$' */
+ { 0x6A, 0x25 }, /* SMALL PERCENT SIGN -> '%' */
+ { 0x6B, 0x40 }, /* SMALL COMMERCIAL AT -> '@' */
+ /* Entries for page 0xFF */
+ { 0x61, 0x2E }, /* HALFWIDTH IDEOGRAPHIC FULL STOP -> '.' */
+ { 0x62, 0x5B }, /* HALFWIDTH LEFT CORNER BRACKET -> '[' */
+ { 0x63, 0x5D }, /* HALFWIDTH RIGHT CORNER BRACKET -> ']' */
+ { 0x64, 0x2C }, /* HALFWIDTH IDEOGRAPHIC COMMA -> ',' */
+ { 0x65, 0x2A }, /* HALFWIDTH KATAKANA MIDDLE DOT -> '*' */
+ { 0x67, 0x61 }, /* HALFWIDTH KATAKANA LETTER SMALL A -> 'a' */
+ { 0x68, 0x69 }, /* HALFWIDTH KATAKANA LETTER SMALL I -> 'i' */
+ { 0x69, 0x75 }, /* HALFWIDTH KATAKANA LETTER SMALL U -> 'u' */
+ { 0x6A, 0x65 }, /* HALFWIDTH KATAKANA LETTER SMALL E -> 'e' */
+ { 0x6B, 0x6F }, /* HALFWIDTH KATAKANA LETTER SMALL O -> 'o' */
+ { 0x70, 0x2B }, /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '+' */
+ { 0x71, 0x61 }, /* HALFWIDTH KATAKANA LETTER A -> 'a' */
+ { 0x72, 0x69 }, /* HALFWIDTH KATAKANA LETTER I -> 'i' */
+ { 0x73, 0x75 }, /* HALFWIDTH KATAKANA LETTER U -> 'u' */
+ { 0x74, 0x65 }, /* HALFWIDTH KATAKANA LETTER E -> 'e' */
+ { 0x75, 0x6F }, /* HALFWIDTH KATAKANA LETTER O -> 'o' */
+ { 0x9D, 0x6E }, /* HALFWIDTH KATAKANA LETTER N -> 'n' */
+ { 0x9E, 0x3A }, /* HALFWIDTH KATAKANA VOICED SOUND MARK -> ':' */
+ { 0x9F, 0x3B }, /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -> ';' */
+ { 0xA1, 0x67 }, /* HALFWIDTH HANGUL LETTER KIYEOK -> 'g' */
+ { 0xA4, 0x6E }, /* HALFWIDTH HANGUL LETTER NIEUN -> 'n' */
+ { 0xA7, 0x64 }, /* HALFWIDTH HANGUL LETTER TIKEUT -> 'd' */
+ { 0xA9, 0x72 }, /* HALFWIDTH HANGUL LETTER RIEUL -> 'r' */
+ { 0xB1, 0x6D }, /* HALFWIDTH HANGUL LETTER MIEUM -> 'm' */
+ { 0xB2, 0x62 }, /* HALFWIDTH HANGUL LETTER PIEUP -> 'b' */
+ { 0xB5, 0x73 }, /* HALFWIDTH HANGUL LETTER SIOS -> 's' */
+ { 0xB8, 0x6A }, /* HALFWIDTH HANGUL LETTER CIEUC -> 'j' */
+ { 0xBA, 0x63 }, /* HALFWIDTH HANGUL LETTER CHIEUCH -> 'c' */
+ { 0xBB, 0x6B }, /* HALFWIDTH HANGUL LETTER KHIEUKH -> 'k' */
+ { 0xBC, 0x74 }, /* HALFWIDTH HANGUL LETTER THIEUTH -> 't' */
+ { 0xBD, 0x70 }, /* HALFWIDTH HANGUL LETTER PHIEUPH -> 'p' */
+ { 0xBE, 0x68 }, /* HALFWIDTH HANGUL LETTER HIEUH -> 'h' */
+ { 0xC2, 0x61 }, /* HALFWIDTH HANGUL LETTER A -> 'a' */
+ { 0xC7, 0x65 }, /* HALFWIDTH HANGUL LETTER E -> 'e' */
+ { 0xCC, 0x6F }, /* HALFWIDTH HANGUL LETTER O -> 'o' */
+ { 0xD3, 0x75 }, /* HALFWIDTH HANGUL LETTER U -> 'u' */
+ { 0xDC, 0x69 }, /* HALFWIDTH HANGUL LETTER I -> 'i' */
+ { 0xE2, 0x21 }, /* FULLWIDTH NOT SIGN -> '!' */
+ { 0xE3, 0x2D }, /* FULLWIDTH MACRON -> '-' */
+ { 0xE4, 0x7C }, /* FULLWIDTH BROKEN BAR -> '|' */
+ { 0xE8, 0x7C }, /* HALFWIDTH FORMS LIGHT VERTICAL -> '|' */
+ { 0xE9, 0x3C }, /* HALFWIDTH LEFTWARDS ARROW -> '<' */
+ { 0xEA, 0x5E }, /* HALFWIDTH UPWARDS ARROW -> '^' */
+ { 0xEB, 0x3E }, /* HALFWIDTH RIGHTWARDS ARROW -> '>' */
+ { 0xEC, 0x76 }, /* HALFWIDTH DOWNWARDS ARROW -> 'v' */
+ { 0xED, 0x23 }, /* HALFWIDTH BLACK SQUARE -> '#' */
+ { 0xEE, 0x4F }, /* HALFWIDTH WHITE CIRCLE -> 'O' */
+ { 0xF9, 0x7B }, /* INTERLINEAR ANNOTATION ANCHOR -> '{' */
+ { 0xFA, 0x7C }, /* INTERLINEAR ANNOTATION SEPARATOR -> '|' */
+ { 0xFB, 0x7D }, /* INTERLINEAR ANNOTATION TERMINATOR -> '}' */
+};
+
+#define UCS_PAGE_ENTRY_RANGE_MARKER 0
diff --git a/drivers/tty/vt/ucs_recompose_table.h_shipped b/drivers/tty/vt/ucs_recompose_table.h_shipped
new file mode 100644
index 000000000000..bd91edde5d19
--- /dev/null
+++ b/drivers/tty/vt/ucs_recompose_table.h_shipped
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_recompose_table.h - Unicode character recomposition
+ *
+ * Auto-generated by gen_ucs_recompose_table.py
+ *
+ * Unicode Version: 16.0.0
+ *
+ * This file contains a table with most commonly used Latin, Greek, and
+ * Cyrillic recomposition pairs only (71 entries). To generate a table with
+ * all possible recomposition pairs from the Unicode BMP (1000 entries)
+ * instead, run:
+ *
+ * python gen_ucs_recompose_table.py --full
+ */
+
+/*
+ * Table of most commonly used Latin, Greek, and Cyrillic recomposition pairs only
+ * Sorted by base character and then combining mark for binary search
+ */
+static const struct ucs_recomposition ucs_recomposition_table[] = {
+ { 0x0041, 0x0300, 0x00C0 }, /* LATIN CAPITAL LETTER A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE */
+ { 0x0041, 0x0301, 0x00C1 }, /* LATIN CAPITAL LETTER A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE */
+ { 0x0041, 0x0302, 0x00C2 }, /* LATIN CAPITAL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ { 0x0041, 0x0303, 0x00C3 }, /* LATIN CAPITAL LETTER A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE */
+ { 0x0041, 0x0308, 0x00C4 }, /* LATIN CAPITAL LETTER A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS */
+ { 0x0041, 0x030A, 0x00C5 }, /* LATIN CAPITAL LETTER A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE */
+ { 0x0043, 0x0327, 0x00C7 }, /* LATIN CAPITAL LETTER C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA */
+ { 0x0045, 0x0300, 0x00C8 }, /* LATIN CAPITAL LETTER E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE */
+ { 0x0045, 0x0301, 0x00C9 }, /* LATIN CAPITAL LETTER E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE */
+ { 0x0045, 0x0302, 0x00CA }, /* LATIN CAPITAL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ { 0x0045, 0x0308, 0x00CB }, /* LATIN CAPITAL LETTER E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS */
+ { 0x0049, 0x0300, 0x00CC }, /* LATIN CAPITAL LETTER I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE */
+ { 0x0049, 0x0301, 0x00CD }, /* LATIN CAPITAL LETTER I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE */
+ { 0x0049, 0x0302, 0x00CE }, /* LATIN CAPITAL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ { 0x0049, 0x0308, 0x00CF }, /* LATIN CAPITAL LETTER I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS */
+ { 0x004E, 0x0303, 0x00D1 }, /* LATIN CAPITAL LETTER N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE */
+ { 0x004F, 0x0300, 0x00D2 }, /* LATIN CAPITAL LETTER O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE */
+ { 0x004F, 0x0301, 0x00D3 }, /* LATIN CAPITAL LETTER O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE */
+ { 0x004F, 0x0302, 0x00D4 }, /* LATIN CAPITAL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ { 0x004F, 0x0303, 0x00D5 }, /* LATIN CAPITAL LETTER O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE */
+ { 0x004F, 0x0308, 0x00D6 }, /* LATIN CAPITAL LETTER O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS */
+ { 0x0055, 0x0300, 0x00D9 }, /* LATIN CAPITAL LETTER U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE */
+ { 0x0055, 0x0301, 0x00DA }, /* LATIN CAPITAL LETTER U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE */
+ { 0x0055, 0x0302, 0x00DB }, /* LATIN CAPITAL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ { 0x0055, 0x0308, 0x00DC }, /* LATIN CAPITAL LETTER U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS */
+ { 0x0059, 0x0301, 0x00DD }, /* LATIN CAPITAL LETTER Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE */
+ { 0x0061, 0x0300, 0x00E0 }, /* LATIN SMALL LETTER A + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE */
+ { 0x0061, 0x0301, 0x00E1 }, /* LATIN SMALL LETTER A + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE */
+ { 0x0061, 0x0302, 0x00E2 }, /* LATIN SMALL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ { 0x0061, 0x0303, 0x00E3 }, /* LATIN SMALL LETTER A + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE */
+ { 0x0061, 0x0308, 0x00E4 }, /* LATIN SMALL LETTER A + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS */
+ { 0x0061, 0x030A, 0x00E5 }, /* LATIN SMALL LETTER A + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE */
+ { 0x0063, 0x0327, 0x00E7 }, /* LATIN SMALL LETTER C + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA */
+ { 0x0065, 0x0300, 0x00E8 }, /* LATIN SMALL LETTER E + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE */
+ { 0x0065, 0x0301, 0x00E9 }, /* LATIN SMALL LETTER E + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE */
+ { 0x0065, 0x0302, 0x00EA }, /* LATIN SMALL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ { 0x0065, 0x0308, 0x00EB }, /* LATIN SMALL LETTER E + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS */
+ { 0x0069, 0x0300, 0x00EC }, /* LATIN SMALL LETTER I + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE */
+ { 0x0069, 0x0301, 0x00ED }, /* LATIN SMALL LETTER I + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE */
+ { 0x0069, 0x0302, 0x00EE }, /* LATIN SMALL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ { 0x0069, 0x0308, 0x00EF }, /* LATIN SMALL LETTER I + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS */
+ { 0x006E, 0x0303, 0x00F1 }, /* LATIN SMALL LETTER N + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE */
+ { 0x006F, 0x0300, 0x00F2 }, /* LATIN SMALL LETTER O + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE */
+ { 0x006F, 0x0301, 0x00F3 }, /* LATIN SMALL LETTER O + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE */
+ { 0x006F, 0x0302, 0x00F4 }, /* LATIN SMALL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ { 0x006F, 0x0303, 0x00F5 }, /* LATIN SMALL LETTER O + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE */
+ { 0x006F, 0x0308, 0x00F6 }, /* LATIN SMALL LETTER O + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS */
+ { 0x0075, 0x0300, 0x00F9 }, /* LATIN SMALL LETTER U + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE */
+ { 0x0075, 0x0301, 0x00FA }, /* LATIN SMALL LETTER U + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE */
+ { 0x0075, 0x0302, 0x00FB }, /* LATIN SMALL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ { 0x0075, 0x0308, 0x00FC }, /* LATIN SMALL LETTER U + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS */
+ { 0x0079, 0x0301, 0x00FD }, /* LATIN SMALL LETTER Y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE */
+ { 0x0079, 0x0308, 0x00FF }, /* LATIN SMALL LETTER Y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS */
+ { 0x0391, 0x0301, 0x0386 }, /* GREEK CAPITAL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS */
+ { 0x0395, 0x0301, 0x0388 }, /* GREEK CAPITAL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS */
+ { 0x0397, 0x0301, 0x0389 }, /* GREEK CAPITAL LETTER ETA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS */
+ { 0x0399, 0x0301, 0x038A }, /* GREEK CAPITAL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS */
+ { 0x039F, 0x0301, 0x038C }, /* GREEK CAPITAL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS */
+ { 0x03A5, 0x0301, 0x038E }, /* GREEK CAPITAL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS */
+ { 0x03A9, 0x0301, 0x038F }, /* GREEK CAPITAL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS */
+ { 0x03B1, 0x0301, 0x03AC }, /* GREEK SMALL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS */
+ { 0x03B5, 0x0301, 0x03AD }, /* GREEK SMALL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS */
+ { 0x03B7, 0x0301, 0x03AE }, /* GREEK SMALL LETTER ETA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS */
+ { 0x03B9, 0x0301, 0x03AF }, /* GREEK SMALL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS */
+ { 0x03BF, 0x0301, 0x03CC }, /* GREEK SMALL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS */
+ { 0x03C5, 0x0301, 0x03CD }, /* GREEK SMALL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS */
+ { 0x03C9, 0x0301, 0x03CE }, /* GREEK SMALL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS */
+ { 0x0418, 0x0306, 0x0419 }, /* CYRILLIC CAPITAL LETTER I + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I */
+ { 0x0423, 0x0306, 0x040E }, /* CYRILLIC CAPITAL LETTER U + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U */
+ { 0x0438, 0x0306, 0x0439 }, /* CYRILLIC SMALL LETTER I + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I */
+ { 0x0443, 0x0306, 0x045E }, /* CYRILLIC SMALL LETTER U + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U */
+};
+
+/*
+ * Boundary values for quick rejection
+ * These are calculated by analyzing the table during generation
+ */
+#define UCS_RECOMPOSE_MIN_BASE 0x0041
+#define UCS_RECOMPOSE_MAX_BASE 0x0443
+#define UCS_RECOMPOSE_MIN_MARK 0x0300
+#define UCS_RECOMPOSE_MAX_MARK 0x0327
diff --git a/drivers/tty/vt/ucs_width_table.h_shipped b/drivers/tty/vt/ucs_width_table.h_shipped
new file mode 100644
index 000000000000..6fcb8f1d577d
--- /dev/null
+++ b/drivers/tty/vt/ucs_width_table.h_shipped
@@ -0,0 +1,453 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_width_table.h - Unicode character width
+ *
+ * Auto-generated by gen_ucs_width_table.py
+ *
+ * Unicode Version: 16.0.0
+ */
+
+/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {
+ { 0x00AD, 0x00AD }, /* SOFT HYPHEN */
+ { 0x0300, 0x036F }, /* COMBINING GRAVE ACCENT - COMBINING LATIN SMALL LETTER X */
+ { 0x0483, 0x0489 }, /* COMBINING CYRILLIC TITLO - COMBINING CYRILLIC MILLIONS SIGN */
+ { 0x0591, 0x05BD }, /* HEBREW ACCENT ETNAHTA - HEBREW POINT METEG */
+ { 0x05BF, 0x05BF }, /* HEBREW POINT RAFE */
+ { 0x05C1, 0x05C2 }, /* HEBREW POINT SHIN DOT - HEBREW POINT SIN DOT */
+ { 0x05C4, 0x05C5 }, /* HEBREW MARK UPPER DOT - HEBREW MARK LOWER DOT */
+ { 0x05C7, 0x05C7 }, /* HEBREW POINT QAMATS QATAN */
+ { 0x0600, 0x0605 }, /* ARABIC NUMBER SIGN - ARABIC NUMBER MARK ABOVE */
+ { 0x0610, 0x061A }, /* ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM - ARABIC SMALL KASRA */
+ { 0x061C, 0x061C }, /* ARABIC LETTER MARK */
+ { 0x064B, 0x065F }, /* ARABIC FATHATAN - ARABIC WAVY HAMZA BELOW */
+ { 0x0670, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */
+ { 0x06D6, 0x06DD }, /* ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA - ARABIC END OF AYAH */
+ { 0x06DF, 0x06E4 }, /* ARABIC SMALL HIGH ROUNDED ZERO - ARABIC SMALL HIGH MADDA */
+ { 0x06E7, 0x06E8 }, /* ARABIC SMALL HIGH YEH - ARABIC SMALL HIGH NOON */
+ { 0x06EA, 0x06ED }, /* ARABIC EMPTY CENTRE LOW STOP - ARABIC SMALL LOW MEEM */
+ { 0x070F, 0x070F }, /* SYRIAC ABBREVIATION MARK */
+ { 0x0711, 0x0711 }, /* SYRIAC LETTER SUPERSCRIPT ALAPH */
+ { 0x0730, 0x074A }, /* SYRIAC PTHAHA ABOVE - SYRIAC BARREKH */
+ { 0x07A6, 0x07B0 }, /* THAANA ABAFILI - THAANA SUKUN */
+ { 0x07EB, 0x07F3 }, /* NKO COMBINING SHORT HIGH TONE - NKO COMBINING DOUBLE DOT ABOVE */
+ { 0x07FD, 0x07FD }, /* NKO DANTAYALAN */
+ { 0x0816, 0x0819 }, /* SAMARITAN MARK IN - SAMARITAN MARK DAGESH */
+ { 0x081B, 0x0823 }, /* SAMARITAN MARK EPENTHETIC YUT - SAMARITAN VOWEL SIGN A */
+ { 0x0825, 0x0827 }, /* SAMARITAN VOWEL SIGN SHORT A - SAMARITAN VOWEL SIGN U */
+ { 0x0829, 0x082D }, /* SAMARITAN VOWEL SIGN LONG I - SAMARITAN MARK NEQUDAA */
+ { 0x0859, 0x085B }, /* MANDAIC AFFRICATION MARK - MANDAIC GEMINATION MARK */
+ { 0x0890, 0x0891 }, /* ARABIC POUND MARK ABOVE - ARABIC PIASTRE MARK ABOVE */
+ { 0x0897, 0x089F }, /* ARABIC PEPET - ARABIC HALF MADDA OVER MADDA */
+ { 0x08CA, 0x0903 }, /* ARABIC SMALL HIGH FARSI YEH - DEVANAGARI SIGN VISARGA */
+ { 0x093A, 0x093C }, /* DEVANAGARI VOWEL SIGN OE - DEVANAGARI SIGN NUKTA */
+ { 0x093E, 0x094F }, /* DEVANAGARI VOWEL SIGN AA - DEVANAGARI VOWEL SIGN AW */
+ { 0x0951, 0x0957 }, /* DEVANAGARI STRESS SIGN UDATTA - DEVANAGARI VOWEL SIGN UUE */
+ { 0x0962, 0x0963 }, /* DEVANAGARI VOWEL SIGN VOCALIC L - DEVANAGARI VOWEL SIGN VOCALIC LL */
+ { 0x0981, 0x0983 }, /* BENGALI SIGN CANDRABINDU - BENGALI SIGN VISARGA */
+ { 0x09BC, 0x09BC }, /* BENGALI SIGN NUKTA */
+ { 0x09BE, 0x09C4 }, /* BENGALI VOWEL SIGN AA - BENGALI VOWEL SIGN VOCALIC RR */
+ { 0x09C7, 0x09C8 }, /* BENGALI VOWEL SIGN E - BENGALI VOWEL SIGN AI */
+ { 0x09CB, 0x09CD }, /* BENGALI VOWEL SIGN O - BENGALI SIGN VIRAMA */
+ { 0x09D7, 0x09D7 }, /* BENGALI AU LENGTH MARK */
+ { 0x09E2, 0x09E3 }, /* BENGALI VOWEL SIGN VOCALIC L - BENGALI VOWEL SIGN VOCALIC LL */
+ { 0x09FE, 0x09FE }, /* BENGALI SANDHI MARK */
+ { 0x0A01, 0x0A03 }, /* GURMUKHI SIGN ADAK BINDI - GURMUKHI SIGN VISARGA */
+ { 0x0A3C, 0x0A3C }, /* GURMUKHI SIGN NUKTA */
+ { 0x0A3E, 0x0A42 }, /* GURMUKHI VOWEL SIGN AA - GURMUKHI VOWEL SIGN UU */
+ { 0x0A47, 0x0A48 }, /* GURMUKHI VOWEL SIGN EE - GURMUKHI VOWEL SIGN AI */
+ { 0x0A4B, 0x0A4D }, /* GURMUKHI VOWEL SIGN OO - GURMUKHI SIGN VIRAMA */
+ { 0x0A51, 0x0A51 }, /* GURMUKHI SIGN UDAAT */
+ { 0x0A70, 0x0A71 }, /* GURMUKHI TIPPI - GURMUKHI ADDAK */
+ { 0x0A75, 0x0A75 }, /* GURMUKHI SIGN YAKASH */
+ { 0x0A81, 0x0A83 }, /* GUJARATI SIGN CANDRABINDU - GUJARATI SIGN VISARGA */
+ { 0x0ABC, 0x0ABC }, /* GUJARATI SIGN NUKTA */
+ { 0x0ABE, 0x0AC5 }, /* GUJARATI VOWEL SIGN AA - GUJARATI VOWEL SIGN CANDRA E */
+ { 0x0AC7, 0x0AC9 }, /* GUJARATI VOWEL SIGN E - GUJARATI VOWEL SIGN CANDRA O */
+ { 0x0ACB, 0x0ACD }, /* GUJARATI VOWEL SIGN O - GUJARATI SIGN VIRAMA */
+ { 0x0AE2, 0x0AE3 }, /* GUJARATI VOWEL SIGN VOCALIC L - GUJARATI VOWEL SIGN VOCALIC LL */
+ { 0x0AFA, 0x0AFF }, /* GUJARATI SIGN SUKUN - GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE */
+ { 0x0B01, 0x0B03 }, /* ORIYA SIGN CANDRABINDU - ORIYA SIGN VISARGA */
+ { 0x0B3C, 0x0B3C }, /* ORIYA SIGN NUKTA */
+ { 0x0B3E, 0x0B44 }, /* ORIYA VOWEL SIGN AA - ORIYA VOWEL SIGN VOCALIC RR */
+ { 0x0B47, 0x0B48 }, /* ORIYA VOWEL SIGN E - ORIYA VOWEL SIGN AI */
+ { 0x0B4B, 0x0B4D }, /* ORIYA VOWEL SIGN O - ORIYA SIGN VIRAMA */
+ { 0x0B55, 0x0B57 }, /* ORIYA SIGN OVERLINE - ORIYA AU LENGTH MARK */
+ { 0x0B62, 0x0B63 }, /* ORIYA VOWEL SIGN VOCALIC L - ORIYA VOWEL SIGN VOCALIC LL */
+ { 0x0B82, 0x0B82 }, /* TAMIL SIGN ANUSVARA */
+ { 0x0BBE, 0x0BC2 }, /* TAMIL VOWEL SIGN AA - TAMIL VOWEL SIGN UU */
+ { 0x0BC6, 0x0BC8 }, /* TAMIL VOWEL SIGN E - TAMIL VOWEL SIGN AI */
+ { 0x0BCA, 0x0BCD }, /* TAMIL VOWEL SIGN O - TAMIL SIGN VIRAMA */
+ { 0x0BD7, 0x0BD7 }, /* TAMIL AU LENGTH MARK */
+ { 0x0C00, 0x0C04 }, /* TELUGU SIGN COMBINING CANDRABINDU ABOVE - TELUGU SIGN COMBINING ANUSVARA ABOVE */
+ { 0x0C3C, 0x0C3C }, /* TELUGU SIGN NUKTA */
+ { 0x0C3E, 0x0C44 }, /* TELUGU VOWEL SIGN AA - TELUGU VOWEL SIGN VOCALIC RR */
+ { 0x0C46, 0x0C48 }, /* TELUGU VOWEL SIGN E - TELUGU VOWEL SIGN AI */
+ { 0x0C4A, 0x0C4D }, /* TELUGU VOWEL SIGN O - TELUGU SIGN VIRAMA */
+ { 0x0C55, 0x0C56 }, /* TELUGU LENGTH MARK - TELUGU AI LENGTH MARK */
+ { 0x0C62, 0x0C63 }, /* TELUGU VOWEL SIGN VOCALIC L - TELUGU VOWEL SIGN VOCALIC LL */
+ { 0x0C81, 0x0C83 }, /* KANNADA SIGN CANDRABINDU - KANNADA SIGN VISARGA */
+ { 0x0CBC, 0x0CBC }, /* KANNADA SIGN NUKTA */
+ { 0x0CBE, 0x0CC4 }, /* KANNADA VOWEL SIGN AA - KANNADA VOWEL SIGN VOCALIC RR */
+ { 0x0CC6, 0x0CC8 }, /* KANNADA VOWEL SIGN E - KANNADA VOWEL SIGN AI */
+ { 0x0CCA, 0x0CCD }, /* KANNADA VOWEL SIGN O - KANNADA SIGN VIRAMA */
+ { 0x0CD5, 0x0CD6 }, /* KANNADA LENGTH MARK - KANNADA AI LENGTH MARK */
+ { 0x0CE2, 0x0CE3 }, /* KANNADA VOWEL SIGN VOCALIC L - KANNADA VOWEL SIGN VOCALIC LL */
+ { 0x0CF3, 0x0CF3 }, /* KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT */
+ { 0x0D00, 0x0D03 }, /* MALAYALAM SIGN COMBINING ANUSVARA ABOVE - MALAYALAM SIGN VISARGA */
+ { 0x0D3B, 0x0D3C }, /* MALAYALAM SIGN VERTICAL BAR VIRAMA - MALAYALAM SIGN CIRCULAR VIRAMA */
+ { 0x0D3E, 0x0D44 }, /* MALAYALAM VOWEL SIGN AA - MALAYALAM VOWEL SIGN VOCALIC RR */
+ { 0x0D46, 0x0D48 }, /* MALAYALAM VOWEL SIGN E - MALAYALAM VOWEL SIGN AI */
+ { 0x0D4A, 0x0D4D }, /* MALAYALAM VOWEL SIGN O - MALAYALAM SIGN VIRAMA */
+ { 0x0D57, 0x0D57 }, /* MALAYALAM AU LENGTH MARK */
+ { 0x0D62, 0x0D63 }, /* MALAYALAM VOWEL SIGN VOCALIC L - MALAYALAM VOWEL SIGN VOCALIC LL */
+ { 0x0D81, 0x0D83 }, /* SINHALA SIGN CANDRABINDU - SINHALA SIGN VISARGAYA */
+ { 0x0DCA, 0x0DCA }, /* SINHALA SIGN AL-LAKUNA */
+ { 0x0DCF, 0x0DD4 }, /* SINHALA VOWEL SIGN AELA-PILLA - SINHALA VOWEL SIGN KETTI PAA-PILLA */
+ { 0x0DD6, 0x0DD6 }, /* SINHALA VOWEL SIGN DIGA PAA-PILLA */
+ { 0x0DD8, 0x0DDF }, /* SINHALA VOWEL SIGN GAETTA-PILLA - SINHALA VOWEL SIGN GAYANUKITTA */
+ { 0x0DF2, 0x0DF3 }, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA - SINHALA VOWEL SIGN DIGA GAYANUKITTA */
+ { 0x0E31, 0x0E31 }, /* THAI CHARACTER MAI HAN-AKAT */
+ { 0x0E34, 0x0E3A }, /* THAI CHARACTER SARA I - THAI CHARACTER PHINTHU */
+ { 0x0E47, 0x0E4E }, /* THAI CHARACTER MAITAIKHU - THAI CHARACTER YAMAKKAN */
+ { 0x0EB1, 0x0EB1 }, /* LAO VOWEL SIGN MAI KAN */
+ { 0x0EB4, 0x0EBC }, /* LAO VOWEL SIGN I - LAO SEMIVOWEL SIGN LO */
+ { 0x0EC8, 0x0ECE }, /* LAO TONE MAI EK - LAO YAMAKKAN */
+ { 0x0F18, 0x0F19 }, /* TIBETAN ASTROLOGICAL SIGN -KHYUD PA - TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS */
+ { 0x0F35, 0x0F35 }, /* TIBETAN MARK NGAS BZUNG NYI ZLA */
+ { 0x0F37, 0x0F37 }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS */
+ { 0x0F39, 0x0F39 }, /* TIBETAN MARK TSA -PHRU */
+ { 0x0F3E, 0x0F3F }, /* TIBETAN SIGN YAR TSHES - TIBETAN SIGN MAR TSHES */
+ { 0x0F71, 0x0F84 }, /* TIBETAN VOWEL SIGN AA - TIBETAN MARK HALANTA */
+ { 0x0F86, 0x0F87 }, /* TIBETAN SIGN LCI RTAGS - TIBETAN SIGN YANG RTAGS */
+ { 0x0F8D, 0x0F97 }, /* TIBETAN SUBJOINED SIGN LCE TSA CAN - TIBETAN SUBJOINED LETTER JA */
+ { 0x0F99, 0x0FBC }, /* TIBETAN SUBJOINED LETTER NYA - TIBETAN SUBJOINED LETTER FIXED-FORM RA */
+ { 0x0FC6, 0x0FC6 }, /* TIBETAN SYMBOL PADMA GDAN */
+ { 0x102B, 0x103E }, /* MYANMAR VOWEL SIGN TALL AA - MYANMAR CONSONANT SIGN MEDIAL HA */
+ { 0x1056, 0x1059 }, /* MYANMAR VOWEL SIGN VOCALIC R - MYANMAR VOWEL SIGN VOCALIC LL */
+ { 0x105E, 0x1060 }, /* MYANMAR CONSONANT SIGN MON MEDIAL NA - MYANMAR CONSONANT SIGN MON MEDIAL LA */
+ { 0x1062, 0x1064 }, /* MYANMAR VOWEL SIGN SGAW KAREN EU - MYANMAR TONE MARK SGAW KAREN KE PHO */
+ { 0x1067, 0x106D }, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU - MYANMAR SIGN WESTERN PWO KAREN TONE-5 */
+ { 0x1071, 0x1074 }, /* MYANMAR VOWEL SIGN GEBA KAREN I - MYANMAR VOWEL SIGN KAYAH EE */
+ { 0x1082, 0x108D }, /* MYANMAR CONSONANT SIGN SHAN MEDIAL WA - MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE */
+ { 0x108F, 0x108F }, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */
+ { 0x109A, 0x109D }, /* MYANMAR SIGN KHAMTI TONE-1 - MYANMAR VOWEL SIGN AITON AI */
+ { 0x135D, 0x135F }, /* ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK - ETHIOPIC COMBINING GEMINATION MARK */
+ { 0x1712, 0x1715 }, /* TAGALOG VOWEL SIGN I - TAGALOG SIGN PAMUDPOD */
+ { 0x1732, 0x1734 }, /* HANUNOO VOWEL SIGN I - HANUNOO SIGN PAMUDPOD */
+ { 0x1752, 0x1753 }, /* BUHID VOWEL SIGN I - BUHID VOWEL SIGN U */
+ { 0x1772, 0x1773 }, /* TAGBANWA VOWEL SIGN I - TAGBANWA VOWEL SIGN U */
+ { 0x17B4, 0x17D3 }, /* KHMER VOWEL INHERENT AQ - KHMER SIGN BATHAMASAT */
+ { 0x17DD, 0x17DD }, /* KHMER SIGN ATTHACAN */
+ { 0x180B, 0x180F }, /* MONGOLIAN FREE VARIATION SELECTOR ONE - MONGOLIAN FREE VARIATION SELECTOR FOUR */
+ { 0x1885, 0x1886 }, /* MONGOLIAN LETTER ALI GALI BALUDA - MONGOLIAN LETTER ALI GALI THREE BALUDA */
+ { 0x18A9, 0x18A9 }, /* MONGOLIAN LETTER ALI GALI DAGALGA */
+ { 0x1920, 0x192B }, /* LIMBU VOWEL SIGN A - LIMBU SUBJOINED LETTER WA */
+ { 0x1930, 0x193B }, /* LIMBU SMALL LETTER KA - LIMBU SIGN SA-I */
+ { 0x1A17, 0x1A1B }, /* BUGINESE VOWEL SIGN I - BUGINESE VOWEL SIGN AE */
+ { 0x1A55, 0x1A5E }, /* TAI THAM CONSONANT SIGN MEDIAL RA - TAI THAM CONSONANT SIGN SA */
+ { 0x1A60, 0x1A7C }, /* TAI THAM SIGN SAKOT - TAI THAM SIGN KHUEN-LUE KARAN */
+ { 0x1A7F, 0x1A7F }, /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */
+ { 0x1AB0, 0x1ACE }, /* COMBINING DOUBLED CIRCUMFLEX ACCENT - COMBINING LATIN SMALL LETTER INSULAR T */
+ { 0x1B00, 0x1B04 }, /* BALINESE SIGN ULU RICEM - BALINESE SIGN BISAH */
+ { 0x1B34, 0x1B44 }, /* BALINESE SIGN REREKAN - BALINESE ADEG ADEG */
+ { 0x1B6B, 0x1B73 }, /* BALINESE MUSICAL SYMBOL COMBINING TEGEH - BALINESE MUSICAL SYMBOL COMBINING GONG */
+ { 0x1B80, 0x1B82 }, /* SUNDANESE SIGN PANYECEK - SUNDANESE SIGN PANGWISAD */
+ { 0x1BA1, 0x1BAD }, /* SUNDANESE CONSONANT SIGN PAMINGKAL - SUNDANESE CONSONANT SIGN PASANGAN WA */
+ { 0x1BE6, 0x1BF3 }, /* BATAK SIGN TOMPI - BATAK PANONGONAN */
+ { 0x1C24, 0x1C37 }, /* LEPCHA SUBJOINED LETTER YA - LEPCHA SIGN NUKTA */
+ { 0x1CD0, 0x1CD2 }, /* VEDIC TONE KARSHANA - VEDIC TONE PRENKHA */
+ { 0x1CD4, 0x1CE8 }, /* VEDIC SIGN YAJURVEDIC MIDLINE SVARITA - VEDIC SIGN VISARGA ANUDATTA WITH TAIL */
+ { 0x1CED, 0x1CED }, /* VEDIC SIGN TIRYAK */
+ { 0x1CF4, 0x1CF4 }, /* VEDIC TONE CANDRA ABOVE */
+ { 0x1CF7, 0x1CF9 }, /* VEDIC SIGN ATIKRAMA - VEDIC TONE DOUBLE RING ABOVE */
+ { 0x1DC0, 0x1DFF }, /* COMBINING DOTTED GRAVE ACCENT - COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */
+ { 0x200B, 0x200F }, /* ZERO WIDTH SPACE - RIGHT-TO-LEFT MARK */
+ { 0x202A, 0x202E }, /* LEFT-TO-RIGHT EMBEDDING - RIGHT-TO-LEFT OVERRIDE */
+ { 0x2060, 0x2064 }, /* WORD JOINER - INVISIBLE PLUS */
+ { 0x2066, 0x206F }, /* LEFT-TO-RIGHT ISOLATE - NOMINAL DIGIT SHAPES */
+ { 0x20D0, 0x20F0 }, /* COMBINING LEFT HARPOON ABOVE - COMBINING ASTERISK ABOVE */
+ { 0x2640, 0x2640 }, /* FEMALE SIGN */
+ { 0x2642, 0x2642 }, /* MALE SIGN */
+ { 0x26A7, 0x26A7 }, /* MALE WITH STROKE AND MALE AND FEMALE SIGN */
+ { 0x2CEF, 0x2CF1 }, /* COPTIC COMBINING NI ABOVE - COPTIC COMBINING SPIRITUS LENIS */
+ { 0x2D7F, 0x2D7F }, /* TIFINAGH CONSONANT JOINER */
+ { 0x2DE0, 0x2DFF }, /* COMBINING CYRILLIC LETTER BE - COMBINING CYRILLIC LETTER IOTIFIED BIG YUS */
+ { 0x302A, 0x302F }, /* IDEOGRAPHIC LEVEL TONE MARK - HANGUL DOUBLE DOT TONE MARK */
+ { 0x3099, 0x309A }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK - COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+ { 0xA66F, 0xA672 }, /* COMBINING CYRILLIC VZMET - COMBINING CYRILLIC THOUSAND MILLIONS SIGN */
+ { 0xA674, 0xA67D }, /* COMBINING CYRILLIC LETTER UKRAINIAN IE - COMBINING CYRILLIC PAYEROK */
+ { 0xA69E, 0xA69F }, /* COMBINING CYRILLIC LETTER EF - COMBINING CYRILLIC LETTER IOTIFIED E */
+ { 0xA6F0, 0xA6F1 }, /* BAMUM COMBINING MARK KOQNDON - BAMUM COMBINING MARK TUKWENTIS */
+ { 0xA802, 0xA802 }, /* SYLOTI NAGRI SIGN DVISVARA */
+ { 0xA806, 0xA806 }, /* SYLOTI NAGRI SIGN HASANTA */
+ { 0xA80B, 0xA80B }, /* SYLOTI NAGRI SIGN ANUSVARA */
+ { 0xA823, 0xA827 }, /* SYLOTI NAGRI VOWEL SIGN A - SYLOTI NAGRI VOWEL SIGN OO */
+ { 0xA82C, 0xA82C }, /* SYLOTI NAGRI SIGN ALTERNATE HASANTA */
+ { 0xA880, 0xA881 }, /* SAURASHTRA SIGN ANUSVARA - SAURASHTRA SIGN VISARGA */
+ { 0xA8B4, 0xA8C5 }, /* SAURASHTRA CONSONANT SIGN HAARU - SAURASHTRA SIGN CANDRABINDU */
+ { 0xA8E0, 0xA8F1 }, /* COMBINING DEVANAGARI DIGIT ZERO - COMBINING DEVANAGARI SIGN AVAGRAHA */
+ { 0xA8FF, 0xA8FF }, /* DEVANAGARI VOWEL SIGN AY */
+ { 0xA926, 0xA92D }, /* KAYAH LI VOWEL UE - KAYAH LI TONE CALYA PLOPHU */
+ { 0xA947, 0xA953 }, /* REJANG VOWEL SIGN I - REJANG VIRAMA */
+ { 0xA980, 0xA983 }, /* JAVANESE SIGN PANYANGGA - JAVANESE SIGN WIGNYAN */
+ { 0xA9B3, 0xA9C0 }, /* JAVANESE SIGN CECAK TELU - JAVANESE PANGKON */
+ { 0xA9E5, 0xA9E5 }, /* MYANMAR SIGN SHAN SAW */
+ { 0xAA29, 0xAA36 }, /* CHAM VOWEL SIGN AA - CHAM CONSONANT SIGN WA */
+ { 0xAA43, 0xAA43 }, /* CHAM CONSONANT SIGN FINAL NG */
+ { 0xAA4C, 0xAA4D }, /* CHAM CONSONANT SIGN FINAL M - CHAM CONSONANT SIGN FINAL H */
+ { 0xAA7B, 0xAA7D }, /* MYANMAR SIGN PAO KAREN TONE - MYANMAR SIGN TAI LAING TONE-5 */
+ { 0xAAB0, 0xAAB0 }, /* TAI VIET MAI KANG */
+ { 0xAAB2, 0xAAB4 }, /* TAI VIET VOWEL I - TAI VIET VOWEL U */
+ { 0xAAB7, 0xAAB8 }, /* TAI VIET MAI KHIT - TAI VIET VOWEL IA */
+ { 0xAABE, 0xAABF }, /* TAI VIET VOWEL AM - TAI VIET TONE MAI EK */
+ { 0xAAC1, 0xAAC1 }, /* TAI VIET TONE MAI THO */
+ { 0xAAEB, 0xAAEF }, /* MEETEI MAYEK VOWEL SIGN II - MEETEI MAYEK VOWEL SIGN AAU */
+ { 0xAAF5, 0xAAF6 }, /* MEETEI MAYEK VOWEL SIGN VISARGA - MEETEI MAYEK VIRAMA */
+ { 0xABE3, 0xABEA }, /* MEETEI MAYEK VOWEL SIGN ONAP - MEETEI MAYEK VOWEL SIGN NUNG */
+ { 0xABEC, 0xABED }, /* MEETEI MAYEK LUM IYEK - MEETEI MAYEK APUN IYEK */
+ { 0xFB1E, 0xFB1E }, /* HEBREW POINT JUDEO-SPANISH VARIKA */
+ { 0xFE00, 0xFE0F }, /* VARIATION SELECTOR-1 - VARIATION SELECTOR-16 */
+ { 0xFE20, 0xFE2F }, /* COMBINING LIGATURE LEFT HALF - COMBINING CYRILLIC TITLO RIGHT HALF */
+ { 0xFEFF, 0xFEFF }, /* ZERO WIDTH NO-BREAK SPACE */
+ { 0xFFF9, 0xFFFB }, /* INTERLINEAR ANNOTATION ANCHOR - INTERLINEAR ANNOTATION TERMINATOR */
+};
+
+/* Zero-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = {
+ { 0x101FD, 0x101FD }, /* PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE */
+ { 0x102E0, 0x102E0 }, /* COPTIC EPACT THOUSANDS MARK */
+ { 0x10376, 0x1037A }, /* COMBINING OLD PERMIC LETTER AN - COMBINING OLD PERMIC LETTER SII */
+ { 0x10A01, 0x10A03 }, /* KHAROSHTHI VOWEL SIGN I - KHAROSHTHI VOWEL SIGN VOCALIC R */
+ { 0x10A05, 0x10A06 }, /* KHAROSHTHI VOWEL SIGN E - KHAROSHTHI VOWEL SIGN O */
+ { 0x10A0C, 0x10A0F }, /* KHAROSHTHI VOWEL LENGTH MARK - KHAROSHTHI SIGN VISARGA */
+ { 0x10A38, 0x10A3A }, /* KHAROSHTHI SIGN BAR ABOVE - KHAROSHTHI SIGN DOT BELOW */
+ { 0x10A3F, 0x10A3F }, /* KHAROSHTHI VIRAMA */
+ { 0x10AE5, 0x10AE6 }, /* MANICHAEAN ABBREVIATION MARK ABOVE - MANICHAEAN ABBREVIATION MARK BELOW */
+ { 0x10D24, 0x10D27 }, /* HANIFI ROHINGYA SIGN HARBAHAY - HANIFI ROHINGYA SIGN TASSI */
+ { 0x10D69, 0x10D6D }, /* GARAY VOWEL SIGN E - GARAY CONSONANT NASALIZATION MARK */
+ { 0x10EAB, 0x10EAC }, /* YEZIDI COMBINING HAMZA MARK - YEZIDI COMBINING MADDA MARK */
+ { 0x10EFC, 0x10EFF }, /* ARABIC COMBINING ALEF OVERLAY - ARABIC SMALL LOW WORD MADDA */
+ { 0x10F46, 0x10F50 }, /* SOGDIAN COMBINING DOT BELOW - SOGDIAN COMBINING STROKE BELOW */
+ { 0x10F82, 0x10F85 }, /* OLD UYGHUR COMBINING DOT ABOVE - OLD UYGHUR COMBINING TWO DOTS BELOW */
+ { 0x11000, 0x11002 }, /* BRAHMI SIGN CANDRABINDU - BRAHMI SIGN VISARGA */
+ { 0x11038, 0x11046 }, /* BRAHMI VOWEL SIGN AA - BRAHMI VIRAMA */
+ { 0x11070, 0x11070 }, /* BRAHMI SIGN OLD TAMIL VIRAMA */
+ { 0x11073, 0x11074 }, /* BRAHMI VOWEL SIGN OLD TAMIL SHORT E - BRAHMI VOWEL SIGN OLD TAMIL SHORT O */
+ { 0x1107F, 0x11082 }, /* BRAHMI NUMBER JOINER - KAITHI SIGN VISARGA */
+ { 0x110B0, 0x110BA }, /* KAITHI VOWEL SIGN AA - KAITHI SIGN NUKTA */
+ { 0x110BD, 0x110BD }, /* KAITHI NUMBER SIGN */
+ { 0x110C2, 0x110C2 }, /* KAITHI VOWEL SIGN VOCALIC R */
+ { 0x110CD, 0x110CD }, /* KAITHI NUMBER SIGN ABOVE */
+ { 0x11100, 0x11102 }, /* CHAKMA SIGN CANDRABINDU - CHAKMA SIGN VISARGA */
+ { 0x11127, 0x11134 }, /* CHAKMA VOWEL SIGN A - CHAKMA MAAYYAA */
+ { 0x11145, 0x11146 }, /* CHAKMA VOWEL SIGN AA - CHAKMA VOWEL SIGN EI */
+ { 0x11173, 0x11173 }, /* MAHAJANI SIGN NUKTA */
+ { 0x11180, 0x11182 }, /* SHARADA SIGN CANDRABINDU - SHARADA SIGN VISARGA */
+ { 0x111B3, 0x111C0 }, /* SHARADA VOWEL SIGN AA - SHARADA SIGN VIRAMA */
+ { 0x111C9, 0x111CC }, /* SHARADA SANDHI MARK - SHARADA EXTRA SHORT VOWEL MARK */
+ { 0x111CE, 0x111CF }, /* SHARADA VOWEL SIGN PRISHTHAMATRA E - SHARADA SIGN INVERTED CANDRABINDU */
+ { 0x1122C, 0x11237 }, /* KHOJKI VOWEL SIGN AA - KHOJKI SIGN SHADDA */
+ { 0x1123E, 0x1123E }, /* KHOJKI SIGN SUKUN */
+ { 0x11241, 0x11241 }, /* KHOJKI VOWEL SIGN VOCALIC R */
+ { 0x112DF, 0x112EA }, /* KHUDAWADI SIGN ANUSVARA - KHUDAWADI SIGN VIRAMA */
+ { 0x11300, 0x11303 }, /* GRANTHA SIGN COMBINING ANUSVARA ABOVE - GRANTHA SIGN VISARGA */
+ { 0x1133B, 0x1133C }, /* COMBINING BINDU BELOW - GRANTHA SIGN NUKTA */
+ { 0x1133E, 0x11344 }, /* GRANTHA VOWEL SIGN AA - GRANTHA VOWEL SIGN VOCALIC RR */
+ { 0x11347, 0x11348 }, /* GRANTHA VOWEL SIGN EE - GRANTHA VOWEL SIGN AI */
+ { 0x1134B, 0x1134D }, /* GRANTHA VOWEL SIGN OO - GRANTHA SIGN VIRAMA */
+ { 0x11357, 0x11357 }, /* GRANTHA AU LENGTH MARK */
+ { 0x11362, 0x11363 }, /* GRANTHA VOWEL SIGN VOCALIC L - GRANTHA VOWEL SIGN VOCALIC LL */
+ { 0x11366, 0x1136C }, /* COMBINING GRANTHA DIGIT ZERO - COMBINING GRANTHA DIGIT SIX */
+ { 0x11370, 0x11374 }, /* COMBINING GRANTHA LETTER A - COMBINING GRANTHA LETTER PA */
+ { 0x113B8, 0x113C0 }, /* TULU-TIGALARI VOWEL SIGN AA - TULU-TIGALARI VOWEL SIGN VOCALIC LL */
+ { 0x113C2, 0x113C2 }, /* TULU-TIGALARI VOWEL SIGN EE */
+ { 0x113C5, 0x113C5 }, /* TULU-TIGALARI VOWEL SIGN AI */
+ { 0x113C7, 0x113CA }, /* TULU-TIGALARI VOWEL SIGN OO - TULU-TIGALARI SIGN CANDRA ANUNASIKA */
+ { 0x113CC, 0x113D0 }, /* TULU-TIGALARI SIGN ANUSVARA - TULU-TIGALARI CONJOINER */
+ { 0x113D2, 0x113D2 }, /* TULU-TIGALARI GEMINATION MARK */
+ { 0x113E1, 0x113E2 }, /* TULU-TIGALARI VEDIC TONE SVARITA - TULU-TIGALARI VEDIC TONE ANUDATTA */
+ { 0x11435, 0x11446 }, /* NEWA VOWEL SIGN AA - NEWA SIGN NUKTA */
+ { 0x1145E, 0x1145E }, /* NEWA SANDHI MARK */
+ { 0x114B0, 0x114C3 }, /* TIRHUTA VOWEL SIGN AA - TIRHUTA SIGN NUKTA */
+ { 0x115AF, 0x115B5 }, /* SIDDHAM VOWEL SIGN AA - SIDDHAM VOWEL SIGN VOCALIC RR */
+ { 0x115B8, 0x115C0 }, /* SIDDHAM VOWEL SIGN E - SIDDHAM SIGN NUKTA */
+ { 0x115DC, 0x115DD }, /* SIDDHAM VOWEL SIGN ALTERNATE U - SIDDHAM VOWEL SIGN ALTERNATE UU */
+ { 0x11630, 0x11640 }, /* MODI VOWEL SIGN AA - MODI SIGN ARDHACANDRA */
+ { 0x116AB, 0x116B7 }, /* TAKRI SIGN ANUSVARA - TAKRI SIGN NUKTA */
+ { 0x1171D, 0x1172B }, /* AHOM CONSONANT SIGN MEDIAL LA - AHOM SIGN KILLER */
+ { 0x1182C, 0x1183A }, /* DOGRA VOWEL SIGN AA - DOGRA SIGN NUKTA */
+ { 0x11930, 0x11935 }, /* DIVES AKURU VOWEL SIGN AA - DIVES AKURU VOWEL SIGN E */
+ { 0x11937, 0x11938 }, /* DIVES AKURU VOWEL SIGN AI - DIVES AKURU VOWEL SIGN O */
+ { 0x1193B, 0x1193E }, /* DIVES AKURU SIGN ANUSVARA - DIVES AKURU VIRAMA */
+ { 0x11940, 0x11940 }, /* DIVES AKURU MEDIAL YA */
+ { 0x11942, 0x11943 }, /* DIVES AKURU MEDIAL RA - DIVES AKURU SIGN NUKTA */
+ { 0x119D1, 0x119D7 }, /* NANDINAGARI VOWEL SIGN AA - NANDINAGARI VOWEL SIGN VOCALIC RR */
+ { 0x119DA, 0x119E0 }, /* NANDINAGARI VOWEL SIGN E - NANDINAGARI SIGN VIRAMA */
+ { 0x119E4, 0x119E4 }, /* NANDINAGARI VOWEL SIGN PRISHTHAMATRA E */
+ { 0x11A01, 0x11A0A }, /* ZANABAZAR SQUARE VOWEL SIGN I - ZANABAZAR SQUARE VOWEL LENGTH MARK */
+ { 0x11A33, 0x11A39 }, /* ZANABAZAR SQUARE FINAL CONSONANT MARK - ZANABAZAR SQUARE SIGN VISARGA */
+ { 0x11A3B, 0x11A3E }, /* ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA - ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA */
+ { 0x11A47, 0x11A47 }, /* ZANABAZAR SQUARE SUBJOINER */
+ { 0x11A51, 0x11A5B }, /* SOYOMBO VOWEL SIGN I - SOYOMBO VOWEL LENGTH MARK */
+ { 0x11A8A, 0x11A99 }, /* SOYOMBO FINAL CONSONANT SIGN G - SOYOMBO SUBJOINER */
+ { 0x11C2F, 0x11C36 }, /* BHAIKSUKI VOWEL SIGN AA - BHAIKSUKI VOWEL SIGN VOCALIC L */
+ { 0x11C38, 0x11C3F }, /* BHAIKSUKI VOWEL SIGN E - BHAIKSUKI SIGN VIRAMA */
+ { 0x11C92, 0x11CA7 }, /* MARCHEN SUBJOINED LETTER KA - MARCHEN SUBJOINED LETTER ZA */
+ { 0x11CA9, 0x11CB6 }, /* MARCHEN SUBJOINED LETTER YA - MARCHEN SIGN CANDRABINDU */
+ { 0x11D31, 0x11D36 }, /* MASARAM GONDI VOWEL SIGN AA - MASARAM GONDI VOWEL SIGN VOCALIC R */
+ { 0x11D3A, 0x11D3A }, /* MASARAM GONDI VOWEL SIGN E */
+ { 0x11D3C, 0x11D3D }, /* MASARAM GONDI VOWEL SIGN AI - MASARAM GONDI VOWEL SIGN O */
+ { 0x11D3F, 0x11D45 }, /* MASARAM GONDI VOWEL SIGN AU - MASARAM GONDI VIRAMA */
+ { 0x11D47, 0x11D47 }, /* MASARAM GONDI RA-KARA */
+ { 0x11D8A, 0x11D8E }, /* GUNJALA GONDI VOWEL SIGN AA - GUNJALA GONDI VOWEL SIGN UU */
+ { 0x11D90, 0x11D91 }, /* GUNJALA GONDI VOWEL SIGN EE - GUNJALA GONDI VOWEL SIGN AI */
+ { 0x11D93, 0x11D97 }, /* GUNJALA GONDI VOWEL SIGN OO - GUNJALA GONDI VIRAMA */
+ { 0x11EF3, 0x11EF6 }, /* MAKASAR VOWEL SIGN I - MAKASAR VOWEL SIGN O */
+ { 0x11F00, 0x11F01 }, /* KAWI SIGN CANDRABINDU - KAWI SIGN ANUSVARA */
+ { 0x11F03, 0x11F03 }, /* KAWI SIGN VISARGA */
+ { 0x11F34, 0x11F3A }, /* KAWI VOWEL SIGN AA - KAWI VOWEL SIGN VOCALIC R */
+ { 0x11F3E, 0x11F42 }, /* KAWI VOWEL SIGN E - KAWI CONJOINER */
+ { 0x11F5A, 0x11F5A }, /* KAWI SIGN NUKTA */
+ { 0x13430, 0x13440 }, /* EGYPTIAN HIEROGLYPH VERTICAL JOINER - EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY */
+ { 0x13447, 0x13455 }, /* EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START - EGYPTIAN HIEROGLYPH MODIFIER DAMAGED */
+ { 0x1611E, 0x1612F }, /* GURUNG KHEMA VOWEL SIGN AA - GURUNG KHEMA SIGN THOLHOMA */
+ { 0x16AF0, 0x16AF4 }, /* BASSA VAH COMBINING HIGH TONE - BASSA VAH COMBINING HIGH-LOW TONE */
+ { 0x16B30, 0x16B36 }, /* PAHAWH HMONG MARK CIM TUB - PAHAWH HMONG MARK CIM TAUM */
+ { 0x16F4F, 0x16F4F }, /* MIAO SIGN CONSONANT MODIFIER BAR */
+ { 0x16F51, 0x16F87 }, /* MIAO SIGN ASPIRATION - MIAO VOWEL SIGN UI */
+ { 0x16F8F, 0x16F92 }, /* MIAO TONE RIGHT - MIAO TONE BELOW */
+ { 0x16FE4, 0x16FE4 }, /* KHITAN SMALL SCRIPT FILLER */
+ { 0x16FF0, 0x16FF1 }, /* VIETNAMESE ALTERNATE READING MARK CA - VIETNAMESE ALTERNATE READING MARK NHAY */
+ { 0x1BC9D, 0x1BC9E }, /* DUPLOYAN THICK LETTER SELECTOR - DUPLOYAN DOUBLE MARK */
+ { 0x1BCA0, 0x1BCA3 }, /* SHORTHAND FORMAT LETTER OVERLAP - SHORTHAND FORMAT UP STEP */
+ { 0x1CF00, 0x1CF2D }, /* ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT - ZNAMENNY COMBINING MARK KRYZH ON LEFT */
+ { 0x1CF30, 0x1CF46 }, /* ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO - ZNAMENNY PRIZNAK MODIFIER ROG */
+ { 0x1D165, 0x1D169 }, /* MUSICAL SYMBOL COMBINING STEM - MUSICAL SYMBOL COMBINING TREMOLO-3 */
+ { 0x1D16D, 0x1D182 }, /* MUSICAL SYMBOL COMBINING AUGMENTATION DOT - MUSICAL SYMBOL COMBINING LOURE */
+ { 0x1D185, 0x1D18B }, /* MUSICAL SYMBOL COMBINING DOIT - MUSICAL SYMBOL COMBINING TRIPLE TONGUE */
+ { 0x1D1AA, 0x1D1AD }, /* MUSICAL SYMBOL COMBINING DOWN BOW - MUSICAL SYMBOL COMBINING SNAP PIZZICATO */
+ { 0x1D242, 0x1D244 }, /* COMBINING GREEK MUSICAL TRISEME - COMBINING GREEK MUSICAL PENTASEME */
+ { 0x1DA00, 0x1DA36 }, /* SIGNWRITING HEAD RIM - SIGNWRITING AIR SUCKING IN */
+ { 0x1DA3B, 0x1DA6C }, /* SIGNWRITING MOUTH CLOSED NEUTRAL - SIGNWRITING EXCITEMENT */
+ { 0x1DA75, 0x1DA75 }, /* SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS */
+ { 0x1DA84, 0x1DA84 }, /* SIGNWRITING LOCATION HEAD NECK */
+ { 0x1DA9B, 0x1DA9F }, /* SIGNWRITING FILL MODIFIER-2 - SIGNWRITING FILL MODIFIER-6 */
+ { 0x1DAA1, 0x1DAAF }, /* SIGNWRITING ROTATION MODIFIER-2 - SIGNWRITING ROTATION MODIFIER-16 */
+ { 0x1E000, 0x1E006 }, /* COMBINING GLAGOLITIC LETTER AZU - COMBINING GLAGOLITIC LETTER ZHIVETE */
+ { 0x1E008, 0x1E018 }, /* COMBINING GLAGOLITIC LETTER ZEMLJA - COMBINING GLAGOLITIC LETTER HERU */
+ { 0x1E01B, 0x1E021 }, /* COMBINING GLAGOLITIC LETTER SHTA - COMBINING GLAGOLITIC LETTER YATI */
+ { 0x1E023, 0x1E024 }, /* COMBINING GLAGOLITIC LETTER YU - COMBINING GLAGOLITIC LETTER SMALL YUS */
+ { 0x1E026, 0x1E02A }, /* COMBINING GLAGOLITIC LETTER YO - COMBINING GLAGOLITIC LETTER FITA */
+ { 0x1E08F, 0x1E08F }, /* COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { 0x1E130, 0x1E136 }, /* NYIAKENG PUACHUE HMONG TONE-B - NYIAKENG PUACHUE HMONG TONE-D */
+ { 0x1E2AE, 0x1E2AE }, /* TOTO SIGN RISING TONE */
+ { 0x1E2EC, 0x1E2EF }, /* WANCHO TONE TUP - WANCHO TONE KOINI */
+ { 0x1E4EC, 0x1E4EF }, /* NAG MUNDARI SIGN MUHOR - NAG MUNDARI SIGN SUTUH */
+ { 0x1E5EE, 0x1E5EF }, /* OL ONAL SIGN MU - OL ONAL SIGN IKIR */
+ { 0x1E8D0, 0x1E8D6 }, /* MENDE KIKAKUI COMBINING NUMBER TEENS - MENDE KIKAKUI COMBINING NUMBER MILLIONS */
+ { 0x1E944, 0x1E94A }, /* ADLAM ALIF LENGTHENER - ADLAM NUKTA */
+ { 0x1F3FB, 0x1F3FF }, /* EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EMOJI MODIFIER FITZPATRICK TYPE-6 */
+ { 0x1F9B0, 0x1F9B3 }, /* EMOJI COMPONENT RED HAIR - EMOJI COMPONENT WHITE HAIR */
+ { 0xE0001, 0xE0001 }, /* LANGUAGE TAG */
+ { 0xE0020, 0xE007F }, /* TAG SPACE - CANCEL TAG */
+ { 0xE0100, 0xE01EF }, /* VARIATION SELECTOR-17 - VARIATION SELECTOR-256 */
+};
+
+/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = {
+ { 0x1100, 0x115F }, /* HANGUL CHOSEONG KIYEOK - HANGUL CHOSEONG FILLER */
+ { 0x231A, 0x231B }, /* WATCH - HOURGLASS */
+ { 0x2329, 0x232A }, /* LEFT-POINTING ANGLE BRACKET - RIGHT-POINTING ANGLE BRACKET */
+ { 0x23E9, 0x23EC }, /* BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK DOWN-POINTING DOUBLE TRIANGLE */
+ { 0x23F0, 0x23F0 }, /* ALARM CLOCK */
+ { 0x23F3, 0x23F3 }, /* HOURGLASS WITH FLOWING SAND */
+ { 0x25FD, 0x25FE }, /* WHITE MEDIUM SMALL SQUARE - BLACK MEDIUM SMALL SQUARE */
+ { 0x2614, 0x2615 }, /* UMBRELLA WITH RAIN DROPS - HOT BEVERAGE */
+ { 0x2630, 0x2637 }, /* TRIGRAM FOR HEAVEN - TRIGRAM FOR EARTH */
+ { 0x2648, 0x2653 }, /* ARIES - PISCES */
+ { 0x267F, 0x267F }, /* WHEELCHAIR SYMBOL */
+ { 0x268A, 0x268F }, /* MONOGRAM FOR YANG - DIGRAM FOR GREATER YIN */
+ { 0x2693, 0x2693 }, /* ANCHOR */
+ { 0x26A1, 0x26A1 }, /* HIGH VOLTAGE SIGN */
+ { 0x26AA, 0x26AB }, /* MEDIUM WHITE CIRCLE - MEDIUM BLACK CIRCLE */
+ { 0x26BD, 0x26BE }, /* SOCCER BALL - BASEBALL */
+ { 0x26C4, 0x26C5 }, /* SNOWMAN WITHOUT SNOW - SUN BEHIND CLOUD */
+ { 0x26CE, 0x26CE }, /* OPHIUCHUS */
+ { 0x26D4, 0x26D4 }, /* NO ENTRY */
+ { 0x26EA, 0x26EA }, /* CHURCH */
+ { 0x26F2, 0x26F3 }, /* FOUNTAIN - FLAG IN HOLE */
+ { 0x26F5, 0x26F5 }, /* SAILBOAT */
+ { 0x26FA, 0x26FA }, /* TENT */
+ { 0x26FD, 0x26FD }, /* FUEL PUMP */
+ { 0x2705, 0x2705 }, /* WHITE HEAVY CHECK MARK */
+ { 0x270A, 0x270B }, /* RAISED FIST - RAISED HAND */
+ { 0x2728, 0x2728 }, /* SPARKLES */
+ { 0x274C, 0x274C }, /* CROSS MARK */
+ { 0x274E, 0x274E }, /* NEGATIVE SQUARED CROSS MARK */
+ { 0x2753, 0x2755 }, /* BLACK QUESTION MARK ORNAMENT - WHITE EXCLAMATION MARK ORNAMENT */
+ { 0x2757, 0x2757 }, /* HEAVY EXCLAMATION MARK SYMBOL */
+ { 0x2795, 0x2797 }, /* HEAVY PLUS SIGN - HEAVY DIVISION SIGN */
+ { 0x27B0, 0x27B0 }, /* CURLY LOOP */
+ { 0x27BF, 0x27BF }, /* DOUBLE CURLY LOOP */
+ { 0x2B1B, 0x2B1C }, /* BLACK LARGE SQUARE - WHITE LARGE SQUARE */
+ { 0x2B50, 0x2B50 }, /* WHITE MEDIUM STAR */
+ { 0x2B55, 0x2B55 }, /* HEAVY LARGE CIRCLE */
+ { 0x2E80, 0x2E99 }, /* CJK RADICAL REPEAT - CJK RADICAL RAP */
+ { 0x2E9B, 0x2EF3 }, /* CJK RADICAL CHOKE - CJK RADICAL C-SIMPLIFIED TURTLE */
+ { 0x2F00, 0x2FD5 }, /* KANGXI RADICAL ONE - KANGXI RADICAL FLUTE */
+ { 0x2FF0, 0x3029 }, /* IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT - HANGZHOU NUMERAL NINE */
+ { 0x3030, 0x303E }, /* WAVY DASH - IDEOGRAPHIC VARIATION INDICATOR */
+ { 0x3041, 0x3096 }, /* HIRAGANA LETTER SMALL A - HIRAGANA LETTER SMALL KE */
+ { 0x309B, 0x30FF }, /* KATAKANA-HIRAGANA VOICED SOUND MARK - KATAKANA DIGRAPH KOTO */
+ { 0x3105, 0x312F }, /* BOPOMOFO LETTER B - BOPOMOFO LETTER NN */
+ { 0x3131, 0x318E }, /* HANGUL LETTER KIYEOK - HANGUL LETTER ARAEAE */
+ { 0x3190, 0x31E5 }, /* IDEOGRAPHIC ANNOTATION LINKING MARK - CJK STROKE SZP */
+ { 0x31EF, 0x321E }, /* IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION - PARENTHESIZED KOREAN CHARACTER O HU */
+ { 0x3220, 0x3247 }, /* PARENTHESIZED IDEOGRAPH ONE - CIRCLED IDEOGRAPH KOTO */
+ { 0x3250, 0xA48C }, /* PARTNERSHIP SIGN - YI SYLLABLE YYR */
+ { 0xA490, 0xA4C6 }, /* YI RADICAL QOT - YI RADICAL KE */
+ { 0xA960, 0xA97C }, /* HANGUL CHOSEONG TIKEUT-MIEUM - HANGUL CHOSEONG SSANGYEORINHIEUH */
+ { 0xAC00, 0xD7A3 }, /* HANGUL SYLLABLE GA - HANGUL SYLLABLE HIH */
+ { 0xF900, 0xFAFF }, /* U+F900 - U+FAFF */
+ { 0xFE10, 0xFE19 }, /* PRESENTATION FORM FOR VERTICAL COMMA - PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */
+ { 0xFE30, 0xFE52 }, /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER - SMALL FULL STOP */
+ { 0xFE54, 0xFE66 }, /* SMALL SEMICOLON - SMALL EQUALS SIGN */
+ { 0xFE68, 0xFE6B }, /* SMALL REVERSE SOLIDUS - SMALL COMMERCIAL AT */
+ { 0xFF01, 0xFF60 }, /* FULLWIDTH EXCLAMATION MARK - FULLWIDTH RIGHT WHITE PARENTHESIS */
+ { 0xFFE0, 0xFFE6 }, /* FULLWIDTH CENT SIGN - FULLWIDTH WON SIGN */
+};
+
+/* Double-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = {
+ { 0x16FE0, 0x16FE3 }, /* TANGUT ITERATION MARK - OLD CHINESE ITERATION MARK */
+ { 0x17000, 0x187F7 }, /* U+17000 - U+187F7 */
+ { 0x18800, 0x18CD5 }, /* TANGUT COMPONENT-001 - KHITAN SMALL SCRIPT CHARACTER-18CD5 */
+ { 0x18CFF, 0x18D08 }, /* U+18CFF - U+18D08 */
+ { 0x1AFF0, 0x1AFF3 }, /* KATAKANA LETTER MINNAN TONE-2 - KATAKANA LETTER MINNAN TONE-5 */
+ { 0x1AFF5, 0x1AFFB }, /* KATAKANA LETTER MINNAN TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-5 */
+ { 0x1AFFD, 0x1AFFE }, /* KATAKANA LETTER MINNAN NASALIZED TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-8 */
+ { 0x1B000, 0x1B122 }, /* KATAKANA LETTER ARCHAIC E - KATAKANA LETTER ARCHAIC WU */
+ { 0x1B132, 0x1B132 }, /* HIRAGANA LETTER SMALL KO */
+ { 0x1B150, 0x1B152 }, /* HIRAGANA LETTER SMALL WI - HIRAGANA LETTER SMALL WO */
+ { 0x1B155, 0x1B155 }, /* KATAKANA LETTER SMALL KO */
+ { 0x1B164, 0x1B167 }, /* KATAKANA LETTER SMALL WI - KATAKANA LETTER SMALL N */
+ { 0x1B170, 0x1B2FB }, /* NUSHU CHARACTER-1B170 - NUSHU CHARACTER-1B2FB */
+ { 0x1D300, 0x1D356 }, /* MONOGRAM FOR EARTH - TETRAGRAM FOR FOSTERING */
+ { 0x1D360, 0x1D376 }, /* COUNTING ROD UNIT DIGIT ONE - IDEOGRAPHIC TALLY MARK FIVE */
+ { 0x1F000, 0x1F02F }, /* U+1F000 - U+1F02F */
+ { 0x1F0A0, 0x1F0FF }, /* U+1F0A0 - U+1F0FF */
+ { 0x1F18E, 0x1F18E }, /* NEGATIVE SQUARED AB */
+ { 0x1F191, 0x1F19A }, /* SQUARED CL - SQUARED VS */
+ { 0x1F200, 0x1F202 }, /* SQUARE HIRAGANA HOKA - SQUARED KATAKANA SA */
+ { 0x1F210, 0x1F23B }, /* SQUARED CJK UNIFIED IDEOGRAPH-624B - SQUARED CJK UNIFIED IDEOGRAPH-914D */
+ { 0x1F240, 0x1F248 }, /* TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C - TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 */
+ { 0x1F250, 0x1F251 }, /* CIRCLED IDEOGRAPH ADVANTAGE - CIRCLED IDEOGRAPH ACCEPT */
+ { 0x1F260, 0x1F265 }, /* ROUNDED SYMBOL FOR FU - ROUNDED SYMBOL FOR CAI */
+ { 0x1F300, 0x1F3FA }, /* CYCLONE - AMPHORA */
+ { 0x1F400, 0x1F64F }, /* RAT - PERSON WITH FOLDED HANDS */
+ { 0x1F680, 0x1F9AF }, /* ROCKET - PROBING CANE */
+ { 0x1F9B4, 0x1FAFF }, /* U+1F9B4 - U+1FAFF */
+ { 0x20000, 0x2FFFD }, /* U+20000 - U+2FFFD */
+ { 0x30000, 0x3FFFD }, /* U+30000 - U+3FFFD */
+};
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f5642b3038e4..ed39d9cb4432 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -104,7 +104,6 @@
#include <linux/uaccess.h>
#include <linux/kdb.h>
#include <linux/ctype.h>
-#include <linux/bsearch.h>
#include <linux/gcd.h>
#define MAX_NR_CON_DRIVER 16
@@ -444,6 +443,15 @@ static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top,
}
}
+static u32 vc_uniscr_getc(struct vc_data *vc, int relative_pos)
+{
+ int pos = vc->state.x + vc->vc_need_wrap + relative_pos;
+
+ if (vc->vc_uni_lines && in_range(pos, 0, vc->vc_cols))
+ return vc->vc_uni_lines[vc->state.y][pos];
+ return 0;
+}
+
static void vc_uniscr_copy_area(u32 **dst_lines,
unsigned int dst_cols,
unsigned int dst_rows,
@@ -1862,6 +1870,14 @@ int mouse_reporting(void)
return vc_cons[fg_console].d->vc_report_mouse;
}
+/* invoked via ioctl(TIOCLINUX) */
+static int get_bracketed_paste(struct tty_struct *tty)
+{
+ struct vc_data *vc = tty->driver_data;
+
+ return vc->vc_bracketed_paste;
+}
+
enum {
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1872,6 +1888,7 @@ enum {
CSI_DEC_hl_MOUSE_X10 = 9,
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
CSI_DEC_hl_MOUSE_VT200 = 1000,
+ CSI_DEC_hl_BRACKETED_PASTE = 2004,
};
/* console_lock is held */
@@ -1924,6 +1941,9 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
case CSI_DEC_hl_MOUSE_VT200:
vc->vc_report_mouse = on_off ? 2 : 0;
break;
+ case CSI_DEC_hl_BRACKETED_PASTE:
+ vc->vc_bracketed_paste = on_off;
+ break;
}
}
@@ -2149,6 +2169,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->state.charset = 0;
vc->vc_need_wrap = 0;
vc->vc_report_mouse = 0;
+ vc->vc_bracketed_paste = 0;
vc->vc_utf = default_utf8;
vc->vc_utf_count = 0;
@@ -2712,43 +2733,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c)
}
}
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
- uint32_t first;
- uint32_t last;
-};
-
-static int ucs_cmp(const void *key, const void *elt)
-{
- uint32_t ucs = *(uint32_t *)key;
- struct interval e = *(struct interval *) elt;
-
- if (ucs > e.last)
- return 1;
- else if (ucs < e.first)
- return -1;
- return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
- static const struct interval double_width[] = {
- { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
- { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
- { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
- { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
- };
- if (ucs < double_width[0].first ||
- ucs > double_width[ARRAY_SIZE(double_width) - 1].last)
- return 0;
-
- return bsearch(&ucs, double_width, ARRAY_SIZE(double_width),
- sizeof(struct interval), ucs_cmp) != NULL;
-}
-
struct vc_draw_region {
unsigned long from, to;
int x;
@@ -2817,7 +2801,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
if ((c & 0xc0) == 0x80) {
/* Unexpected continuation byte? */
if (!vc->vc_utf_count)
- return 0xfffd;
+ goto bad_sequence;
vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
vc->vc_npar++;
@@ -2829,17 +2813,17 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
/* Reject overlong sequences */
if (c <= utf8_length_changes[vc->vc_npar - 1] ||
c > utf8_length_changes[vc->vc_npar])
- return 0xfffd;
+ goto bad_sequence;
return vc_sanitize_unicode(c);
}
/* Single ASCII byte or first byte of a sequence received */
if (vc->vc_utf_count) {
- /* Continuation byte expected */
+ /* A continuation byte was expected */
*rescan = true;
vc->vc_utf_count = 0;
- return 0xfffd;
+ goto bad_sequence;
}
/* Nothing to do if an ASCII byte was received */
@@ -2858,11 +2842,14 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
vc->vc_utf_count = 3;
vc->vc_utf_char = (c & 0x07);
} else {
- return 0xfffd;
+ goto bad_sequence;
}
need_more_bytes:
return -1;
+
+bad_sequence:
+ return 0xfffd;
}
static int vc_translate(struct vc_data *vc, int *c, bool *rescan)
@@ -2940,54 +2927,143 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
return false;
}
+static void vc_con_rewind(struct vc_data *vc)
+{
+ if (vc->state.x && !vc->vc_need_wrap) {
+ vc->vc_pos -= 2;
+ vc->state.x--;
+ }
+ vc->vc_need_wrap = 0;
+}
+
+#define UCS_ZWS 0x200b /* Zero Width Space */
+#define UCS_VS16 0xfe0f /* Variation Selector 16 */
+#define UCS_REPLACEMENT 0xfffd /* Replacement Character */
+
+static int vc_process_ucs(struct vc_data *vc, int *c, int *tc)
+{
+ u32 prev_c, curr_c = *c;
+
+ if (ucs_is_double_width(curr_c)) {
+ /*
+ * The Unicode screen memory is allocated only when
+ * required. This is one such case as we need to remember
+ * which displayed characters are double-width.
+ */
+ vc_uniscr_check(vc);
+ return 2;
+ }
+
+ if (!ucs_is_zero_width(curr_c))
+ return 1;
+
+ /* From here curr_c is known to be zero-width. */
+
+ if (ucs_is_double_width(vc_uniscr_getc(vc, -2))) {
+ /*
+ * Let's merge this zero-width code point with the preceding
+ * double-width code point by replacing the existing
+ * zero-width space padding. To do so we rewind one column
+ * and pretend this has a width of 1.
+ * We give the legacy display the same initial space padding.
+ */
+ vc_con_rewind(vc);
+ *tc = ' ';
+ return 1;
+ }
+
+ /* From here the preceding character, if any, must be single-width. */
+ prev_c = vc_uniscr_getc(vc, -1);
+
+ if (curr_c == UCS_VS16 && prev_c != 0) {
+ /*
+ * VS16 (U+FE0F) is special. It typically turns the preceding
+ * single-width character into a double-width one. Let it
+ * have a width of 1 effectively making the combination with
+ * the preceding character double-width.
+ */
+ *tc = ' ';
+ return 1;
+ }
+
+ /* try recomposition */
+ prev_c = ucs_recompose(prev_c, curr_c);
+ if (prev_c != 0) {
+ vc_con_rewind(vc);
+ *tc = *c = prev_c;
+ return 1;
+ }
+
+ /* Otherwise zero-width code points are ignored. */
+ return 0;
+}
+
+static int vc_get_glyph(struct vc_data *vc, int tc)
+{
+ int glyph = conv_uni_to_pc(vc, tc);
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+
+ if (!(glyph & ~charmask))
+ return glyph;
+
+ if (glyph == -1)
+ return -1; /* nothing to display */
+
+ /* Glyph not found */
+ if ((!vc->vc_utf || vc->vc_disp_ctrl || tc < 128) && !(tc & ~charmask)) {
+ /*
+ * In legacy mode use the glyph we get by a 1:1 mapping.
+ * This would make absolutely no sense with Unicode in mind, but do this for
+ * ASCII characters since a font may lack Unicode mapping info and we don't
+ * want to end up with having question marks only.
+ */
+ return tc;
+ }
+
+ /*
+ * The Unicode screen memory is allocated only when required.
+ * This is one such case: we're about to "cheat" with the displayed
+ * character meaning the simple screen buffer won't hold the original
+ * information, whereas the Unicode screen buffer always does.
+ */
+ vc_uniscr_check(vc);
+
+ /* Try getting a simpler fallback character. */
+ tc = ucs_get_fallback(tc);
+ if (tc)
+ return vc_get_glyph(vc, tc);
+
+ /* Display U+FFFD (Unicode Replacement Character). */
+ return conv_uni_to_pc(vc, UCS_REPLACEMENT);
+}
+
static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
struct vc_draw_region *draw)
{
int next_c;
unsigned char vc_attr = vc->vc_attr;
- u16 himask = vc->vc_hi_font_mask, charmask = himask ? 0x1ff : 0xff;
+ u16 himask = vc->vc_hi_font_mask;
u8 width = 1;
bool inverse = false;
if (vc->vc_utf && !vc->vc_disp_ctrl) {
- if (is_double_width(c))
- width = 2;
+ width = vc_process_ucs(vc, &c, &tc);
+ if (!width)
+ goto out;
}
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(vc, tc);
- if (tc & ~charmask) {
- if (tc == -1 || tc == -2)
- return -1; /* nothing to display */
-
- /* Glyph not found */
- if ((!vc->vc_utf || vc->vc_disp_ctrl || c < 128) &&
- !(c & ~charmask)) {
- /*
- * In legacy mode use the glyph we get by a 1:1
- * mapping.
- * This would make absolutely no sense with Unicode in
- * mind, but do this for ASCII characters since a font
- * may lack Unicode mapping info and we don't want to
- * end up with having question marks only.
- */
- tc = c;
- } else {
- /*
- * Display U+FFFD. If it's not found, display an inverse
- * question mark.
- */
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (tc < 0) {
- inverse = true;
- tc = conv_uni_to_pc(vc, '?');
- if (tc < 0)
- tc = '?';
-
- vc_attr = vc_invert_attr(vc);
- con_flush(vc, draw);
- }
- }
+ tc = vc_get_glyph(vc, tc);
+ if (tc == -1)
+ return -1; /* nothing to display */
+ if (tc < 0) {
+ inverse = true;
+ tc = conv_uni_to_pc(vc, '?');
+ if (tc < 0)
+ tc = '?';
+
+ vc_attr = vc_invert_attr(vc);
+ con_flush(vc, draw);
}
next_c = c;
@@ -3028,8 +3104,14 @@ static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
tc = conv_uni_to_pc(vc, ' ');
if (tc < 0)
tc = ' ';
- next_c = ' ';
+ /*
+ * Store a zero-width space in the Unicode screen given that
+ * the previous code point is semantically double width.
+ */
+ next_c = UCS_ZWS;
}
+
+out:
notify_write(vc, c);
if (inverse)
@@ -3414,6 +3496,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
break;
case TIOCL_BLANKEDSCREEN:
return console_blanked;
+ case TIOCL_GETBRACKETEDPASTE:
+ return get_bracketed_paste(tty);
default:
return -EINVAL;
}
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 4b91072f3a4e..61342e06970a 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -951,6 +951,22 @@ int vt_ioctl(struct tty_struct *tty,
(unsigned short __user *)arg);
case VT_WAITEVENT:
return vt_event_wait_ioctl((struct vt_event __user *)arg);
+
+ case VT_GETCONSIZECSRPOS:
+ {
+ struct vt_consizecsrpos concsr;
+
+ console_lock();
+ concsr.con_cols = vc->vc_cols;
+ concsr.con_rows = vc->vc_rows;
+ concsr.csr_col = vc->state.x;
+ concsr.csr_row = vc->state.y;
+ console_unlock();
+ if (copy_to_user(up, &concsr, sizeof(concsr)))
+ return -EFAULT;
+ return 0;
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -1103,8 +1119,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
case VT_WAITACTIVE:
case VT_RELDISP:
case VT_DISALLOCATE:
- case VT_RESIZE:
- case VT_RESIZEX:
return vt_ioctl(tty, cmd, arg);
/*
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 76cedd30c274..4410e7d93b7d 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1397,6 +1397,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
* make sure that there are no outstanding requests when
* clock scaling is in progress
*/
+ mutex_lock(&hba->host->scan_mutex);
blk_mq_quiesce_tagset(&hba->host->tag_set);
mutex_lock(&hba->wb_mutex);
down_write(&hba->clk_scaling_lock);
@@ -1407,6 +1408,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba, u64 timeout_us)
up_write(&hba->clk_scaling_lock);
mutex_unlock(&hba->wb_mutex);
blk_mq_unquiesce_tagset(&hba->host->tag_set);
+ mutex_unlock(&hba->host->scan_mutex);
goto out;
}
@@ -1428,6 +1430,7 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err)
mutex_unlock(&hba->wb_mutex);
blk_mq_unquiesce_tagset(&hba->host->tag_set);
+ mutex_unlock(&hba->host->scan_mutex);
ufshcd_release(hba);
}
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 37887ec68412..18a978452001 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -122,7 +122,9 @@ static const struct {
};
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
-static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq);
+static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba,
+ unsigned long freq, char *name);
+static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq);
static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd)
{
@@ -506,10 +508,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
if (ret)
return ret;
- if (phy->power_count) {
+ if (phy->power_count)
phy_power_off(phy);
- phy_exit(phy);
- }
+
/* phy initialization - calibrate the phy */
ret = phy_init(phy);
@@ -597,13 +598,14 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
*
* @hba: host controller instance
* @is_pre_scale_up: flag to check if pre scale up condition.
+ * @freq: target opp freq
* Return: zero for success and non-zero in case of a failure.
*/
-static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up)
+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up, unsigned long freq)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_clk_info *clki;
- unsigned long core_clk_rate = 0;
+ unsigned long clk_freq = 0;
u32 core_clk_cycles_per_us;
/*
@@ -615,22 +617,34 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, bool is_pre_scale_up)
if (host->hw_ver.major < 4 && !ufshcd_is_intr_aggr_allowed(hba))
return 0;
+ if (hba->use_pm_opp && freq != ULONG_MAX) {
+ clk_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk");
+ if (clk_freq)
+ goto cfg_timers;
+ }
+
list_for_each_entry(clki, &hba->clk_list_head, list) {
if (!strcmp(clki->name, "core_clk")) {
+ if (freq == ULONG_MAX) {
+ clk_freq = clki->max_freq;
+ break;
+ }
+
if (is_pre_scale_up)
- core_clk_rate = clki->max_freq;
+ clk_freq = clki->max_freq;
else
- core_clk_rate = clk_get_rate(clki->clk);
+ clk_freq = clk_get_rate(clki->clk);
break;
}
}
+cfg_timers:
/* If frequency is smaller than 1MHz, set to 1MHz */
- if (core_clk_rate < DEFAULT_CLK_RATE_HZ)
- core_clk_rate = DEFAULT_CLK_RATE_HZ;
+ if (clk_freq < DEFAULT_CLK_RATE_HZ)
+ clk_freq = DEFAULT_CLK_RATE_HZ;
- core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
+ core_clk_cycles_per_us = clk_freq / USEC_PER_SEC;
if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {
ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
/*
@@ -650,13 +664,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
- if (ufs_qcom_cfg_timers(hba, false)) {
+ if (ufs_qcom_cfg_timers(hba, false, ULONG_MAX)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
return -EINVAL;
}
- err = ufs_qcom_set_core_clk_ctrl(hba, ULONG_MAX);
+ err = ufs_qcom_set_core_clk_ctrl(hba, true, ULONG_MAX);
if (err)
dev_err(hba->dev, "cfg core clk ctrl failed\n");
/*
@@ -928,17 +942,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
break;
case POST_CHANGE:
- if (ufs_qcom_cfg_timers(hba, false)) {
- dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
- __func__);
- /*
- * we return error code at the end of the routine,
- * but continue to configure UFS_PHY_TX_LANE_ENABLE
- * and bus voting as usual
- */
- ret = -EINVAL;
- }
-
/* cache the power mode parameters to use internally */
memcpy(&host->dev_req_params,
dev_req_params, sizeof(*dev_req_params));
@@ -1414,29 +1417,46 @@ static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba,
return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg);
}
-static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, unsigned long freq)
+static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up, unsigned long freq)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct list_head *head = &hba->clk_list_head;
struct ufs_clk_info *clki;
u32 cycles_in_1us = 0;
u32 core_clk_ctrl_reg;
+ unsigned long clk_freq;
int err;
+ if (hba->use_pm_opp && freq != ULONG_MAX) {
+ clk_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro");
+ if (clk_freq) {
+ cycles_in_1us = ceil(clk_freq, HZ_PER_MHZ);
+ goto set_core_clk_ctrl;
+ }
+ }
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk) &&
!strcmp(clki->name, "core_clk_unipro")) {
- if (!clki->max_freq)
+ if (!clki->max_freq) {
cycles_in_1us = 150; /* default for backwards compatibility */
- else if (freq == ULONG_MAX)
+ break;
+ }
+
+ if (freq == ULONG_MAX) {
cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ);
- else
- cycles_in_1us = ceil(freq, HZ_PER_MHZ);
+ break;
+ }
+ if (is_scale_up)
+ cycles_in_1us = ceil(clki->max_freq, HZ_PER_MHZ);
+ else
+ cycles_in_1us = ceil(clk_get_rate(clki->clk), HZ_PER_MHZ);
break;
}
}
+set_core_clk_ctrl:
err = ufshcd_dme_get(hba,
UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
&core_clk_ctrl_reg);
@@ -1473,13 +1493,13 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba, unsigned long f
{
int ret;
- ret = ufs_qcom_cfg_timers(hba, true);
+ ret = ufs_qcom_cfg_timers(hba, true, freq);
if (ret) {
dev_err(hba->dev, "%s ufs cfg timer failed\n", __func__);
return ret;
}
/* set unipro core clock attributes and clear clock divider */
- return ufs_qcom_set_core_clk_ctrl(hba, freq);
+ return ufs_qcom_set_core_clk_ctrl(hba, true, freq);
}
static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
@@ -1510,8 +1530,15 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba, unsigned long freq)
{
+ int ret;
+
+ ret = ufs_qcom_cfg_timers(hba, false, freq);
+ if (ret) {
+ dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__);
+ return ret;
+ }
/* set unipro core clock attributes and clear clock divider */
- return ufs_qcom_set_core_clk_ctrl(hba, freq);
+ return ufs_qcom_set_core_clk_ctrl(hba, false, freq);
}
static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up,
@@ -2092,11 +2119,53 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba)
return 0;
}
+static unsigned long ufs_qcom_opp_freq_to_clk_freq(struct ufs_hba *hba,
+ unsigned long freq, char *name)
+{
+ struct ufs_clk_info *clki;
+ struct dev_pm_opp *opp;
+ unsigned long clk_freq;
+ int idx = 0;
+ bool found = false;
+
+ opp = dev_pm_opp_find_freq_exact_indexed(hba->dev, freq, 0, true);
+ if (IS_ERR(opp)) {
+ dev_err(hba->dev, "Failed to find OPP for exact frequency %lu\n", freq);
+ return 0;
+ }
+
+ list_for_each_entry(clki, &hba->clk_list_head, list) {
+ if (!strcmp(clki->name, name)) {
+ found = true;
+ break;
+ }
+
+ idx++;
+ }
+
+ if (!found) {
+ dev_err(hba->dev, "Failed to find clock '%s' in clk list\n", name);
+ dev_pm_opp_put(opp);
+ return 0;
+ }
+
+ clk_freq = dev_pm_opp_get_freq_indexed(opp, idx);
+
+ dev_pm_opp_put(opp);
+
+ return clk_freq;
+}
+
static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq)
{
- u32 gear = 0;
+ u32 gear = UFS_HS_DONT_CHANGE;
+ unsigned long unipro_freq;
- switch (freq) {
+ if (!hba->use_pm_opp)
+ return gear;
+
+ unipro_freq = ufs_qcom_opp_freq_to_clk_freq(hba, freq, "core_clk_unipro");
+ switch (unipro_freq) {
case 403000000:
gear = UFS_HS_G5;
break;
@@ -2116,10 +2185,10 @@ static u32 ufs_qcom_freq_to_gear_speed(struct ufs_hba *hba, unsigned long freq)
break;
default:
dev_err(hba->dev, "%s: Unsupported clock freq : %lu\n", __func__, freq);
- break;
+ return UFS_HS_DONT_CHANGE;
}
- return gear;
+ return min_t(u32, gear, hba->max_pwr_info.info.gear_rx);
}
/*
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index aac67a4413ce..f19efad4d6f8 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -65,6 +65,16 @@ struct hv_uio_private_data {
char send_name[32];
};
+static void set_event(struct vmbus_channel *channel, s32 irq_state)
+{
+ channel->inbound.ring_buffer->interrupt_mask = !irq_state;
+ if (!channel->offermsg.monitor_allocated && irq_state) {
+ /* MB is needed for host to see the interrupt mask first */
+ virt_mb();
+ vmbus_set_event(channel);
+ }
+}
+
/*
* This is the irqcontrol callback to be registered to uio_info.
* It can be used to disable/enable interrupt from user space processes.
@@ -79,12 +89,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
{
struct hv_uio_private_data *pdata = info->priv;
struct hv_device *dev = pdata->device;
+ struct vmbus_channel *primary, *sc;
- dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
- virt_mb();
+ primary = dev->channel;
+ set_event(primary, irq_state);
- if (!dev->channel->offermsg.monitor_allocated && irq_state)
- vmbus_setevent(dev->channel);
+ mutex_lock(&vmbus_connection.channel_mutex);
+ list_for_each_entry(sc, &primary->sc_list, sc_list)
+ set_event(sc, irq_state);
+ mutex_unlock(&vmbus_connection.channel_mutex);
return 0;
}
@@ -95,12 +108,19 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
static void hv_uio_channel_cb(void *context)
{
struct vmbus_channel *chan = context;
- struct hv_device *hv_dev = chan->device_obj;
- struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+ struct hv_device *hv_dev;
+ struct hv_uio_private_data *pdata;
chan->inbound.ring_buffer->interrupt_mask = 1;
virt_mb();
+ /*
+ * The callback may come from a subchannel, in which case look
+ * for the hv device in the primary channel
+ */
+ hv_dev = chan->primary_channel ?
+ chan->primary_channel->device_obj : chan->device_obj;
+ pdata = hv_get_drvdata(hv_dev);
uio_event_notify(&pdata->info);
}
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 59ec505e198a..735df88774e4 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -179,8 +179,6 @@ err_phy3_init:
/**
* cdns3_plat_remove() - unbind drd driver and clean up
* @pdev: Pointer to Linux platform device
- *
- * Returns 0 on success otherwise negative errno
*/
static void cdns3_plat_remove(struct platform_device *pdev)
{
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 4824a10df07e..55f95f41b3b4 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -29,7 +29,8 @@
unsigned int cdnsp_port_speed(unsigned int port_status)
{
/*Detect gadget speed based on PORTSC register*/
- if (DEV_SUPERSPEEDPLUS(port_status))
+ if (DEV_SUPERSPEEDPLUS(port_status) ||
+ DEV_SSP_GEN1x2(port_status) || DEV_SSP_GEN2x2(port_status))
return USB_SPEED_SUPER_PLUS;
else if (DEV_SUPERSPEED(port_status))
return USB_SPEED_SUPER;
@@ -547,6 +548,7 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev)
dma_addr_t cmd_deq_dma;
union cdnsp_trb *event;
u32 cycle_state;
+ u32 retry = 10;
int ret, val;
u64 cmd_dma;
u32 flags;
@@ -578,8 +580,23 @@ int cdnsp_wait_for_cmd_compl(struct cdnsp_device *pdev)
flags = le32_to_cpu(event->event_cmd.flags);
/* Check the owner of the TRB. */
- if ((flags & TRB_CYCLE) != cycle_state)
+ if ((flags & TRB_CYCLE) != cycle_state) {
+ /*
+ * Give some extra time to get chance controller
+ * to finish command before returning error code.
+ * Checking CMD_RING_BUSY is not sufficient because
+ * this bit is cleared to '0' when the Command
+ * Descriptor has been executed by controller
+ * and not when command completion event has
+ * be added to event ring.
+ */
+ if (retry--) {
+ udelay(20);
+ continue;
+ }
+
return -EINVAL;
+ }
cmd_dma = le64_to_cpu(event->event_cmd.cmd_trb);
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index 12534be52f39..2afa3e558f85 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -285,11 +285,15 @@ struct cdnsp_port_regs {
#define XDEV_HS (0x3 << 10)
#define XDEV_SS (0x4 << 10)
#define XDEV_SSP (0x5 << 10)
+#define XDEV_SSP1x2 (0x6 << 10)
+#define XDEV_SSP2x2 (0x7 << 10)
#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0 << 10))
#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS)
#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS)
#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS)
#define DEV_SUPERSPEEDPLUS(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP)
+#define DEV_SSP_GEN1x2(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP1x2)
+#define DEV_SSP_GEN2x2(p) (((p) & DEV_SPEED_MASK) == XDEV_SSP2x2)
#define DEV_SUPERSPEED_ANY(p) (((p) & DEV_SPEED_MASK) >= XDEV_SS)
#define DEV_PORT_SPEED(p) (((p) >> 10) & 0x0f)
/* Port Link State Write Strobe - set this when changing link state */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 4f8bfd242b59..780f4d151345 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -6,6 +6,7 @@
*/
#include <linux/module.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -98,6 +99,7 @@ struct ci_hdrc_imx_data {
struct clk *clk;
struct clk *clk_wakeup;
struct imx_usbmisc_data *usbmisc_data;
+ int wakeup_irq;
bool supports_runtime_pm;
bool override_phy_control;
bool in_lpm;
@@ -336,6 +338,16 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
return ret;
}
+static irqreturn_t ci_wakeup_irq_handler(int irq, void *data)
+{
+ struct ci_hdrc_imx_data *imx_data = data;
+
+ disable_irq_nosync(irq);
+ pm_runtime_resume(&imx_data->ci_pdev->dev);
+
+ return IRQ_HANDLED;
+}
+
static void ci_hdrc_imx_disable_regulator(void *arg)
{
struct ci_hdrc_imx_data *data = arg;
@@ -494,6 +506,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
+ data->wakeup_irq = platform_get_irq_optional(pdev, 1);
+ if (data->wakeup_irq > 0) {
+ ret = devm_request_threaded_irq(dev, data->wakeup_irq,
+ NULL, ci_wakeup_irq_handler,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ pdata.name, data);
+ if (ret)
+ goto err_clk;
+ }
+
ret = imx_usbmisc_init(data->usbmisc_data);
if (ret) {
dev_err(dev, "usbmisc init failed, ret=%d\n", ret);
@@ -602,6 +624,10 @@ static int imx_controller_suspend(struct device *dev,
}
imx_disable_unprepare_clks(dev);
+
+ if (data->wakeup_irq > 0)
+ enable_irq(data->wakeup_irq);
+
if (data->plat_data->flags & CI_HDRC_PMQOS)
cpu_latency_qos_remove_request(&data->pm_qos_req);
@@ -626,6 +652,10 @@ static int imx_controller_resume(struct device *dev,
if (data->plat_data->flags & CI_HDRC_PMQOS)
cpu_latency_qos_add_request(&data->pm_qos_req, 0);
+ if (data->wakeup_irq > 0 &&
+ !irqd_irq_disabled(irq_get_irq_data(data->wakeup_irq)))
+ disable_irq_nosync(data->wakeup_irq);
+
ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;
@@ -661,6 +691,10 @@ static int ci_hdrc_imx_suspend(struct device *dev)
return ret;
pinctrl_pm_select_sleep_state(dev);
+
+ if (data->wakeup_irq > 0 && device_may_wakeup(dev))
+ enable_irq_wake(data->wakeup_irq);
+
return ret;
}
@@ -669,6 +703,9 @@ static int ci_hdrc_imx_resume(struct device *dev)
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret;
+ if (data->wakeup_irq > 0 && device_may_wakeup(dev))
+ disable_irq_wake(data->wakeup_irq);
+
pinctrl_pm_select_default_state(dev);
ret = imx_controller_resume(dev, PMSG_RESUME);
if (!ret && data->supports_runtime_pm) {
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 6243d8005f5d..118b9a68496b 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -139,6 +139,22 @@
#define MX6_USB_OTG_WAKEUP_BITS (MX6_BM_WAKEUP_ENABLE | MX6_BM_VBUS_WAKEUP | \
MX6_BM_ID_WAKEUP | MX6SX_BM_DPDM_WAKEUP_EN)
+/*
+ * HSIO Block Control Register
+ */
+
+#define BLKCTL_USB_WAKEUP_CTRL 0x0
+#define BLKCTL_OTG_WAKE_ENABLE BIT(31)
+#define BLKCTL_OTG_VBUS_SESSVALID BIT(4)
+#define BLKCTL_OTG_ID_WAKEUP_EN BIT(2)
+#define BLKCTL_OTG_VBUS_WAKEUP_EN BIT(1)
+#define BLKCTL_OTG_DPDM_WAKEUP_EN BIT(0)
+
+#define BLKCTL_WAKEUP_SOURCE (BLKCTL_OTG_WAKE_ENABLE | \
+ BLKCTL_OTG_ID_WAKEUP_EN | \
+ BLKCTL_OTG_VBUS_WAKEUP_EN | \
+ BLKCTL_OTG_DPDM_WAKEUP_EN)
+
struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct imx_usbmisc_data *data);
@@ -159,6 +175,7 @@ struct usbmisc_ops {
struct imx_usbmisc {
void __iomem *base;
+ void __iomem *blkctl;
spinlock_t lock;
const struct usbmisc_ops *ops;
};
@@ -1016,6 +1033,44 @@ static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data)
return 0;
}
+static u32 usbmisc_blkctl_wakeup_setting(struct imx_usbmisc_data *data)
+{
+ u32 wakeup_setting = BLKCTL_WAKEUP_SOURCE;
+
+ if (data->ext_id || data->available_role != USB_DR_MODE_OTG)
+ wakeup_setting &= ~BLKCTL_OTG_ID_WAKEUP_EN;
+
+ if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST)
+ wakeup_setting &= ~BLKCTL_OTG_VBUS_WAKEUP_EN;
+
+ /* Select session valid as VBUS wakeup source */
+ wakeup_setting |= BLKCTL_OTG_VBUS_SESSVALID;
+
+ return wakeup_setting;
+}
+
+static int usbmisc_imx95_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ if (!usbmisc->blkctl)
+ return 0;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL);
+ val &= ~BLKCTL_WAKEUP_SOURCE;
+
+ if (enabled)
+ val |= usbmisc_blkctl_wakeup_setting(data);
+
+ writel(val, usbmisc->blkctl + BLKCTL_USB_WAKEUP_CTRL);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ return 0;
+}
+
static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
@@ -1068,6 +1123,14 @@ static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
.power_lost_check = usbmisc_imx7d_power_lost_check,
};
+static const struct usbmisc_ops imx95_usbmisc_ops = {
+ .init = usbmisc_imx7d_init,
+ .set_wakeup = usbmisc_imx95_set_wakeup,
+ .charger_detection = imx7d_charger_detection,
+ .power_lost_check = usbmisc_imx7d_power_lost_check,
+ .vbus_comparator_on = usbmisc_imx7d_vbus_comparator_on,
+};
+
static inline bool is_imx53_usbmisc(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
@@ -1289,6 +1352,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx8ulp-usbmisc",
.data = &imx7ulp_usbmisc_ops,
},
+ {
+ .compatible = "fsl,imx95-usbmisc",
+ .data = &imx95_usbmisc_ops,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
@@ -1296,6 +1363,7 @@ MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct imx_usbmisc *data;
+ struct resource *res;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1307,6 +1375,15 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ data->blkctl = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->blkctl))
+ return PTR_ERR(data->blkctl);
+ } else if (device_is_compatible(&pdev->dev, "fsl,imx95-usbmisc")) {
+ dev_warn(&pdev->dev, "wakeup setting is missing\n");
+ }
+
data->ops = of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, data);
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 16e7fa4d488d..ecd6d1f39e49 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -92,7 +92,6 @@ struct wdm_device {
u16 wMaxCommand;
u16 wMaxPacketSize;
__le16 inum;
- int reslength;
int length;
int read;
int count;
@@ -214,6 +213,11 @@ static void wdm_in_callback(struct urb *urb)
if (desc->rerr == 0 && status != -EPIPE)
desc->rerr = status;
+ if (length == 0) {
+ dev_dbg(&desc->intf->dev, "received ZLP\n");
+ goto skip_zlp;
+ }
+
if (length + desc->length > desc->wMaxCommand) {
/* The buffer would overflow */
set_bit(WDM_OVERFLOW, &desc->flags);
@@ -222,18 +226,18 @@ static void wdm_in_callback(struct urb *urb)
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
memmove(desc->ubuf + desc->length, desc->inbuf, length);
desc->length += length;
- desc->reslength = length;
}
}
skip_error:
if (desc->rerr) {
/*
- * Since there was an error, userspace may decide to not read
- * any data after poll'ing.
+ * If there was a ZLP or an error, userspace may decide to not
+ * read any data after poll'ing.
* We should respond to further attempts from the device to send
* data, so that we can get unstuck.
*/
+skip_zlp:
schedule_work(&desc->service_outs_intr);
} else {
set_bit(WDM_READ, &desc->flags);
@@ -585,15 +589,6 @@ retry:
goto retry;
}
- if (!desc->reslength) { /* zero length read */
- dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n");
- clear_bit(WDM_READ, &desc->flags);
- rv = service_outstanding_interrupt(desc);
- spin_unlock_irq(&desc->iuspin);
- if (rv < 0)
- goto err;
- goto retry;
- }
cntr = desc->length;
spin_unlock_irq(&desc->iuspin);
}
@@ -1016,7 +1011,7 @@ static void service_interrupt_work(struct work_struct *work)
spin_lock_irq(&desc->iuspin);
service_outstanding_interrupt(desc);
- if (!desc->resp_count) {
+ if (!desc->resp_count && (desc->length || desc->rerr)) {
set_bit(WDM_READ, &desc->flags);
wake_up(&desc->wait);
}
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 740d2d2b19fb..75de29725a45 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -483,6 +483,7 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)
u8 tag;
int rv;
long wait_rv;
+ unsigned long expire;
dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
data->iin_ep_present);
@@ -512,10 +513,11 @@ static int usbtmc_get_stb(struct usbtmc_file_data *file_data, __u8 *stb)
}
if (data->iin_ep_present) {
+ expire = msecs_to_jiffies(file_data->timeout);
wait_rv = wait_event_interruptible_timeout(
data->waitq,
atomic_read(&data->iin_data_valid) != 0,
- file_data->timeout);
+ expire);
if (wait_rv < 0) {
dev_dbg(dev, "wait interrupted %ld\n", wait_rv);
rv = wait_rv;
@@ -563,14 +565,15 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
rv = usbtmc_get_stb(file_data, &stb);
- if (rv > 0) {
- srq_asserted = atomic_xchg(&file_data->srq_asserted,
- srq_asserted);
- if (srq_asserted)
- stb |= 0x40; /* Set RQS bit */
+ if (rv < 0)
+ return rv;
+
+ srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted);
+ if (srq_asserted)
+ stb |= 0x40; /* Set RQS bit */
+
+ rv = put_user(stb, (__u8 __user *)arg);
- rv = put_user(stb, (__u8 __user *)arg);
- }
return rv;
}
@@ -2199,7 +2202,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case USBTMC_IOCTL_GET_STB:
retval = usbtmc_get_stb(file_data, &tmp_byte);
- if (retval > 0)
+ if (!retval)
retval = put_user(tmp_byte, (__u8 __user *)arg);
break;
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
index 1e36be2a28fd..421c3af38e06 100644
--- a/drivers/usb/common/usb-conn-gpio.c
+++ b/drivers/usb/common/usb-conn-gpio.c
@@ -21,6 +21,9 @@
#include <linux/regulator/consumer.h>
#include <linux/string_choices.h>
#include <linux/usb/role.h>
+#include <linux/idr.h>
+
+static DEFINE_IDA(usb_conn_ida);
#define USB_GPIO_DEB_MS 20 /* ms */
#define USB_GPIO_DEB_US ((USB_GPIO_DEB_MS) * 1000) /* us */
@@ -30,6 +33,7 @@
struct usb_conn_info {
struct device *dev;
+ int conn_id; /* store the IDA-allocated ID */
struct usb_role_switch *role_sw;
enum usb_role last_role;
struct regulator *vbus;
@@ -161,7 +165,17 @@ static int usb_conn_psy_register(struct usb_conn_info *info)
.fwnode = dev_fwnode(dev),
};
- desc->name = "usb-charger";
+ info->conn_id = ida_alloc(&usb_conn_ida, GFP_KERNEL);
+ if (info->conn_id < 0)
+ return info->conn_id;
+
+ desc->name = devm_kasprintf(dev, GFP_KERNEL, "usb-charger-%d",
+ info->conn_id);
+ if (!desc->name) {
+ ida_free(&usb_conn_ida, info->conn_id);
+ return -ENOMEM;
+ }
+
desc->properties = usb_charger_properties;
desc->num_properties = ARRAY_SIZE(usb_charger_properties);
desc->get_property = usb_charger_get_property;
@@ -169,8 +183,10 @@ static int usb_conn_psy_register(struct usb_conn_info *info)
cfg.drv_data = info;
info->charger = devm_power_supply_register(dev, desc, &cfg);
- if (IS_ERR(info->charger))
- dev_err(dev, "Unable to register charger\n");
+ if (IS_ERR(info->charger)) {
+ dev_err(dev, "Unable to register charger %d\n", info->conn_id);
+ ida_free(&usb_conn_ida, info->conn_id);
+ }
return PTR_ERR_OR_ZERO(info->charger);
}
@@ -278,6 +294,9 @@ static void usb_conn_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&info->dw_det);
+ if (info->charger)
+ ida_free(&usb_conn_ida, info->conn_id);
+
if (info->last_role == USB_ROLE_HOST && info->vbus)
regulator_disable(info->vbus);
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 13bd4ec4ea5f..fc0cfd94cbab 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -307,7 +307,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
goto skip_to_next_endpoint_or_interface_descriptor;
}
- i = d->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ i = usb_endpoint_num(d);
if (i == 0) {
dev_notice(ddev, "config %d interface %d altsetting %d has an "
"invalid descriptor for endpoint zero, skipping\n",
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 0e1dd6ef60a7..416af6d76374 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4160,7 +4160,7 @@ static int usb_set_device_initiated_lpm(struct usb_device *udev,
"for unconfigured device.\n",
__func__, str_enable_disable(enable),
usb3_lpm_names[state]);
- return 0;
+ return -EINVAL;
}
if (enable) {
@@ -4234,9 +4234,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
}
/*
- * Don't allow device intiated U1/U2 if the system exit latency + one bus
- * interval is greater than the minimum service interval of any active
- * periodic endpoint. See USB 3.2 section 9.4.9
+ * Don't allow device intiated U1/U2 if device isn't in the configured state,
+ * or the system exit latency + one bus interval is greater than the minimum
+ * service interval of any active periodic endpoint. See USB 3.2 section 9.4.9
*/
static bool usb_device_may_initiate_lpm(struct usb_device *udev,
enum usb3_link_state state)
@@ -4244,7 +4244,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev,
unsigned int sel; /* us */
int i, j;
- if (!udev->lpm_devinit_allow)
+ if (!udev->lpm_devinit_allow || !udev->actconfig)
return false;
if (state == USB3_LPM_U1)
@@ -4292,7 +4292,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev,
* driver know about it. If that call fails, it should be harmless, and just
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
*/
-static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+static int usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
int timeout;
@@ -4301,7 +4301,7 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
/* Skip if the device BOS descriptor couldn't be read */
if (!udev->bos)
- return;
+ return -EINVAL;
u1_mel = udev->bos->ss_cap->bU1devExitLat;
u2_mel = udev->bos->ss_cap->bU2DevExitLat;
@@ -4312,7 +4312,7 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
*/
if ((state == USB3_LPM_U1 && u1_mel == 0) ||
(state == USB3_LPM_U2 && u2_mel == 0))
- return;
+ return -EINVAL;
/* We allow the host controller to set the U1/U2 timeout internally
* first, so that it can change its schedule to account for the
@@ -4323,13 +4323,13 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
/* xHCI host controller doesn't want to enable this LPM state. */
if (timeout == 0)
- return;
+ return -EINVAL;
if (timeout < 0) {
dev_warn(&udev->dev, "Could not enable %s link state, "
"xHCI error %i.\n", usb3_lpm_names[state],
timeout);
- return;
+ return timeout;
}
if (usb_set_lpm_timeout(udev, state, timeout)) {
@@ -4338,29 +4338,15 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
- return;
- }
-
- /* Only a configured device will accept the Set Feature
- * U1/U2_ENABLE
- */
- if (udev->actconfig &&
- usb_device_may_initiate_lpm(udev, state)) {
- if (usb_set_device_initiated_lpm(udev, state, true)) {
- /*
- * Request to enable device initiated U1/U2 failed,
- * better to turn off lpm in this case.
- */
- usb_set_lpm_timeout(udev, state, 0);
- hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
- return;
- }
+ return -EBUSY;
}
if (state == USB3_LPM_U1)
udev->usb3_lpm_u1_enabled = 1;
else if (state == USB3_LPM_U2)
udev->usb3_lpm_u2_enabled = 1;
+
+ return 0;
}
/*
* Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
@@ -4393,8 +4379,6 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
if (usb_set_lpm_timeout(udev, state, 0))
return -EBUSY;
- usb_set_device_initiated_lpm(udev, state, false);
-
if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
"bus schedule bandwidth may be impacted.\n",
@@ -4424,6 +4408,7 @@ static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
int usb_disable_lpm(struct usb_device *udev)
{
struct usb_hcd *hcd;
+ int err;
if (!udev || !udev->parent ||
udev->speed < USB_SPEED_SUPER ||
@@ -4441,14 +4426,19 @@ int usb_disable_lpm(struct usb_device *udev)
/* If LPM is enabled, attempt to disable it. */
if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
- goto enable_lpm;
+ goto disable_failed;
if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
- goto enable_lpm;
+ goto disable_failed;
+
+ err = usb_set_device_initiated_lpm(udev, USB3_LPM_U1, false);
+ if (!err)
+ usb_set_device_initiated_lpm(udev, USB3_LPM_U2, false);
return 0;
-enable_lpm:
- usb_enable_lpm(udev);
+disable_failed:
+ udev->lpm_disable_count--;
+
return -EBUSY;
}
EXPORT_SYMBOL_GPL(usb_disable_lpm);
@@ -4509,10 +4499,24 @@ void usb_enable_lpm(struct usb_device *udev)
port_dev = hub->ports[udev->portnum - 1];
if (port_dev->usb3_lpm_u1_permit)
- usb_enable_link_state(hcd, udev, USB3_LPM_U1);
+ if (usb_enable_link_state(hcd, udev, USB3_LPM_U1))
+ return;
if (port_dev->usb3_lpm_u2_permit)
- usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+ if (usb_enable_link_state(hcd, udev, USB3_LPM_U2))
+ return;
+
+ /*
+ * Enable device initiated U1/U2 with a SetFeature(U1/U2_ENABLE) request
+ * if system exit latency is short enough and device is configured
+ */
+ if (usb_device_may_initiate_lpm(udev, USB3_LPM_U1)) {
+ if (usb_set_device_initiated_lpm(udev, USB3_LPM_U1, true))
+ return;
+
+ if (usb_device_may_initiate_lpm(udev, USB3_LPM_U2))
+ usb_set_device_initiated_lpm(udev, USB3_LPM_U2, true);
+ }
}
EXPORT_SYMBOL_GPL(usb_enable_lpm);
@@ -6133,6 +6137,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
struct usb_hub *parent_hub;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor;
+ struct usb_interface *intf;
struct usb_host_bos *bos;
int i, j, ret = 0;
int port1 = udev->portnum;
@@ -6190,6 +6195,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
if (!udev->actconfig)
goto done;
+ /*
+ * Some devices can't handle setting default altsetting 0 with a
+ * Set-Interface request. Disable host-side endpoints of those
+ * interfaces here. Enable and reset them back after host has set
+ * its internal endpoint structures during usb_hcd_alloc_bandwith()
+ */
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ if (intf->cur_altsetting->desc.bAlternateSetting == 0)
+ usb_disable_interface(udev, intf, true);
+ }
+
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
@@ -6221,12 +6238,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
*/
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct usb_host_config *config = udev->actconfig;
- struct usb_interface *intf = config->interface[i];
struct usb_interface_descriptor *desc;
+ intf = config->interface[i];
desc = &intf->cur_altsetting->desc;
if (desc->bAlternateSetting == 0) {
- usb_disable_interface(udev, intf, true);
usb_enable_interface(udev, intf, true);
ret = 0;
} else {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 36d3df7d040c..53d68d20fb62 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -372,6 +372,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* SanDisk Corp. SanDisk 3.2Gen1 */
{ USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT },
+ /* SanDisk Extreme 55AE */
+ { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM },
+
/* Realforce 87U Keyboard */
{ USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index 935c0efea0b6..ea1ce8beb0cb 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -165,6 +165,8 @@ static int usb_acpi_add_usb4_devlink(struct usb_device *udev)
return 0;
hub = usb_hub_to_struct_hub(udev->parent);
+ if (!hub)
+ return 0;
port_dev = hub->ports[udev->portnum - 1];
struct fwnode_handle *nhi_fwnode __free(fwnode_handle) =
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0b4685aad2d5..118fa4c93a79 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -695,15 +695,16 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
device_set_of_node_from_dev(&dev->dev, bus->sysdev);
dev_set_name(&dev->dev, "usb%d", bus->busnum);
} else {
+ int n;
+
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0') {
- snprintf(dev->devpath, sizeof dev->devpath,
- "%d", port1);
+ n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1);
/* Root ports are not counted in route string */
dev->route = 0;
} else {
- snprintf(dev->devpath, sizeof dev->devpath,
- "%s.%d", parent->devpath, port1);
+ n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d",
+ parent->devpath, port1);
/* Route string assumes hubs have less than 16 ports */
if (port1 < 15)
dev->route = parent->route +
@@ -712,6 +713,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = parent->route +
(15 << ((parent->level - 1)*4));
}
+ if (n >= sizeof(dev->devpath)) {
+ usb_put_hcd(bus_to_hcd(bus));
+ usb_put_dev(dev);
+ return NULL;
+ }
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 300ea4969f0c..d5b622f78cf3 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -4049,7 +4049,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
return -EINVAL;
}
- ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ ep_type = usb_endpoint_type(desc);
mps = usb_endpoint_maxp(desc);
mc = usb_endpoint_maxp_mult(desc);
@@ -4604,6 +4604,12 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
if (!hsotg)
return -ENODEV;
+ /* Exit clock gating when driver is stopped. */
+ if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
+ hsotg->bus_suspended && !hsotg->params.no_clock_gating) {
+ dwc2_gadget_exit_clock_gating(hsotg, 0);
+ }
+
/* all endpoints should be shutdown */
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 124eda2522d9..830e6c9e5fe0 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o
obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o
obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o
+obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom-legacy.o
obj-$(CONFIG_USB_DWC3_IMX8MP) += dwc3-imx8mp.o
obj-$(CONFIG_USB_DWC3_XILINX) += dwc3-xilinx.o
obj-$(CONFIG_USB_DWC3_OCTEON) += dwc3-octeon.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 66a08b527165..2bc775a747f2 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -26,6 +26,7 @@
#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/devinfo.h>
#include <linux/reset.h>
#include <linux/bitfield.h>
@@ -36,6 +37,7 @@
#include "core.h"
#include "gadget.h"
+#include "glue.h"
#include "io.h"
#include "debug.h"
@@ -1699,6 +1701,7 @@ static void dwc3_get_properties(struct dwc3 *dwc)
u8 tx_thr_num_pkt_prd = 0;
u8 tx_max_burst_prd = 0;
u8 tx_fifo_resize_max_num;
+ u16 num_hc_interrupters;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xf;
@@ -1719,6 +1722,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
*/
tx_fifo_resize_max_num = 6;
+ /* default to a single XHCI interrupter */
+ num_hc_interrupters = 1;
+
dwc->maximum_speed = usb_get_maximum_speed(dev);
dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev);
dwc->dr_mode = usb_get_dr_mode(dev);
@@ -1765,6 +1771,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
&tx_thr_num_pkt_prd);
device_property_read_u8(dev, "snps,tx-max-burst-prd",
&tx_max_burst_prd);
+ device_property_read_u16(dev, "num-hc-interrupters",
+ &num_hc_interrupters);
+ /* DWC3 core allowed to have a max of 8 interrupters */
+ if (num_hc_interrupters > 8)
+ num_hc_interrupters = 8;
+
dwc->do_fifo_resize = device_property_read_bool(dev,
"tx-fifo-resize");
if (dwc->do_fifo_resize)
@@ -1851,6 +1863,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->tx_max_burst_prd = tx_max_burst_prd;
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
+
+ dwc->num_hc_interrupters = num_hc_interrupters;
}
/* check whether the core supports IMOD */
@@ -2148,27 +2162,16 @@ static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
return usb_psy;
}
-static int dwc3_probe(struct platform_device *pdev)
+int dwc3_core_probe(const struct dwc3_probe_data *data)
{
- struct device *dev = &pdev->dev;
- struct resource *res, dwc_res;
+ struct dwc3 *dwc = data->dwc;
+ struct device *dev = dwc->dev;
+ struct resource dwc_res;
unsigned int hw_mode;
void __iomem *regs;
- struct dwc3 *dwc;
+ struct resource *res = data->res;
int ret;
- dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
- if (!dwc)
- return -ENOMEM;
-
- dwc->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing memory resource\n");
- return -ENODEV;
- }
-
dwc->xhci_resources[0].start = res->start;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
DWC3_XHCI_REGS_END;
@@ -2208,15 +2211,17 @@ static int dwc3_probe(struct platform_device *pdev)
if (IS_ERR(dwc->usb_psy))
return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n");
- dwc->reset = devm_reset_control_array_get_optional_shared(dev);
- if (IS_ERR(dwc->reset)) {
- ret = PTR_ERR(dwc->reset);
- goto err_put_psy;
- }
+ if (!data->ignore_clocks_and_resets) {
+ dwc->reset = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(dwc->reset)) {
+ ret = PTR_ERR(dwc->reset);
+ goto err_put_psy;
+ }
- ret = dwc3_get_clocks(dwc);
- if (ret)
- goto err_put_psy;
+ ret = dwc3_get_clocks(dwc);
+ if (ret)
+ goto err_put_psy;
+ }
ret = reset_control_deassert(dwc->reset);
if (ret)
@@ -2232,7 +2237,7 @@ static int dwc3_probe(struct platform_device *pdev)
goto err_disable_clks;
}
- platform_set_drvdata(pdev, dwc);
+ dev_set_drvdata(dev, dwc);
dwc3_cache_hwparams(dwc);
if (!dwc->sysdev_is_parent &&
@@ -2327,12 +2332,35 @@ err_put_psy:
return ret;
}
+EXPORT_SYMBOL_GPL(dwc3_core_probe);
-static void dwc3_remove(struct platform_device *pdev)
+static int dwc3_probe(struct platform_device *pdev)
{
- struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct dwc3_probe_data probe_data = {};
+ struct resource *res;
+ struct dwc3 *dwc;
- pm_runtime_get_sync(&pdev->dev);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+
+ dwc = devm_kzalloc(&pdev->dev, sizeof(*dwc), GFP_KERNEL);
+ if (!dwc)
+ return -ENOMEM;
+
+ dwc->dev = &pdev->dev;
+
+ probe_data.dwc = dwc;
+ probe_data.res = res;
+
+ return dwc3_core_probe(&probe_data);
+}
+
+void dwc3_core_remove(struct dwc3 *dwc)
+{
+ pm_runtime_get_sync(dwc->dev);
dwc3_core_exit_mode(dwc);
dwc3_debugfs_exit(dwc);
@@ -2340,22 +2368,28 @@ static void dwc3_remove(struct platform_device *pdev)
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
- pm_runtime_allow(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_dont_use_autosuspend(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(dwc->dev);
+ pm_runtime_disable(dwc->dev);
+ pm_runtime_dont_use_autosuspend(dwc->dev);
+ pm_runtime_put_noidle(dwc->dev);
/*
* HACK: Clear the driver data, which is currently accessed by parent
* glue drivers, before allowing the parent to suspend.
*/
- platform_set_drvdata(pdev, NULL);
- pm_runtime_set_suspended(&pdev->dev);
+ dev_set_drvdata(dwc->dev, NULL);
+ pm_runtime_set_suspended(dwc->dev);
dwc3_free_event_buffers(dwc);
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
}
+EXPORT_SYMBOL_GPL(dwc3_core_remove);
+
+static void dwc3_remove(struct platform_device *pdev)
+{
+ dwc3_core_remove(platform_get_drvdata(pdev));
+}
#ifdef CONFIG_PM
static int dwc3_core_init_for_resume(struct dwc3 *dwc)
@@ -2544,9 +2578,8 @@ static int dwc3_runtime_checks(struct dwc3 *dwc)
return 0;
}
-static int dwc3_runtime_suspend(struct device *dev)
+int dwc3_runtime_suspend(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
if (dwc3_runtime_checks(dwc))
@@ -2558,10 +2591,11 @@ static int dwc3_runtime_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_suspend);
-static int dwc3_runtime_resume(struct device *dev)
+int dwc3_runtime_resume(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct device *dev = dwc->dev;
int ret;
ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
@@ -2571,7 +2605,7 @@ static int dwc3_runtime_resume(struct device *dev)
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc->pending_events) {
- pm_runtime_put(dwc->dev);
+ pm_runtime_put(dev);
dwc->pending_events = false;
enable_irq(dwc->irq_gadget);
}
@@ -2586,10 +2620,11 @@ static int dwc3_runtime_resume(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_resume);
-static int dwc3_runtime_idle(struct device *dev)
+int dwc3_runtime_idle(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct device *dev = dwc->dev;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
@@ -2607,12 +2642,28 @@ static int dwc3_runtime_idle(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_runtime_idle);
+
+static int dwc3_plat_runtime_suspend(struct device *dev)
+{
+ return dwc3_runtime_suspend(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_runtime_resume(struct device *dev)
+{
+ return dwc3_runtime_resume(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_runtime_idle(struct device *dev)
+{
+ return dwc3_runtime_idle(dev_get_drvdata(dev));
+}
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
-static int dwc3_suspend(struct device *dev)
+int dwc3_pm_suspend(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct device *dev = dwc->dev;
int ret;
ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
@@ -2623,10 +2674,11 @@ static int dwc3_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(dwc3_pm_suspend);
-static int dwc3_resume(struct device *dev)
+int dwc3_pm_resume(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct device *dev = dwc->dev;
int ret = 0;
pinctrl_pm_select_default_state(dev);
@@ -2645,10 +2697,10 @@ out:
return ret;
}
+EXPORT_SYMBOL_GPL(dwc3_pm_resume);
-static void dwc3_complete(struct device *dev)
+void dwc3_pm_complete(struct dwc3 *dwc)
{
- struct dwc3 *dwc = dev_get_drvdata(dev);
u32 reg;
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
@@ -2658,21 +2710,60 @@ static void dwc3_complete(struct device *dev)
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
}
}
+EXPORT_SYMBOL_GPL(dwc3_pm_complete);
+
+int dwc3_pm_prepare(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+
+ /*
+ * Indicate to the PM core that it may safely leave the device in
+ * runtime suspend if runtime-suspended already in device mode.
+ */
+ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE &&
+ pm_runtime_suspended(dev) &&
+ !dev_pinctrl(dev))
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dwc3_pm_prepare);
+
+static int dwc3_plat_suspend(struct device *dev)
+{
+ return dwc3_pm_suspend(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_resume(struct device *dev)
+{
+ return dwc3_pm_resume(dev_get_drvdata(dev));
+}
+
+static void dwc3_plat_complete(struct device *dev)
+{
+ dwc3_pm_complete(dev_get_drvdata(dev));
+}
+
+static int dwc3_plat_prepare(struct device *dev)
+{
+ return dwc3_pm_prepare(dev_get_drvdata(dev));
+}
#else
-#define dwc3_complete NULL
+#define dwc3_plat_complete NULL
+#define dwc3_plat_prepare NULL
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
- .complete = dwc3_complete,
-
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_plat_suspend, dwc3_plat_resume)
+ .complete = dwc3_plat_complete,
+ .prepare = dwc3_plat_prepare,
/*
* Runtime suspend halts the controller on disconnection. It relies on
* platforms with custom connection notification to start the controller
* again.
*/
- SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
- dwc3_runtime_idle)
+ SET_RUNTIME_PM_OPS(dwc3_plat_runtime_suspend, dwc3_plat_runtime_resume,
+ dwc3_plat_runtime_idle)
};
#ifdef CONFIG_OF
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 27eae4cf223d..d5b985fa12f4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1083,6 +1083,7 @@ struct dwc3_scratchpad_array {
* @tx_max_burst_prd: max periodic ESS transmit burst size
* @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize
* @clear_stall_protocol: endpoint number that requires a delayed status phase
+ * @num_hc_interrupters: number of host controller interrupters
* @hsphy_interface: "utmi" or "ulpi"
* @connected: true when we're connected to a host, false otherwise
* @softconnect: true when gadget connect is called, false when disconnect runs
@@ -1333,6 +1334,7 @@ struct dwc3 {
u8 tx_max_burst_prd;
u8 tx_fifo_resize_max_num;
u8 clear_stall_protocol;
+ u16 num_hc_interrupters;
const char *hsphy_interface;
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index de686b9e6404..e934f94e8fd8 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -145,6 +145,12 @@ static void dwc3_exynos_remove(struct platform_device *pdev)
regulator_disable(exynos->vdd10);
}
+static const struct dwc3_exynos_driverdata exynos2200_drvdata = {
+ .clk_names = { "link_aclk" },
+ .num_clks = 1,
+ .suspend_clk_idx = -1,
+};
+
static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
.clk_names = { "usbdrd30" },
.num_clks = 1,
@@ -181,8 +187,17 @@ static const struct dwc3_exynos_driverdata gs101_drvdata = {
.suspend_clk_idx = 1,
};
+static const struct dwc3_exynos_driverdata exynosautov920_drvdata = {
+ .clk_names = { "ref", "susp_clk"},
+ .num_clks = 2,
+ .suspend_clk_idx = 1,
+};
+
static const struct of_device_id exynos_dwc3_match[] = {
{
+ .compatible = "samsung,exynos2200-dwusb3",
+ .data = &exynos2200_drvdata,
+ }, {
.compatible = "samsung,exynos5250-dwusb3",
.data = &exynos5250_drvdata,
}, {
@@ -198,6 +213,9 @@ static const struct of_device_id exynos_dwc3_match[] = {
.compatible = "samsung,exynos850-dwusb3",
.data = &exynos850_drvdata,
}, {
+ .compatible = "samsung,exynosautov920-dwusb3",
+ .data = &exynosautov920_drvdata,
+ }, {
.compatible = "google,gs101-dwusb3",
.data = &gs101_drvdata,
}, {
diff --git a/drivers/usb/dwc3/dwc3-qcom-legacy.c b/drivers/usb/dwc3/dwc3-qcom-legacy.c
new file mode 100644
index 000000000000..d3fad0fcfdac
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-qcom-legacy.c
@@ -0,0 +1,935 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Inspired by dwc3-of-simple.c
+ */
+
+#include <linux/cleanup.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/of_clk.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/extcon.h>
+#include <linux/interconnect.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/of.h>
+#include <linux/reset.h>
+#include <linux/iopoll.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb.h>
+#include "core.h"
+
+/* USB QSCRATCH Hardware registers */
+#define QSCRATCH_HS_PHY_CTRL 0x10
+#define UTMI_OTG_VBUS_VALID BIT(20)
+#define SW_SESSVLD_SEL BIT(28)
+
+#define QSCRATCH_SS_PHY_CTRL 0x30
+#define LANE0_PWR_PRESENT BIT(24)
+
+#define QSCRATCH_GENERAL_CFG 0x08
+#define PIPE_UTMI_CLK_SEL BIT(0)
+#define PIPE3_PHYSTATUS_SW BIT(3)
+#define PIPE_UTMI_CLK_DIS BIT(8)
+
+#define PWR_EVNT_LPM_IN_L2_MASK BIT(4)
+#define PWR_EVNT_LPM_OUT_L2_MASK BIT(5)
+
+#define SDM845_QSCRATCH_BASE_OFFSET 0xf8800
+#define SDM845_QSCRATCH_SIZE 0x400
+#define SDM845_DWC3_CORE_SIZE 0xcd00
+
+/* Interconnect path bandwidths in MBps */
+#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
+#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
+#define USB_MEMORY_AVG_SS_BW MBps_to_icc(1000)
+#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
+#define APPS_USB_AVG_BW 0
+#define APPS_USB_PEAK_BW MBps_to_icc(40)
+
+/* Qualcomm SoCs with multiport support has up to 4 ports */
+#define DWC3_QCOM_MAX_PORTS 4
+
+static const u32 pwr_evnt_irq_stat_reg[DWC3_QCOM_MAX_PORTS] = {
+ 0x58,
+ 0x1dc,
+ 0x228,
+ 0x238,
+};
+
+struct dwc3_qcom_port {
+ int qusb2_phy_irq;
+ int dp_hs_phy_irq;
+ int dm_hs_phy_irq;
+ int ss_phy_irq;
+ enum usb_device_speed usb2_speed;
+};
+
+struct dwc3_qcom {
+ struct device *dev;
+ void __iomem *qscratch_base;
+ struct platform_device *dwc3;
+ struct clk **clks;
+ int num_clocks;
+ struct reset_control *resets;
+ struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS];
+ u8 num_ports;
+
+ struct extcon_dev *edev;
+ struct extcon_dev *host_edev;
+ struct notifier_block vbus_nb;
+ struct notifier_block host_nb;
+
+ enum usb_dr_mode mode;
+ bool is_suspended;
+ bool pm_suspended;
+ struct icc_path *icc_path_ddr;
+ struct icc_path *icc_path_apps;
+};
+
+static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
+{
+ u32 reg;
+
+ reg = readl(base + offset);
+ reg |= val;
+ writel(reg, base + offset);
+
+ /* ensure that above write is through */
+ readl(base + offset);
+}
+
+static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
+{
+ u32 reg;
+
+ reg = readl(base + offset);
+ reg &= ~val;
+ writel(reg, base + offset);
+
+ /* ensure that above write is through */
+ readl(base + offset);
+}
+
+static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
+{
+ if (enable) {
+ dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+ LANE0_PWR_PRESENT);
+ dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+ UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+ } else {
+ dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
+ LANE0_PWR_PRESENT);
+ dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
+ UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
+ }
+}
+
+static int dwc3_qcom_vbus_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb);
+
+ /* enable vbus override for device mode */
+ dwc3_qcom_vbus_override_enable(qcom, event);
+ qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST;
+
+ return NOTIFY_DONE;
+}
+
+static int dwc3_qcom_host_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb);
+
+ /* disable vbus override in host mode */
+ dwc3_qcom_vbus_override_enable(qcom, !event);
+ qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL;
+
+ return NOTIFY_DONE;
+}
+
+static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
+{
+ struct device *dev = qcom->dev;
+ struct extcon_dev *host_edev;
+ int ret;
+
+ if (!of_property_present(dev->of_node, "extcon"))
+ return 0;
+
+ qcom->edev = extcon_get_edev_by_phandle(dev, 0);
+ if (IS_ERR(qcom->edev))
+ return dev_err_probe(dev, PTR_ERR(qcom->edev),
+ "Failed to get extcon\n");
+
+ qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier;
+
+ qcom->host_edev = extcon_get_edev_by_phandle(dev, 1);
+ if (IS_ERR(qcom->host_edev))
+ qcom->host_edev = NULL;
+
+ ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB,
+ &qcom->vbus_nb);
+ if (ret < 0) {
+ dev_err(dev, "VBUS notifier register failed\n");
+ return ret;
+ }
+
+ if (qcom->host_edev)
+ host_edev = qcom->host_edev;
+ else
+ host_edev = qcom->edev;
+
+ qcom->host_nb.notifier_call = dwc3_qcom_host_notifier;
+ ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST,
+ &qcom->host_nb);
+ if (ret < 0) {
+ dev_err(dev, "Host notifier register failed\n");
+ return ret;
+ }
+
+ /* Update initial VBUS override based on extcon state */
+ if (extcon_get_state(qcom->edev, EXTCON_USB) ||
+ !extcon_get_state(host_edev, EXTCON_USB_HOST))
+ dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev);
+ else
+ dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev);
+
+ return 0;
+}
+
+static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
+{
+ int ret;
+
+ ret = icc_enable(qcom->icc_path_ddr);
+ if (ret)
+ return ret;
+
+ ret = icc_enable(qcom->icc_path_apps);
+ if (ret)
+ icc_disable(qcom->icc_path_ddr);
+
+ return ret;
+}
+
+static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
+{
+ int ret;
+
+ ret = icc_disable(qcom->icc_path_ddr);
+ if (ret)
+ return ret;
+
+ ret = icc_disable(qcom->icc_path_apps);
+ if (ret)
+ icc_enable(qcom->icc_path_ddr);
+
+ return ret;
+}
+
+/**
+ * dwc3_qcom_interconnect_init() - Get interconnect path handles
+ * and set bandwidth.
+ * @qcom: Pointer to the concerned usb core.
+ *
+ */
+static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
+{
+ enum usb_device_speed max_speed;
+ struct device *dev = qcom->dev;
+ int ret;
+
+ qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
+ if (IS_ERR(qcom->icc_path_ddr)) {
+ return dev_err_probe(dev, PTR_ERR(qcom->icc_path_ddr),
+ "failed to get usb-ddr path\n");
+ }
+
+ qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
+ if (IS_ERR(qcom->icc_path_apps)) {
+ ret = dev_err_probe(dev, PTR_ERR(qcom->icc_path_apps),
+ "failed to get apps-usb path\n");
+ goto put_path_ddr;
+ }
+
+ max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
+ if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
+ ret = icc_set_bw(qcom->icc_path_ddr,
+ USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
+ } else {
+ ret = icc_set_bw(qcom->icc_path_ddr,
+ USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
+ }
+ if (ret) {
+ dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
+ goto put_path_apps;
+ }
+
+ ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
+ if (ret) {
+ dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
+ goto put_path_apps;
+ }
+
+ return 0;
+
+put_path_apps:
+ icc_put(qcom->icc_path_apps);
+put_path_ddr:
+ icc_put(qcom->icc_path_ddr);
+ return ret;
+}
+
+/**
+ * dwc3_qcom_interconnect_exit() - Release interconnect path handles
+ * @qcom: Pointer to the concerned usb core.
+ *
+ * This function is used to release interconnect path handle.
+ */
+static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
+{
+ icc_put(qcom->icc_path_ddr);
+ icc_put(qcom->icc_path_apps);
+}
+
+/* Only usable in contexts where the role can not change. */
+static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
+{
+ struct dwc3 *dwc;
+
+ /*
+ * FIXME: Fix this layering violation.
+ */
+ dwc = platform_get_drvdata(qcom->dwc3);
+
+ /* Core driver may not have probed yet. */
+ if (!dwc)
+ return false;
+
+ return dwc->xhci;
+}
+
+static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
+{
+ struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+ struct usb_device *udev;
+ struct usb_hcd __maybe_unused *hcd;
+
+ /*
+ * FIXME: Fix this layering violation.
+ */
+ hcd = platform_get_drvdata(dwc->xhci);
+
+#ifdef CONFIG_USB
+ udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1);
+#else
+ udev = NULL;
+#endif
+ if (!udev)
+ return USB_SPEED_UNKNOWN;
+
+ return udev->speed;
+}
+
+static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity)
+{
+ if (!irq)
+ return;
+
+ if (polarity)
+ irq_set_irq_type(irq, polarity);
+
+ enable_irq(irq);
+ enable_irq_wake(irq);
+}
+
+static void dwc3_qcom_disable_wakeup_irq(int irq)
+{
+ if (!irq)
+ return;
+
+ disable_irq_wake(irq);
+ disable_irq_nosync(irq);
+}
+
+static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port)
+{
+ dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq);
+
+ if (port->usb2_speed == USB_SPEED_LOW) {
+ dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
+ } else if ((port->usb2_speed == USB_SPEED_HIGH) ||
+ (port->usb2_speed == USB_SPEED_FULL)) {
+ dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
+ } else {
+ dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
+ }
+
+ dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq);
+}
+
+static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port)
+{
+ dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0);
+
+ /*
+ * Configure DP/DM line interrupts based on the USB2 device attached to
+ * the root hub port. When HS/FS device is connected, configure the DP line
+ * as falling edge to detect both disconnect and remote wakeup scenarios. When
+ * LS device is connected, configure DM line as falling edge to detect both
+ * disconnect and remote wakeup. When no device is connected, configure both
+ * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
+ */
+
+ if (port->usb2_speed == USB_SPEED_LOW) {
+ dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
+ IRQ_TYPE_EDGE_FALLING);
+ } else if ((port->usb2_speed == USB_SPEED_HIGH) ||
+ (port->usb2_speed == USB_SPEED_FULL)) {
+ dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
+ IRQ_TYPE_EDGE_FALLING);
+ } else {
+ dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
+ IRQ_TYPE_EDGE_RISING);
+ dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
+ IRQ_TYPE_EDGE_RISING);
+ }
+
+ dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0);
+}
+
+static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
+{
+ int i;
+
+ for (i = 0; i < qcom->num_ports; i++)
+ dwc3_qcom_disable_port_interrupts(&qcom->ports[i]);
+}
+
+static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
+{
+ int i;
+
+ for (i = 0; i < qcom->num_ports; i++)
+ dwc3_qcom_enable_port_interrupts(&qcom->ports[i]);
+}
+
+static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
+{
+ u32 val;
+ int i, ret;
+
+ if (qcom->is_suspended)
+ return 0;
+
+ for (i = 0; i < qcom->num_ports; i++) {
+ val = readl(qcom->qscratch_base + pwr_evnt_irq_stat_reg[i]);
+ if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
+ dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1);
+ }
+
+ for (i = qcom->num_clocks - 1; i >= 0; i--)
+ clk_disable_unprepare(qcom->clks[i]);
+
+ ret = dwc3_qcom_interconnect_disable(qcom);
+ if (ret)
+ dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
+
+ /*
+ * The role is stable during suspend as role switching is done from a
+ * freezable workqueue.
+ */
+ if (dwc3_qcom_is_host(qcom) && wakeup) {
+ for (i = 0; i < qcom->num_ports; i++)
+ qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i);
+ dwc3_qcom_enable_interrupts(qcom);
+ }
+
+ qcom->is_suspended = true;
+
+ return 0;
+}
+
+static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
+{
+ int ret;
+ int i;
+
+ if (!qcom->is_suspended)
+ return 0;
+
+ if (dwc3_qcom_is_host(qcom) && wakeup)
+ dwc3_qcom_disable_interrupts(qcom);
+
+ for (i = 0; i < qcom->num_clocks; i++) {
+ ret = clk_prepare_enable(qcom->clks[i]);
+ if (ret < 0) {
+ while (--i >= 0)
+ clk_disable_unprepare(qcom->clks[i]);
+ return ret;
+ }
+ }
+
+ ret = dwc3_qcom_interconnect_enable(qcom);
+ if (ret)
+ dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
+
+ /* Clear existing events from PHY related to L2 in/out */
+ for (i = 0; i < qcom->num_ports; i++) {
+ dwc3_qcom_setbits(qcom->qscratch_base,
+ pwr_evnt_irq_stat_reg[i],
+ PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
+ }
+
+ qcom->is_suspended = false;
+
+ return 0;
+}
+
+static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
+{
+ struct dwc3_qcom *qcom = data;
+ struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+
+ /* If pm_suspended then let pm_resume take care of resuming h/w */
+ if (qcom->pm_suspended)
+ return IRQ_HANDLED;
+
+ /*
+ * This is safe as role switching is done from a freezable workqueue
+ * and the wakeup interrupts are disabled as part of resume.
+ */
+ if (dwc3_qcom_is_host(qcom))
+ pm_runtime_resume(&dwc->xhci->dev);
+
+ return IRQ_HANDLED;
+}
+
+static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
+{
+ /* Configure dwc3 to use UTMI clock as PIPE clock not present */
+ dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+ PIPE_UTMI_CLK_DIS);
+
+ usleep_range(100, 1000);
+
+ dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+ PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
+
+ usleep_range(100, 1000);
+
+ dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
+ PIPE_UTMI_CLK_DIS);
+}
+
+static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
+ const char *name)
+{
+ int ret;
+
+ /* Keep wakeup interrupts disabled until suspend */
+ ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
+ qcom_dwc3_resume_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ name, qcom);
+ if (ret)
+ dev_err(qcom->dev, "failed to request irq %s: %d\n", name, ret);
+
+ return ret;
+}
+
+static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ const char *irq_name;
+ int irq;
+ int ret;
+
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
+ if (irq > 0) {
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
+ if (ret)
+ return ret;
+ qcom->ports[port_index].dp_hs_phy_irq = irq;
+ }
+
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_index + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
+ if (irq > 0) {
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
+ if (ret)
+ return ret;
+ qcom->ports[port_index].dm_hs_phy_irq = irq;
+ }
+
+ if (is_multiport)
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_index + 1);
+ else
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq");
+ if (!irq_name)
+ return -ENOMEM;
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
+ if (irq > 0) {
+ ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
+ if (ret)
+ return ret;
+ qcom->ports[port_index].ss_phy_irq = irq;
+ }
+
+ if (is_multiport)
+ return 0;
+
+ irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
+ if (irq > 0) {
+ ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy");
+ if (ret)
+ return ret;
+ qcom->ports[port_index].qusb2_phy_irq = irq;
+ }
+
+ return 0;
+}
+
+static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
+{
+ char irq_name[14];
+ int port_num;
+ int irq;
+
+ irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1");
+ if (irq <= 0)
+ return 1;
+
+ for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) {
+ sprintf(irq_name, "dp_hs_phy_%d", port_num);
+
+ irq = platform_get_irq_byname_optional(pdev, irq_name);
+ if (irq <= 0)
+ return port_num - 1;
+ }
+
+ return DWC3_QCOM_MAX_PORTS;
+}
+
+static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ bool is_multiport;
+ int ret;
+ int i;
+
+ qcom->num_ports = dwc3_qcom_find_num_ports(pdev);
+ is_multiport = (qcom->num_ports > 1);
+
+ for (i = 0; i < qcom->num_ports; i++) {
+ ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
+{
+ struct device *dev = qcom->dev;
+ struct device_node *np = dev->of_node;
+ int i;
+
+ if (!np || !count)
+ return 0;
+
+ if (count < 0)
+ return count;
+
+ qcom->num_clocks = count;
+
+ qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
+ sizeof(struct clk *), GFP_KERNEL);
+ if (!qcom->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < qcom->num_clocks; i++) {
+ struct clk *clk;
+ int ret;
+
+ clk = of_clk_get(np, i);
+ if (IS_ERR(clk)) {
+ while (--i >= 0)
+ clk_put(qcom->clks[i]);
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret < 0) {
+ while (--i >= 0) {
+ clk_disable_unprepare(qcom->clks[i]);
+ clk_put(qcom->clks[i]);
+ }
+ clk_put(clk);
+
+ return ret;
+ }
+
+ qcom->clks[i] = clk;
+ }
+
+ return 0;
+}
+
+static int dwc3_qcom_of_register_core(struct platform_device *pdev)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np,
+ "snps,dwc3");
+ if (!dwc3_np) {
+ dev_err(dev, "failed to find dwc3 core child\n");
+ return -ENODEV;
+ }
+
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "failed to register dwc3 core - %d\n", ret);
+ return ret;
+ }
+
+ qcom->dwc3 = of_find_device_by_node(dwc3_np);
+ if (!qcom->dwc3) {
+ ret = -ENODEV;
+ dev_err(dev, "failed to get dwc3 platform device\n");
+ of_platform_depopulate(dev);
+ }
+
+ return ret;
+}
+
+static int dwc3_qcom_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct dwc3_qcom *qcom;
+ int ret, i;
+ bool ignore_pipe_clk;
+ bool wakeup_source;
+
+ qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
+ if (!qcom)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, qcom);
+ qcom->dev = &pdev->dev;
+
+ qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(qcom->resets)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
+ "failed to get resets\n");
+ }
+
+ ret = reset_control_assert(qcom->resets);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
+ return ret;
+ }
+
+ usleep_range(10, 1000);
+
+ ret = reset_control_deassert(qcom->resets);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
+ goto reset_assert;
+ }
+
+ ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to get clocks\n");
+ goto reset_assert;
+ }
+
+ qcom->qscratch_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(qcom->qscratch_base)) {
+ ret = PTR_ERR(qcom->qscratch_base);
+ goto clk_disable;
+ }
+
+ ret = dwc3_qcom_setup_irq(pdev);
+ if (ret) {
+ dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
+ goto clk_disable;
+ }
+
+ /*
+ * Disable pipe_clk requirement if specified. Used when dwc3
+ * operates without SSPHY and only HS/FS/LS modes are supported.
+ */
+ ignore_pipe_clk = device_property_read_bool(dev,
+ "qcom,select-utmi-as-pipe-clk");
+ if (ignore_pipe_clk)
+ dwc3_qcom_select_utmi_clk(qcom);
+
+ ret = dwc3_qcom_of_register_core(pdev);
+ if (ret) {
+ dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
+ goto clk_disable;
+ }
+
+ ret = dwc3_qcom_interconnect_init(qcom);
+ if (ret)
+ goto depopulate;
+
+ qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
+
+ /* enable vbus override for device mode */
+ if (qcom->mode != USB_DR_MODE_HOST)
+ dwc3_qcom_vbus_override_enable(qcom, true);
+
+ /* register extcon to override sw_vbus on Vbus change later */
+ ret = dwc3_qcom_register_extcon(qcom);
+ if (ret)
+ goto interconnect_exit;
+
+ wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
+ device_init_wakeup(&pdev->dev, wakeup_source);
+ device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
+
+ qcom->is_suspended = false;
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_forbid(dev);
+
+ return 0;
+
+interconnect_exit:
+ dwc3_qcom_interconnect_exit(qcom);
+depopulate:
+ of_platform_depopulate(&pdev->dev);
+ platform_device_put(qcom->dwc3);
+clk_disable:
+ for (i = qcom->num_clocks - 1; i >= 0; i--) {
+ clk_disable_unprepare(qcom->clks[i]);
+ clk_put(qcom->clks[i]);
+ }
+reset_assert:
+ reset_control_assert(qcom->resets);
+
+ return ret;
+}
+
+static void dwc3_qcom_remove(struct platform_device *pdev)
+{
+ struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ int i;
+
+ of_platform_depopulate(&pdev->dev);
+ platform_device_put(qcom->dwc3);
+
+ for (i = qcom->num_clocks - 1; i >= 0; i--) {
+ clk_disable_unprepare(qcom->clks[i]);
+ clk_put(qcom->clks[i]);
+ }
+ qcom->num_clocks = 0;
+
+ dwc3_qcom_interconnect_exit(qcom);
+ reset_control_assert(qcom->resets);
+
+ pm_runtime_allow(dev);
+ pm_runtime_disable(dev);
+}
+
+static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
+{
+ struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ bool wakeup = device_may_wakeup(dev);
+ int ret;
+
+ ret = dwc3_qcom_suspend(qcom, wakeup);
+ if (ret)
+ return ret;
+
+ qcom->pm_suspended = true;
+
+ return 0;
+}
+
+static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
+{
+ struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ bool wakeup = device_may_wakeup(dev);
+ int ret;
+
+ ret = dwc3_qcom_resume(qcom, wakeup);
+ if (ret)
+ return ret;
+
+ qcom->pm_suspended = false;
+
+ return 0;
+}
+
+static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
+{
+ struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+
+ return dwc3_qcom_suspend(qcom, true);
+}
+
+static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
+{
+ struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+
+ return dwc3_qcom_resume(qcom, true);
+}
+
+static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
+ SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id dwc3_qcom_of_match[] = {
+ { .compatible = "qcom,dwc3" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
+
+static struct platform_driver dwc3_qcom_driver = {
+ .probe = dwc3_qcom_probe,
+ .remove = dwc3_qcom_remove,
+ .driver = {
+ .name = "dwc3-qcom-legacy",
+ .pm = &dwc3_qcom_dev_pm_ops,
+ .of_match_table = dwc3_qcom_of_match,
+ },
+};
+
+module_platform_driver(dwc3_qcom_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DesignWare DWC3 QCOM legacy glue Driver");
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index 58683bb672e9..7334de85ad10 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -4,7 +4,6 @@
* Inspired by dwc3-of-simple.c
*/
-#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clk.h>
@@ -14,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/extcon.h>
#include <linux/interconnect.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/usb/of.h>
@@ -23,6 +21,7 @@
#include <linux/usb/hcd.h>
#include <linux/usb.h>
#include "core.h"
+#include "glue.h"
/* USB QSCRATCH Hardware registers */
#define QSCRATCH_HS_PHY_CTRL 0x10
@@ -73,8 +72,8 @@ struct dwc3_qcom_port {
struct dwc3_qcom {
struct device *dev;
void __iomem *qscratch_base;
- struct platform_device *dwc3;
- struct clk **clks;
+ struct dwc3 dwc;
+ struct clk_bulk_data *clks;
int num_clocks;
struct reset_control *resets;
struct dwc3_qcom_port ports[DWC3_QCOM_MAX_PORTS];
@@ -92,6 +91,8 @@ struct dwc3_qcom {
struct icc_path *icc_path_apps;
};
+#define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc)
+
static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
{
u32 reg;
@@ -116,6 +117,11 @@ static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
readl(base + offset);
}
+/*
+ * TODO: Make the in-core role switching code invoke dwc3_qcom_vbus_override_enable(),
+ * validate that the in-core extcon support is functional, and drop extcon
+ * handling from the glue
+ */
static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
{
if (enable) {
@@ -260,7 +266,7 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
goto put_path_ddr;
}
- max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
+ max_speed = usb_get_maximum_speed(qcom->dwc.dev);
if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
ret = icc_set_bw(qcom->icc_path_ddr,
USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
@@ -303,25 +309,14 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
/* Only usable in contexts where the role can not change. */
static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
{
- struct dwc3 *dwc;
-
- /*
- * FIXME: Fix this layering violation.
- */
- dwc = platform_get_drvdata(qcom->dwc3);
-
- /* Core driver may not have probed yet. */
- if (!dwc)
- return false;
-
- return dwc->xhci;
+ return qcom->dwc.xhci;
}
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
{
- struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
struct usb_device *udev;
struct usb_hcd __maybe_unused *hcd;
+ struct dwc3 *dwc = &qcom->dwc;
/*
* FIXME: Fix this layering violation.
@@ -436,9 +431,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1);
}
-
- for (i = qcom->num_clocks - 1; i >= 0; i--)
- clk_disable_unprepare(qcom->clks[i]);
+ clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
ret = dwc3_qcom_interconnect_disable(qcom);
if (ret)
@@ -470,14 +463,9 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
if (dwc3_qcom_is_host(qcom) && wakeup)
dwc3_qcom_disable_interrupts(qcom);
- for (i = 0; i < qcom->num_clocks; i++) {
- ret = clk_prepare_enable(qcom->clks[i]);
- if (ret < 0) {
- while (--i >= 0)
- clk_disable_unprepare(qcom->clks[i]);
- return ret;
- }
- }
+ ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks);
+ if (ret < 0)
+ return ret;
ret = dwc3_qcom_interconnect_enable(qcom);
if (ret)
@@ -498,7 +486,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
{
struct dwc3_qcom *qcom = data;
- struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+ struct dwc3 *dwc = &qcom->dwc;
/* If pm_suspended then let pm_resume take care of resuming h/w */
if (qcom->pm_suspended)
@@ -547,9 +535,10 @@ static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
return ret;
}
-static int dwc3_qcom_setup_port_irq(struct platform_device *pdev, int port_index, bool is_multiport)
+static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
+ struct platform_device *pdev,
+ int port_index, bool is_multiport)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
const char *irq_name;
int irq;
int ret;
@@ -634,9 +623,8 @@ static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
return DWC3_QCOM_MAX_PORTS;
}
-static int dwc3_qcom_setup_irq(struct platform_device *pdev)
+static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
bool is_multiport;
int ret;
int i;
@@ -645,7 +633,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
is_multiport = (qcom->num_ports > 1);
for (i = 0; i < qcom->num_ports; i++) {
- ret = dwc3_qcom_setup_port_irq(pdev, i, is_multiport);
+ ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport);
if (ret)
return ret;
}
@@ -653,89 +641,14 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
return 0;
}
-static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
-{
- struct device *dev = qcom->dev;
- struct device_node *np = dev->of_node;
- int i;
-
- if (!np || !count)
- return 0;
-
- if (count < 0)
- return count;
-
- qcom->num_clocks = count;
-
- qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
- sizeof(struct clk *), GFP_KERNEL);
- if (!qcom->clks)
- return -ENOMEM;
-
- for (i = 0; i < qcom->num_clocks; i++) {
- struct clk *clk;
- int ret;
-
- clk = of_clk_get(np, i);
- if (IS_ERR(clk)) {
- while (--i >= 0)
- clk_put(qcom->clks[i]);
- return PTR_ERR(clk);
- }
-
- ret = clk_prepare_enable(clk);
- if (ret < 0) {
- while (--i >= 0) {
- clk_disable_unprepare(qcom->clks[i]);
- clk_put(qcom->clks[i]);
- }
- clk_put(clk);
-
- return ret;
- }
-
- qcom->clks[i] = clk;
- }
-
- return 0;
-}
-
-static int dwc3_qcom_of_register_core(struct platform_device *pdev)
-{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
- struct device_node *np = pdev->dev.of_node;
- struct device *dev = &pdev->dev;
- int ret;
-
- struct device_node *dwc3_np __free(device_node) = of_get_compatible_child(np,
- "snps,dwc3");
- if (!dwc3_np) {
- dev_err(dev, "failed to find dwc3 core child\n");
- return -ENODEV;
- }
-
- ret = of_platform_populate(np, NULL, NULL, dev);
- if (ret) {
- dev_err(dev, "failed to register dwc3 core - %d\n", ret);
- return ret;
- }
-
- qcom->dwc3 = of_find_device_by_node(dwc3_np);
- if (!qcom->dwc3) {
- ret = -ENODEV;
- dev_err(dev, "failed to get dwc3 platform device\n");
- of_platform_depopulate(dev);
- }
-
- return ret;
-}
-
static int dwc3_qcom_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct dwc3_probe_data probe_data = {};
struct device *dev = &pdev->dev;
struct dwc3_qcom *qcom;
- int ret, i;
+ struct resource res;
+ struct resource *r;
+ int ret;
bool ignore_pipe_clk;
bool wakeup_source;
@@ -743,7 +656,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (!qcom)
return -ENOMEM;
- platform_set_drvdata(pdev, qcom);
qcom->dev = &pdev->dev;
qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
@@ -752,6 +664,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
"failed to get resets\n");
}
+ ret = devm_clk_bulk_get_all(&pdev->dev, &qcom->clks);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get clocks\n");
+ qcom->num_clocks = ret;
+
ret = reset_control_assert(qcom->resets);
if (ret) {
dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
@@ -766,19 +683,26 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
goto reset_assert;
}
- ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
- if (ret) {
- dev_err_probe(dev, ret, "failed to get clocks\n");
+ ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks);
+ if (ret < 0)
goto reset_assert;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -EINVAL;
+ goto clk_disable;
}
+ res = *r;
+ res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET;
- qcom->qscratch_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(qcom->qscratch_base)) {
- ret = PTR_ERR(qcom->qscratch_base);
+ qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE);
+ if (!qcom->qscratch_base) {
+ dev_err(dev, "failed to map qscratch region\n");
+ ret = -ENOMEM;
goto clk_disable;
}
- ret = dwc3_qcom_setup_irq(pdev);
+ ret = dwc3_qcom_setup_irq(qcom, pdev);
if (ret) {
dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
goto clk_disable;
@@ -793,17 +717,21 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
if (ignore_pipe_clk)
dwc3_qcom_select_utmi_clk(qcom);
- ret = dwc3_qcom_of_register_core(pdev);
- if (ret) {
- dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
+ qcom->dwc.dev = dev;
+ probe_data.dwc = &qcom->dwc;
+ probe_data.res = &res;
+ probe_data.ignore_clocks_and_resets = true;
+ ret = dwc3_core_probe(&probe_data);
+ if (ret) {
+ ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
goto clk_disable;
}
ret = dwc3_qcom_interconnect_init(qcom);
if (ret)
- goto depopulate;
+ goto remove_core;
- qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
+ qcom->mode = usb_get_dr_mode(dev);
/* enable vbus override for device mode */
if (qcom->mode != USB_DR_MODE_HOST)
@@ -816,25 +744,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
device_init_wakeup(&pdev->dev, wakeup_source);
- device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
qcom->is_suspended = false;
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- pm_runtime_forbid(dev);
return 0;
interconnect_exit:
dwc3_qcom_interconnect_exit(qcom);
-depopulate:
- of_platform_depopulate(&pdev->dev);
- platform_device_put(qcom->dwc3);
+remove_core:
+ dwc3_core_remove(&qcom->dwc);
clk_disable:
- for (i = qcom->num_clocks - 1; i >= 0; i--) {
- clk_disable_unprepare(qcom->clks[i]);
- clk_put(qcom->clks[i]);
- }
+ clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
reset_assert:
reset_control_assert(qcom->resets);
@@ -843,32 +763,28 @@ reset_assert:
static void dwc3_qcom_remove(struct platform_device *pdev)
{
- struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- int i;
+ struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
- of_platform_depopulate(&pdev->dev);
- platform_device_put(qcom->dwc3);
+ dwc3_core_remove(&qcom->dwc);
- for (i = qcom->num_clocks - 1; i >= 0; i--) {
- clk_disable_unprepare(qcom->clks[i]);
- clk_put(qcom->clks[i]);
- }
- qcom->num_clocks = 0;
+ clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
dwc3_qcom_interconnect_exit(qcom);
reset_control_assert(qcom->resets);
-
- pm_runtime_allow(dev);
- pm_runtime_disable(dev);
}
-static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
+static int dwc3_qcom_pm_suspend(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
bool wakeup = device_may_wakeup(dev);
int ret;
+ ret = dwc3_pm_suspend(&qcom->dwc);
+ if (ret)
+ return ret;
+
ret = dwc3_qcom_suspend(qcom, wakeup);
if (ret)
return ret;
@@ -878,9 +794,10 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
+static int dwc3_qcom_pm_resume(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
bool wakeup = device_may_wakeup(dev);
int ret;
@@ -890,31 +807,68 @@ static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
qcom->pm_suspended = false;
+ ret = dwc3_pm_resume(&qcom->dwc);
+ if (ret)
+ return ret;
+
return 0;
}
-static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
+static void dwc3_qcom_complete(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+
+ dwc3_pm_complete(dwc);
+}
+
+static int dwc3_qcom_prepare(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+
+ return dwc3_pm_prepare(dwc);
+}
+
+static int dwc3_qcom_runtime_suspend(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
+ int ret;
+
+ ret = dwc3_runtime_suspend(&qcom->dwc);
+ if (ret)
+ return ret;
return dwc3_qcom_suspend(qcom, true);
}
-static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
+static int dwc3_qcom_runtime_resume(struct device *dev)
{
- struct dwc3_qcom *qcom = dev_get_drvdata(dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
+ int ret;
- return dwc3_qcom_resume(qcom, true);
+ ret = dwc3_qcom_resume(qcom, true);
+ if (ret)
+ return ret;
+
+ return dwc3_runtime_resume(&qcom->dwc);
+}
+
+static int dwc3_qcom_runtime_idle(struct device *dev)
+{
+ return dwc3_runtime_idle(dev_get_drvdata(dev));
}
static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
- SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
+ RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
+ dwc3_qcom_runtime_idle)
+ .complete = pm_sleep_ptr(dwc3_qcom_complete),
+ .prepare = pm_sleep_ptr(dwc3_qcom_prepare),
};
static const struct of_device_id dwc3_qcom_of_match[] = {
- { .compatible = "qcom,dwc3" },
+ { .compatible = "qcom,snps-dwc3" },
{ }
};
MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
@@ -924,7 +878,7 @@ static struct platform_driver dwc3_qcom_driver = {
.remove = dwc3_qcom_remove,
.driver = {
.name = "dwc3-qcom",
- .pm = &dwc3_qcom_dev_pm_ops,
+ .pm = pm_ptr(&dwc3_qcom_dev_pm_ops),
.of_match_table = dwc3_qcom_of_match,
},
};
diff --git a/drivers/usb/dwc3/glue.h b/drivers/usb/dwc3/glue.h
new file mode 100644
index 000000000000..2efd00e763be
--- /dev/null
+++ b/drivers/usb/dwc3/glue.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * glue.h - DesignWare USB3 DRD glue header
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GLUE_H
+#define __DRIVERS_USB_DWC3_GLUE_H
+
+#include <linux/types.h>
+#include "core.h"
+
+/**
+ * dwc3_probe_data: Initialization parameters passed to dwc3_core_probe()
+ * @dwc: Reference to dwc3 context structure
+ * @res: resource for the DWC3 core mmio region
+ * @ignore_clocks_and_resets: clocks and resets defined for the device should
+ * be ignored by the DWC3 core, as they are managed by the glue
+ */
+struct dwc3_probe_data {
+ struct dwc3 *dwc;
+ struct resource *res;
+ bool ignore_clocks_and_resets;
+};
+
+int dwc3_core_probe(const struct dwc3_probe_data *data);
+void dwc3_core_remove(struct dwc3 *dwc);
+
+int dwc3_runtime_suspend(struct dwc3 *dwc);
+int dwc3_runtime_resume(struct dwc3 *dwc);
+int dwc3_runtime_idle(struct dwc3 *dwc);
+int dwc3_pm_suspend(struct dwc3 *dwc);
+int dwc3_pm_resume(struct dwc3 *dwc);
+void dwc3_pm_complete(struct dwc3 *dwc);
+int dwc3_pm_prepare(struct dwc3 *dwc);
+
+#endif
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b48e108fc8fe..1c513bf8002e 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -182,6 +182,9 @@ int dwc3_host_init(struct dwc3 *dwc)
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A))
props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
+ props[prop_idx++] = PROPERTY_ENTRY_U16("num-hc-interrupters",
+ dwc->num_hc_interrupters);
+
if (prop_idx) {
ret = device_create_managed_software_node(&xhci->dev, props, NULL);
if (ret) {
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index ed5a92c474e5..30016b805bfd 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -158,7 +158,7 @@ struct usb_ep *usb_ep_autoconfig(
if (!ep)
return NULL;
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ type = usb_endpoint_type(desc);
/* report (variable) full speed bulk maxpacket */
if (type == USB_ENDPOINT_XFER_BULK) {
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index c7a05f842745..97a62b926415 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -62,6 +62,9 @@ struct f_hidg {
unsigned short report_desc_length;
char *report_desc;
unsigned short report_length;
+ unsigned char interval;
+ bool interval_user_set;
+
/*
* use_out_ep - if true, the OUT Endpoint (interrupt out method)
* will be used to receive reports from the host
@@ -75,6 +78,7 @@ struct f_hidg {
/* recv report */
spinlock_t read_spinlock;
wait_queue_head_t read_queue;
+ bool disabled;
/* recv report - interrupt out only (use_out_ep == 1) */
struct list_head completed_out_req;
unsigned int qlen;
@@ -156,10 +160,7 @@ static struct usb_endpoint_descriptor hidg_ss_in_ep_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 4, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /*.bInterval = DYNAMIC */
};
static struct usb_ss_ep_comp_descriptor hidg_ss_in_comp_desc = {
@@ -177,10 +178,7 @@ static struct usb_endpoint_descriptor hidg_ss_out_ep_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 4, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /*.bInterval = DYNAMIC */
};
static struct usb_ss_ep_comp_descriptor hidg_ss_out_comp_desc = {
@@ -218,10 +216,7 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 4, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /* .bInterval = DYNAMIC */
};
static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
@@ -230,10 +225,7 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 4, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /*.bInterval = DYNAMIC */
};
static struct usb_descriptor_header *hidg_hs_descriptors_intout[] = {
@@ -259,10 +251,7 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 10, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /*.bInterval = DYNAMIC */
};
static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
@@ -271,10 +260,7 @@ static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
/*.wMaxPacketSize = DYNAMIC */
- .bInterval = 10, /* FIXME: Add this field in the
- * HID gadget configuration?
- * (struct hidg_func_descriptor)
- */
+ /*.bInterval = DYNAMIC */
};
static struct usb_descriptor_header *hidg_fs_descriptors_intout[] = {
@@ -329,7 +315,7 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer,
spin_lock_irqsave(&hidg->read_spinlock, flags);
-#define READ_COND_INTOUT (!list_empty(&hidg->completed_out_req))
+#define READ_COND_INTOUT (!list_empty(&hidg->completed_out_req) || hidg->disabled)
/* wait for at least one buffer to complete */
while (!READ_COND_INTOUT) {
@@ -343,6 +329,11 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer,
spin_lock_irqsave(&hidg->read_spinlock, flags);
}
+ if (hidg->disabled) {
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
+ return -ESHUTDOWN;
+ }
+
/* pick the first one */
list = list_first_entry(&hidg->completed_out_req,
struct f_hidg_req_list, list);
@@ -387,7 +378,7 @@ static ssize_t f_hidg_intout_read(struct file *file, char __user *buffer,
return count;
}
-#define READ_COND_SSREPORT (hidg->set_report_buf != NULL)
+#define READ_COND_SSREPORT (hidg->set_report_buf != NULL || hidg->disabled)
static ssize_t f_hidg_ssreport_read(struct file *file, char __user *buffer,
size_t count, loff_t *ptr)
@@ -1012,6 +1003,11 @@ static void hidg_disable(struct usb_function *f)
}
spin_unlock_irqrestore(&hidg->get_report_spinlock, flags);
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
+ hidg->disabled = true;
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
+ wake_up(&hidg->read_queue);
+
spin_lock_irqsave(&hidg->write_spinlock, flags);
if (!hidg->write_pending) {
free_ep_req(hidg->in_ep, hidg->req);
@@ -1097,6 +1093,10 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
}
}
+ spin_lock_irqsave(&hidg->read_spinlock, flags);
+ hidg->disabled = false;
+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
+
if (hidg->in_ep != NULL) {
spin_lock_irqsave(&hidg->write_spinlock, flags);
hidg->req = req_in;
@@ -1202,6 +1202,16 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
hidg_ss_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+
+ /* IN endpoints: FS default=10ms, HS default=4µ-frame; user override if set */
+ if (!hidg->interval_user_set) {
+ hidg_fs_in_ep_desc.bInterval = 10;
+ hidg_hs_in_ep_desc.bInterval = 4;
+ } else {
+ hidg_fs_in_ep_desc.bInterval = hidg->interval;
+ hidg_hs_in_ep_desc.bInterval = hidg->interval;
+ }
+
hidg_ss_out_comp_desc.wBytesPerInterval =
cpu_to_le16(hidg->report_length);
hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
@@ -1224,19 +1234,27 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
hidg_ss_out_ep_desc.bEndpointAddress =
hidg_fs_out_ep_desc.bEndpointAddress;
- if (hidg->use_out_ep)
+ if (hidg->use_out_ep) {
+ /* OUT endpoints: same defaults (FS=10, HS=4) unless user set */
+ if (!hidg->interval_user_set) {
+ hidg_fs_out_ep_desc.bInterval = 10;
+ hidg_hs_out_ep_desc.bInterval = 4;
+ } else {
+ hidg_fs_out_ep_desc.bInterval = hidg->interval;
+ hidg_hs_out_ep_desc.bInterval = hidg->interval;
+ }
status = usb_assign_descriptors(f,
- hidg_fs_descriptors_intout,
- hidg_hs_descriptors_intout,
- hidg_ss_descriptors_intout,
- hidg_ss_descriptors_intout);
- else
+ hidg_fs_descriptors_intout,
+ hidg_hs_descriptors_intout,
+ hidg_ss_descriptors_intout,
+ hidg_ss_descriptors_intout);
+ } else {
status = usb_assign_descriptors(f,
hidg_fs_descriptors_ssreport,
hidg_hs_descriptors_ssreport,
hidg_ss_descriptors_ssreport,
hidg_ss_descriptors_ssreport);
-
+ }
if (status)
goto fail;
@@ -1408,6 +1426,53 @@ end:
CONFIGFS_ATTR(f_hid_opts_, report_desc);
+static ssize_t f_hid_opts_interval_show(struct config_item *item, char *page)
+{
+ struct f_hid_opts *opts = to_f_hid_opts(item);
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%d\n", opts->interval);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_hid_opts_interval_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_hid_opts *opts = to_f_hid_opts(item);
+ int ret;
+ unsigned int tmp;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ /* parse into a wider type first */
+ ret = kstrtouint(page, 0, &tmp);
+ if (ret)
+ goto end;
+
+ /* range-check against unsigned char max */
+ if (tmp > 255) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ opts->interval = (unsigned char)tmp;
+ opts->interval_user_set = true;
+ ret = len;
+
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+CONFIGFS_ATTR(f_hid_opts_, interval);
+
static ssize_t f_hid_opts_dev_show(struct config_item *item, char *page)
{
struct f_hid_opts *opts = to_f_hid_opts(item);
@@ -1422,6 +1487,7 @@ static struct configfs_attribute *hid_attrs[] = {
&f_hid_opts_attr_protocol,
&f_hid_opts_attr_no_out_endpoint,
&f_hid_opts_attr_report_length,
+ &f_hid_opts_attr_interval,
&f_hid_opts_attr_report_desc,
&f_hid_opts_attr_dev,
NULL,
@@ -1468,6 +1534,10 @@ static struct usb_function_instance *hidg_alloc_inst(void)
if (!opts)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
+
+ opts->interval = 4;
+ opts->interval_user_set = false;
+
opts->func_inst.free_func_inst = hidg_free_inst;
ret = &opts->func_inst;
@@ -1546,6 +1616,8 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
hidg->bInterfaceProtocol = opts->protocol;
hidg->report_length = opts->report_length;
hidg->report_desc_length = opts->report_desc_length;
+ hidg->interval = opts->interval;
+ hidg->interval_user_set = opts->interval_user_set;
if (opts->report_desc) {
hidg->report_desc = kmemdup(opts->report_desc,
opts->report_desc_length,
diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h
index 3b8c4ce2a40a..82ecd3fedb3a 100644
--- a/drivers/usb/gadget/function/f_mass_storage.h
+++ b/drivers/usb/gadget/function/f_mass_storage.h
@@ -110,7 +110,7 @@ struct fsg_config {
};
static inline struct fsg_opts *
-fsg_opts_from_func_inst(const struct usb_function_instance *fi)
+fsg_opts_from_func_inst(struct usb_function_instance *fi)
{
return container_of(fi, struct fsg_opts, func_inst);
}
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index 8f7e7a2b2ff2..0f266bc067f5 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -364,6 +364,12 @@ static void gser_suspend(struct usb_function *f)
gserial_suspend(&gser->port);
}
+static int gser_get_status(struct usb_function *f)
+{
+ return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) |
+ USB_INTRF_STAT_FUNC_RW_CAP;
+}
+
static struct usb_function *gser_alloc(struct usb_function_instance *fi)
{
struct f_gser *gser;
@@ -387,6 +393,7 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
gser->port.func.free_func = gser_free;
gser->port.func.resume = gser_resume;
gser->port.func.suspend = gser_suspend;
+ gser->port.func.get_status = gser_get_status;
return &gser->port.func;
}
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index 5a2e1237f85c..6e8804f04baa 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1641,14 +1641,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
tport_wwn);
struct usbg_tpg *tpg;
- unsigned long tpgt;
+ u16 tpgt;
int ret;
struct f_tcm_opts *opts;
unsigned i;
if (strstr(name, "tpgt_") != name)
return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+ if (kstrtou16(name + 5, 0, &tpgt))
return ERR_PTR(-EINVAL);
ret = -ENODEV;
mutex_lock(&tpg_instances_lock);
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
index 84bb70292855..a9ed9720caee 100644
--- a/drivers/usb/gadget/function/u_hid.h
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -25,6 +25,8 @@ struct f_hid_opts {
unsigned short report_desc_length;
unsigned char *report_desc;
bool report_desc_alloc;
+ unsigned char interval;
+ bool interval_user_set;
/*
* Protect the data form concurrent access by read/write
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 36fff45e8c9b..ab544f6824be 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -592,6 +592,17 @@ static int gs_start_io(struct gs_port *port)
return status;
}
+static int gserial_wakeup_host(struct gserial *gser)
+{
+ struct usb_function *func = &gser->func;
+ struct usb_gadget *gadget = func->config->cdev->gadget;
+
+ if (func->func_suspended)
+ return usb_func_wakeup(func);
+ else
+ return usb_gadget_wakeup(gadget);
+}
+
/*-------------------------------------------------------------------------*/
/* TTY Driver */
@@ -746,6 +757,8 @@ static ssize_t gs_write(struct tty_struct *tty, const u8 *buf, size_t count)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
+ int ret = 0;
+ struct gserial *gser = port->port_usb;
pr_vdebug("gs_write: ttyGS%d (%p) writing %zu bytes\n",
port->port_num, tty, count);
@@ -753,6 +766,17 @@ static ssize_t gs_write(struct tty_struct *tty, const u8 *buf, size_t count)
spin_lock_irqsave(&port->port_lock, flags);
if (count)
count = kfifo_in(&port->port_write_buf, buf, count);
+
+ if (port->suspended) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = gserial_wakeup_host(gser);
+ if (ret) {
+ pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret);
+ return count;
+ }
+ spin_lock_irqsave(&port->port_lock, flags);
+ }
+
/* treat count == 0 as flush_chars() */
if (port->port_usb)
gs_start_tx(port);
@@ -781,10 +805,22 @@ static void gs_flush_chars(struct tty_struct *tty)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
+ int ret = 0;
+ struct gserial *gser = port->port_usb;
pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
spin_lock_irqsave(&port->port_lock, flags);
+ if (port->suspended) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = gserial_wakeup_host(gser);
+ if (ret) {
+ pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret);
+ return;
+ }
+ spin_lock_irqsave(&port->port_lock, flags);
+ }
+
if (port->port_usb)
gs_start_tx(port);
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -1464,6 +1500,20 @@ void gserial_suspend(struct gserial *gser)
return;
}
+ if (port->write_busy || port->write_started) {
+ /* Wakeup to host if there are ongoing transfers */
+ spin_unlock_irqrestore(&serial_port_lock, flags);
+ if (!gserial_wakeup_host(gser))
+ return;
+
+ /* Check if port is valid after acquiring lock back */
+ spin_lock_irqsave(&serial_port_lock, flags);
+ if (!port) {
+ spin_unlock_irqrestore(&serial_port_lock, flags);
+ return;
+ }
+ }
+
spin_lock(&port->port_lock);
spin_unlock(&serial_port_lock);
port->suspended = true;
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
index 2f78cd4f396f..9391614135e9 100644
--- a/drivers/usb/gadget/function/uvc_configfs.h
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -74,10 +74,12 @@ static inline struct uvcg_format *to_uvcg_format(struct config_item *item)
struct uvcg_streaming_header {
struct config_item item;
- struct uvc_input_header_descriptor desc;
unsigned linked;
struct list_head formats;
unsigned num_fmt;
+
+ /* Must be last --ends in a flexible-array member. */
+ struct uvc_input_header_descriptor desc;
};
static inline struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c
index a9544fea8723..578556422ea3 100644
--- a/drivers/usb/gadget/legacy/g_ffs.c
+++ b/drivers/usb/gadget/legacy/g_ffs.c
@@ -188,7 +188,7 @@ static int __init gfs_init(void)
/*
* Allocate in one chunk for easier maintenance
*/
- f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL);
+ f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs[0]), GFP_KERNEL);
if (!f_ffs[0]) {
ret = -ENOMEM;
goto no_func;
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index b6a30d88a800..fcce84a726f2 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1615,7 +1615,7 @@ static int activate_ep_files (struct dev_data *dev)
mutex_init(&data->lock);
init_waitqueue_head (&data->wait);
- strncpy (data->name, ep->name, sizeof (data->name) - 1);
+ strscpy(data->name, ep->name);
refcount_set (&data->count, 1);
data->dev = dev;
get_dev (dev);
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index aae1787320d4..26460340fbc9 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -102,12 +102,6 @@ config USB_FSL_USB2
dynamically linked module called "fsl_usb2_udc" and force
all gadget drivers to also be dynamically linked.
-config USB_FUSB300
- tristate "Faraday FUSB300 USB Peripheral Controller"
- depends on !PHYS_ADDR_T_64BIT && HAS_DMA
- help
- Faraday usb device controller FUSB300 driver
-
config USB_GR_UDC
tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
depends on HAS_DMA
@@ -228,21 +222,6 @@ config USB_PXA27X
dynamically linked module called "pxa27x_udc" and force all
gadget drivers to also be dynamically linked.
-config USB_MV_UDC
- tristate "Marvell USB2.0 Device Controller"
- depends on HAS_DMA
- help
- Marvell Socs (including PXA and MMP series) include a high speed
- USB2.0 OTG controller, which can be configured as high speed or
- full speed USB peripheral.
-
-config USB_MV_U3D
- depends on HAS_DMA
- tristate "MARVELL PXA2128 USB 3.0 controller"
- help
- MARVELL PXA2128 Processor series include a super speed USB3.0 device
- controller, which support super speed USB peripheral.
-
config USB_SNP_CORE
depends on (USB_AMD5536UDC || USB_SNP_UDC_PLAT)
depends on HAS_DMA
@@ -326,29 +305,6 @@ config USB_FSL_QE
Set CONFIG_USB_GADGET to "m" to build this driver as a
dynamically linked module called "fsl_qe_udc".
-config USB_NET2272
- depends on HAS_IOMEM
- tristate "PLX NET2272"
- help
- PLX NET2272 is a USB peripheral controller which supports
- both full and high speed USB 2.0 data transfers.
-
- It has three configurable endpoints, as well as endpoint zero
- (for control transfer).
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "net2272" and force all
- gadget drivers to also be dynamically linked.
-
-config USB_NET2272_DMA
- bool "Support external DMA controller"
- depends on USB_NET2272 && HAS_DMA
- help
- The NET2272 part can optionally support an external DMA
- controller, but your board has to have support in the
- driver itself.
-
- If unsure, say "N" here. The driver works fine in PIO mode.
-
config USB_NET2280
tristate "NetChip NET228x / PLX USB3x8x"
depends on USB_PCI
diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
index b52f93e9c61d..1b9b1a4f9c57 100644
--- a/drivers/usb/gadget/udc/Makefile
+++ b/drivers/usb/gadget/udc/Makefile
@@ -9,7 +9,6 @@ udc-core-y := core.o trace.o
#
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
-obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_SNP_CORE) += snps_udc_core.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc_pci.o
@@ -31,10 +30,6 @@ obj-$(CONFIG_USB_RENESAS_USBF) += renesas_usbf.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
-obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
-mv_udc-y := mv_udc_core.o
-obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
-obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o
obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 4b3d5075621a..d709e24c1fd4 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1570,7 +1570,7 @@ static int gadget_match_driver(struct device *dev, const struct device_driver *d
{
struct usb_gadget *gadget = dev_to_usb_gadget(dev);
struct usb_udc *udc = gadget->udc;
- struct usb_gadget_driver *driver = container_of(drv,
+ const struct usb_gadget_driver *driver = container_of(drv,
struct usb_gadget_driver, driver);
/* If the driver specifies a udc_name, it must match the UDC's name */
diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c
deleted file mode 100644
index 5e94a99b3e53..000000000000
--- a/drivers/usb/gadget/udc/fusb300_udc.c
+++ /dev/null
@@ -1,1516 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Fusb300 UDC (USB gadget)
- *
- * Copyright (C) 2010 Faraday Technology Corp.
- *
- * Author : Yuan-hsin Chen <yhchen@faraday-tech.com>
- */
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include "fusb300_udc.h"
-
-MODULE_DESCRIPTION("FUSB300 USB gadget driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");
-MODULE_ALIAS("platform:fusb300_udc");
-
-#define DRIVER_VERSION "20 October 2010"
-
-static const char udc_name[] = "fusb300_udc";
-static const char * const fusb300_ep_name[] = {
- "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9",
- "ep10", "ep11", "ep12", "ep13", "ep14", "ep15"
-};
-
-static void done(struct fusb300_ep *ep, struct fusb300_request *req,
- int status);
-
-static void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset,
- u32 value)
-{
- u32 reg = ioread32(fusb300->reg + offset);
-
- reg |= value;
- iowrite32(reg, fusb300->reg + offset);
-}
-
-static void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset,
- u32 value)
-{
- u32 reg = ioread32(fusb300->reg + offset);
-
- reg &= ~value;
- iowrite32(reg, fusb300->reg + offset);
-}
-
-
-static void fusb300_ep_setting(struct fusb300_ep *ep,
- struct fusb300_ep_info info)
-{
- ep->epnum = info.epnum;
- ep->type = info.type;
-}
-
-static int fusb300_ep_release(struct fusb300_ep *ep)
-{
- if (!ep->epnum)
- return 0;
- ep->epnum = 0;
- ep->stall = 0;
- ep->wedged = 0;
- return 0;
-}
-
-static void fusb300_set_fifo_entry(struct fusb300 *fusb300,
- u32 ep)
-{
- u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
-
- val &= ~FUSB300_EPSET1_FIFOENTRY_MSK;
- val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM);
- iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
-}
-
-static void fusb300_set_start_entry(struct fusb300 *fusb300,
- u8 ep)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
- u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM;
-
- reg &= ~FUSB300_EPSET1_START_ENTRY_MSK ;
- reg |= FUSB300_EPSET1_START_ENTRY(start_entry);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
- if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) {
- fusb300->fifo_entry_num = 0;
- fusb300->addrofs = 0;
- pr_err("fifo entry is over the maximum number!\n");
- } else
- fusb300->fifo_entry_num++;
-}
-
-/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */
-static void fusb300_set_epaddrofs(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
-
- reg &= ~FUSB300_EPSET2_ADDROFS_MSK;
- reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
- fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM;
-}
-
-static void ep_fifo_setting(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- fusb300_set_fifo_entry(fusb300, info.epnum);
- fusb300_set_start_entry(fusb300, info.epnum);
- fusb300_set_epaddrofs(fusb300, info);
-}
-
-static void fusb300_set_eptype(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-
- reg &= ~FUSB300_EPSET1_TYPE_MSK;
- reg |= FUSB300_EPSET1_TYPE(info.type);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-}
-
-static void fusb300_set_epdir(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg;
-
- if (!info.dir_in)
- return;
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
- reg &= ~FUSB300_EPSET1_DIR_MSK;
- reg |= FUSB300_EPSET1_DIRIN;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-}
-
-static void fusb300_set_ep_active(struct fusb300 *fusb300,
- u8 ep)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
-
- reg |= FUSB300_EPSET1_ACTEN;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep));
-}
-
-static void fusb300_set_epmps(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
-
- reg &= ~FUSB300_EPSET2_MPS_MSK;
- reg |= FUSB300_EPSET2_MPS(info.maxpacket);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum));
-}
-
-static void fusb300_set_interval(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-
- reg &= ~FUSB300_EPSET1_INTERVAL(0x7);
- reg |= FUSB300_EPSET1_INTERVAL(info.interval);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-}
-
-static void fusb300_set_bwnum(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-
- reg &= ~FUSB300_EPSET1_BWNUM(0x3);
- reg |= FUSB300_EPSET1_BWNUM(info.bw_num);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum));
-}
-
-static void set_ep_reg(struct fusb300 *fusb300,
- struct fusb300_ep_info info)
-{
- fusb300_set_eptype(fusb300, info);
- fusb300_set_epdir(fusb300, info);
- fusb300_set_epmps(fusb300, info);
-
- if (info.interval)
- fusb300_set_interval(fusb300, info);
-
- if (info.bw_num)
- fusb300_set_bwnum(fusb300, info);
-
- fusb300_set_ep_active(fusb300, info.epnum);
-}
-
-static int config_ep(struct fusb300_ep *ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct fusb300 *fusb300 = ep->fusb300;
- struct fusb300_ep_info info;
-
- ep->ep.desc = desc;
-
- info.interval = 0;
- info.addrofs = 0;
- info.bw_num = 0;
-
- info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
- info.maxpacket = usb_endpoint_maxp(desc);
- info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-
- if ((info.type == USB_ENDPOINT_XFER_INT) ||
- (info.type == USB_ENDPOINT_XFER_ISOC)) {
- info.interval = desc->bInterval;
- if (info.type == USB_ENDPOINT_XFER_ISOC)
- info.bw_num = usb_endpoint_maxp_mult(desc);
- }
-
- ep_fifo_setting(fusb300, info);
-
- set_ep_reg(fusb300, info);
-
- fusb300_ep_setting(ep, info);
-
- fusb300->ep[info.epnum] = ep;
-
- return 0;
-}
-
-static int fusb300_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct fusb300_ep *ep;
-
- ep = container_of(_ep, struct fusb300_ep, ep);
-
- if (ep->fusb300->reenum) {
- ep->fusb300->fifo_entry_num = 0;
- ep->fusb300->addrofs = 0;
- ep->fusb300->reenum = 0;
- }
-
- return config_ep(ep, desc);
-}
-
-static int fusb300_disable(struct usb_ep *_ep)
-{
- struct fusb300_ep *ep;
- struct fusb300_request *req;
- unsigned long flags;
-
- ep = container_of(_ep, struct fusb300_ep, ep);
-
- BUG_ON(!ep);
-
- while (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next, struct fusb300_request, queue);
- spin_lock_irqsave(&ep->fusb300->lock, flags);
- done(ep, req, -ECONNRESET);
- spin_unlock_irqrestore(&ep->fusb300->lock, flags);
- }
-
- return fusb300_ep_release(ep);
-}
-
-static struct usb_request *fusb300_alloc_request(struct usb_ep *_ep,
- gfp_t gfp_flags)
-{
- struct fusb300_request *req;
-
- req = kzalloc(sizeof(struct fusb300_request), gfp_flags);
- if (!req)
- return NULL;
- INIT_LIST_HEAD(&req->queue);
-
- return &req->req;
-}
-
-static void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct fusb300_request *req;
-
- req = container_of(_req, struct fusb300_request, req);
- kfree(req);
-}
-
-static int enable_fifo_int(struct fusb300_ep *ep)
-{
- struct fusb300 *fusb300 = ep->fusb300;
-
- if (ep->epnum) {
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0,
- FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
- } else {
- pr_err("can't enable_fifo_int ep0\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int disable_fifo_int(struct fusb300_ep *ep)
-{
- struct fusb300 *fusb300 = ep->fusb300;
-
- if (ep->epnum) {
- fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0,
- FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum));
- } else {
- pr_err("can't disable_fifo_int ep0\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length)
-{
- u32 reg;
-
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
- reg &= ~FUSB300_CSR_LEN_MSK;
- reg |= FUSB300_CSR_LEN(length);
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR);
-}
-
-/* write data to cx fifo */
-static void fusb300_wrcxf(struct fusb300_ep *ep,
- struct fusb300_request *req)
-{
- int i = 0;
- u8 *tmp;
- u32 data;
- struct fusb300 *fusb300 = ep->fusb300;
- u32 length = req->req.length - req->req.actual;
-
- tmp = req->req.buf + req->req.actual;
-
- if (length > SS_CTL_MAX_PACKET_SIZE) {
- fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE);
- for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) {
- data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
- *(tmp + 3) << 24;
- iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
- tmp += 4;
- }
- req->req.actual += SS_CTL_MAX_PACKET_SIZE;
- } else { /* length is less than max packet size */
- fusb300_set_cxlen(fusb300, length);
- for (i = length >> 2; i > 0; i--) {
- data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 |
- *(tmp + 3) << 24;
- printk(KERN_DEBUG " 0x%x\n", data);
- iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
- tmp = tmp + 4;
- }
- switch (length % 4) {
- case 1:
- data = *tmp;
- printk(KERN_DEBUG " 0x%x\n", data);
- iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
- break;
- case 2:
- data = *tmp | *(tmp + 1) << 8;
- printk(KERN_DEBUG " 0x%x\n", data);
- iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
- break;
- case 3:
- data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
- printk(KERN_DEBUG " 0x%x\n", data);
- iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT);
- break;
- default:
- break;
- }
- req->req.actual += length;
- }
-}
-
-static void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep)
-{
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
- FUSB300_EPSET0_STL);
-}
-
-static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
-
- if (reg & FUSB300_EPSET0_STL) {
- printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
- reg |= FUSB300_EPSET0_STL_CLR;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
- }
-}
-
-static void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req)
-{
- if (ep->fusb300->ep0_dir) { /* if IN */
- if (req->req.length) {
- fusb300_wrcxf(ep, req);
- } else
- printk(KERN_DEBUG "%s : req->req.length = 0x%x\n",
- __func__, req->req.length);
- if ((req->req.length == req->req.actual) ||
- (req->req.actual < ep->ep.maxpacket))
- done(ep, req, 0);
- } else { /* OUT */
- if (!req->req.length)
- done(ep, req, 0);
- else
- fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1,
- FUSB300_IGER1_CX_OUT_INT);
- }
-}
-
-static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req,
- gfp_t gfp_flags)
-{
- struct fusb300_ep *ep;
- struct fusb300_request *req;
- unsigned long flags;
- int request = 0;
-
- ep = container_of(_ep, struct fusb300_ep, ep);
- req = container_of(_req, struct fusb300_request, req);
-
- if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- spin_lock_irqsave(&ep->fusb300->lock, flags);
-
- if (list_empty(&ep->queue))
- request = 1;
-
- list_add_tail(&req->queue, &ep->queue);
-
- req->req.actual = 0;
- req->req.status = -EINPROGRESS;
-
- if (ep->ep.desc == NULL) /* ep0 */
- ep0_queue(ep, req);
- else if (request && !ep->stall)
- enable_fifo_int(ep);
-
- spin_unlock_irqrestore(&ep->fusb300->lock, flags);
-
- return 0;
-}
-
-static int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct fusb300_ep *ep;
- struct fusb300_request *req;
- unsigned long flags;
-
- ep = container_of(_ep, struct fusb300_ep, ep);
- req = container_of(_req, struct fusb300_request, req);
-
- spin_lock_irqsave(&ep->fusb300->lock, flags);
- if (!list_empty(&ep->queue))
- done(ep, req, -ECONNRESET);
- spin_unlock_irqrestore(&ep->fusb300->lock, flags);
-
- return 0;
-}
-
-static int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
-{
- struct fusb300_ep *ep;
- struct fusb300 *fusb300;
- unsigned long flags;
- int ret = 0;
-
- ep = container_of(_ep, struct fusb300_ep, ep);
-
- fusb300 = ep->fusb300;
-
- spin_lock_irqsave(&ep->fusb300->lock, flags);
-
- if (!list_empty(&ep->queue)) {
- ret = -EAGAIN;
- goto out;
- }
-
- if (value) {
- fusb300_set_epnstall(fusb300, ep->epnum);
- ep->stall = 1;
- if (wedge)
- ep->wedged = 1;
- } else {
- fusb300_clear_epnstall(fusb300, ep->epnum);
- ep->stall = 0;
- ep->wedged = 0;
- }
-
-out:
- spin_unlock_irqrestore(&ep->fusb300->lock, flags);
- return ret;
-}
-
-static int fusb300_set_halt(struct usb_ep *_ep, int value)
-{
- return fusb300_set_halt_and_wedge(_ep, value, 0);
-}
-
-static int fusb300_set_wedge(struct usb_ep *_ep)
-{
- return fusb300_set_halt_and_wedge(_ep, 1, 1);
-}
-
-static void fusb300_fifo_flush(struct usb_ep *_ep)
-{
-}
-
-static const struct usb_ep_ops fusb300_ep_ops = {
- .enable = fusb300_enable,
- .disable = fusb300_disable,
-
- .alloc_request = fusb300_alloc_request,
- .free_request = fusb300_free_request,
-
- .queue = fusb300_queue,
- .dequeue = fusb300_dequeue,
-
- .set_halt = fusb300_set_halt,
- .fifo_flush = fusb300_fifo_flush,
- .set_wedge = fusb300_set_wedge,
-};
-
-/*****************************************************************************/
-static void fusb300_clear_int(struct fusb300 *fusb300, u32 offset,
- u32 value)
-{
- iowrite32(value, fusb300->reg + offset);
-}
-
-static void fusb300_reset(void)
-{
-}
-
-static void fusb300_set_cxstall(struct fusb300 *fusb300)
-{
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
- FUSB300_CSR_STL);
-}
-
-static void fusb300_set_cxdone(struct fusb300 *fusb300)
-{
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR,
- FUSB300_CSR_DONE);
-}
-
-/* read data from cx fifo */
-static void fusb300_rdcxf(struct fusb300 *fusb300,
- u8 *buffer, u32 length)
-{
- int i = 0;
- u8 *tmp;
- u32 data;
-
- tmp = buffer;
-
- for (i = (length >> 2); i > 0; i--) {
- data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
- printk(KERN_DEBUG " 0x%x\n", data);
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- *(tmp + 2) = (data >> 16) & 0xFF;
- *(tmp + 3) = (data >> 24) & 0xFF;
- tmp = tmp + 4;
- }
-
- switch (length % 4) {
- case 1:
- data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
- printk(KERN_DEBUG " 0x%x\n", data);
- *tmp = data & 0xFF;
- break;
- case 2:
- data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
- printk(KERN_DEBUG " 0x%x\n", data);
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- break;
- case 3:
- data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT);
- printk(KERN_DEBUG " 0x%x\n", data);
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- *(tmp + 2) = (data >> 16) & 0xFF;
- break;
- default:
- break;
- }
-}
-
-static void fusb300_rdfifo(struct fusb300_ep *ep,
- struct fusb300_request *req,
- u32 length)
-{
- int i = 0;
- u8 *tmp;
- u32 data, reg;
- struct fusb300 *fusb300 = ep->fusb300;
-
- tmp = req->req.buf + req->req.actual;
- req->req.actual += length;
-
- if (req->req.actual > req->req.length)
- printk(KERN_DEBUG "req->req.actual > req->req.length\n");
-
- for (i = (length >> 2); i > 0; i--) {
- data = ioread32(fusb300->reg +
- FUSB300_OFFSET_EPPORT(ep->epnum));
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- *(tmp + 2) = (data >> 16) & 0xFF;
- *(tmp + 3) = (data >> 24) & 0xFF;
- tmp = tmp + 4;
- }
-
- switch (length % 4) {
- case 1:
- data = ioread32(fusb300->reg +
- FUSB300_OFFSET_EPPORT(ep->epnum));
- *tmp = data & 0xFF;
- break;
- case 2:
- data = ioread32(fusb300->reg +
- FUSB300_OFFSET_EPPORT(ep->epnum));
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- break;
- case 3:
- data = ioread32(fusb300->reg +
- FUSB300_OFFSET_EPPORT(ep->epnum));
- *tmp = data & 0xFF;
- *(tmp + 1) = (data >> 8) & 0xFF;
- *(tmp + 2) = (data >> 16) & 0xFF;
- break;
- default:
- break;
- }
-
- do {
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
- reg &= FUSB300_IGR1_SYNF0_EMPTY_INT;
- if (i)
- printk(KERN_INFO "sync fifo is not empty!\n");
- i++;
- } while (!reg);
-}
-
-static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
-{
- u8 value;
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
-
- value = reg & FUSB300_EPSET0_STL;
-
- return value;
-}
-
-static u8 fusb300_get_cxstall(struct fusb300 *fusb300)
-{
- u8 value;
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR);
-
- value = (reg & FUSB300_CSR_STL) >> 1;
-
- return value;
-}
-
-static void request_error(struct fusb300 *fusb300)
-{
- fusb300_set_cxstall(fusb300);
- printk(KERN_DEBUG "request error!!\n");
-}
-
-static void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
-__releases(fusb300->lock)
-__acquires(fusb300->lock)
-{
- u8 ep;
- u16 status = 0;
- u16 w_index = ctrl->wIndex;
-
- switch (ctrl->bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_DEVICE:
- status = 1 << USB_DEVICE_SELF_POWERED;
- break;
- case USB_RECIP_INTERFACE:
- status = 0;
- break;
- case USB_RECIP_ENDPOINT:
- ep = w_index & USB_ENDPOINT_NUMBER_MASK;
- if (ep) {
- if (fusb300_get_epnstall(fusb300, ep))
- status = 1 << USB_ENDPOINT_HALT;
- } else {
- if (fusb300_get_cxstall(fusb300))
- status = 0;
- }
- break;
-
- default:
- request_error(fusb300);
- return; /* exit */
- }
-
- fusb300->ep0_data = cpu_to_le16(status);
- fusb300->ep0_req->buf = &fusb300->ep0_data;
- fusb300->ep0_req->length = 2;
-
- spin_unlock(&fusb300->lock);
- fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL);
- spin_lock(&fusb300->lock);
-}
-
-static void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
-{
- u8 ep;
-
- switch (ctrl->bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_DEVICE:
- fusb300_set_cxdone(fusb300);
- break;
- case USB_RECIP_INTERFACE:
- fusb300_set_cxdone(fusb300);
- break;
- case USB_RECIP_ENDPOINT: {
- u16 w_index = le16_to_cpu(ctrl->wIndex);
-
- ep = w_index & USB_ENDPOINT_NUMBER_MASK;
- if (ep)
- fusb300_set_epnstall(fusb300, ep);
- else
- fusb300_set_cxstall(fusb300);
- fusb300_set_cxdone(fusb300);
- }
- break;
- default:
- request_error(fusb300);
- break;
- }
-}
-
-static void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep)
-{
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep),
- FUSB300_EPSET0_CLRSEQNUM);
-}
-
-static void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
-{
- struct fusb300_ep *ep =
- fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK];
-
- switch (ctrl->bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_DEVICE:
- fusb300_set_cxdone(fusb300);
- break;
- case USB_RECIP_INTERFACE:
- fusb300_set_cxdone(fusb300);
- break;
- case USB_RECIP_ENDPOINT:
- if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) {
- if (ep->wedged) {
- fusb300_set_cxdone(fusb300);
- break;
- }
- if (ep->stall) {
- ep->stall = 0;
- fusb300_clear_seqnum(fusb300, ep->epnum);
- fusb300_clear_epnstall(fusb300, ep->epnum);
- if (!list_empty(&ep->queue))
- enable_fifo_int(ep);
- }
- }
- fusb300_set_cxdone(fusb300);
- break;
- default:
- request_error(fusb300);
- break;
- }
-}
-
-static void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR);
-
- reg &= ~FUSB300_DAR_DRVADDR_MSK;
- reg |= FUSB300_DAR_DRVADDR(addr);
-
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR);
-}
-
-static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
-{
- if (ctrl->wValue >= 0x0100)
- request_error(fusb300);
- else {
- fusb300_set_dev_addr(fusb300, ctrl->wValue);
- fusb300_set_cxdone(fusb300);
- }
-}
-
-#define UVC_COPY_DESCRIPTORS(mem, src) \
- do { \
- const struct usb_descriptor_header * const *__src; \
- for (__src = src; *__src; ++__src) { \
- memcpy(mem, *__src, (*__src)->bLength); \
- mem += (*__src)->bLength; \
- } \
- } while (0)
-
-static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
-{
- u8 *p = (u8 *)ctrl;
- u8 ret = 0;
- u8 i = 0;
-
- fusb300_rdcxf(fusb300, p, 8);
- fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN;
- fusb300->ep0_length = ctrl->wLength;
-
- /* check request */
- if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- switch (ctrl->bRequest) {
- case USB_REQ_GET_STATUS:
- get_status(fusb300, ctrl);
- break;
- case USB_REQ_CLEAR_FEATURE:
- clear_feature(fusb300, ctrl);
- break;
- case USB_REQ_SET_FEATURE:
- set_feature(fusb300, ctrl);
- break;
- case USB_REQ_SET_ADDRESS:
- set_address(fusb300, ctrl);
- break;
- case USB_REQ_SET_CONFIGURATION:
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR,
- FUSB300_DAR_SETCONFG);
- /* clear sequence number */
- for (i = 1; i <= FUSB300_MAX_NUM_EP; i++)
- fusb300_clear_seqnum(fusb300, i);
- fusb300->reenum = 1;
- ret = 1;
- break;
- default:
- ret = 1;
- break;
- }
- } else
- ret = 1;
-
- return ret;
-}
-
-static void done(struct fusb300_ep *ep, struct fusb300_request *req,
- int status)
-{
- list_del_init(&req->queue);
-
- /* don't modify queue heads during completion callback */
- if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN)
- req->req.status = -ESHUTDOWN;
- else
- req->req.status = status;
-
- spin_unlock(&ep->fusb300->lock);
- usb_gadget_giveback_request(&ep->ep, &req->req);
- spin_lock(&ep->fusb300->lock);
-
- if (ep->epnum) {
- disable_fifo_int(ep);
- if (!list_empty(&ep->queue))
- enable_fifo_int(ep);
- } else
- fusb300_set_cxdone(ep->fusb300);
-}
-
-static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d,
- u32 len)
-{
- u32 value;
- u32 reg;
-
- /* wait SW owner */
- do {
- reg = ioread32(ep->fusb300->reg +
- FUSB300_OFFSET_EPPRD_W0(ep->epnum));
- reg &= FUSB300_EPPRD0_H;
- } while (reg);
-
- iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum));
-
- value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |
- FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
- iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
-
- iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum));
-
- fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY,
- FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum));
-}
-
-static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
-{
- u32 reg;
-
- do {
- reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1);
- if ((reg & FUSB300_IGR1_VBUS_CHG_INT) ||
- (reg & FUSB300_IGR1_WARM_RST_INT) ||
- (reg & FUSB300_IGR1_HOT_RST_INT) ||
- (reg & FUSB300_IGR1_USBRST_INT)
- )
- goto IDMA_RESET;
- reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0);
- reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum);
- } while (!reg);
-
- fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
- FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
- return;
-
-IDMA_RESET:
- reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
- reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
- iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
-}
-
-static void fusb300_set_idma(struct fusb300_ep *ep,
- struct fusb300_request *req)
-{
- int ret;
-
- ret = usb_gadget_map_request(&ep->fusb300->gadget,
- &req->req, DMA_TO_DEVICE);
- if (ret)
- return;
-
- fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
- FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
-
- fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
- /* check idma is done */
- fusb300_wait_idma_finished(ep);
-
- usb_gadget_unmap_request(&ep->fusb300->gadget,
- &req->req, DMA_TO_DEVICE);
-}
-
-static void in_ep_fifo_handler(struct fusb300_ep *ep)
-{
- struct fusb300_request *req = list_entry(ep->queue.next,
- struct fusb300_request, queue);
-
- if (req->req.length)
- fusb300_set_idma(ep, req);
- done(ep, req, 0);
-}
-
-static void out_ep_fifo_handler(struct fusb300_ep *ep)
-{
- struct fusb300 *fusb300 = ep->fusb300;
- struct fusb300_request *req = list_entry(ep->queue.next,
- struct fusb300_request, queue);
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
- u32 length = reg & FUSB300_FFR_BYCNT;
-
- fusb300_rdfifo(ep, req, length);
-
- /* finish out transfer */
- if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket))
- done(ep, req, 0);
-}
-
-static void check_device_mode(struct fusb300 *fusb300)
-{
- u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR);
-
- switch (reg & FUSB300_GCR_DEVEN_MSK) {
- case FUSB300_GCR_DEVEN_SS:
- fusb300->gadget.speed = USB_SPEED_SUPER;
- break;
- case FUSB300_GCR_DEVEN_HS:
- fusb300->gadget.speed = USB_SPEED_HIGH;
- break;
- case FUSB300_GCR_DEVEN_FS:
- fusb300->gadget.speed = USB_SPEED_FULL;
- break;
- default:
- fusb300->gadget.speed = USB_SPEED_UNKNOWN;
- break;
- }
- printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK));
-}
-
-
-static void fusb300_ep0out(struct fusb300 *fusb300)
-{
- struct fusb300_ep *ep = fusb300->ep[0];
- u32 reg;
-
- if (!list_empty(&ep->queue)) {
- struct fusb300_request *req;
-
- req = list_first_entry(&ep->queue,
- struct fusb300_request, queue);
- if (req->req.length)
- fusb300_rdcxf(ep->fusb300, req->req.buf,
- req->req.length);
- done(ep, req, 0);
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
- reg &= ~FUSB300_IGER1_CX_OUT_INT;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1);
- } else
- pr_err("%s : empty queue\n", __func__);
-}
-
-static void fusb300_ep0in(struct fusb300 *fusb300)
-{
- struct fusb300_request *req;
- struct fusb300_ep *ep = fusb300->ep[0];
-
- if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) {
- req = list_entry(ep->queue.next,
- struct fusb300_request, queue);
- if (req->req.length)
- fusb300_wrcxf(ep, req);
- if ((req->req.length - req->req.actual) < ep->ep.maxpacket)
- done(ep, req, 0);
- } else
- fusb300_set_cxdone(fusb300);
-}
-
-static void fusb300_grp2_handler(void)
-{
-}
-
-static void fusb300_grp3_handler(void)
-{
-}
-
-static void fusb300_grp4_handler(void)
-{
-}
-
-static void fusb300_grp5_handler(void)
-{
-}
-
-static irqreturn_t fusb300_irq(int irq, void *_fusb300)
-{
- struct fusb300 *fusb300 = _fusb300;
- u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
- u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1);
- u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0);
- u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0);
- struct usb_ctrlrequest ctrl;
- u8 in;
- u32 reg;
- int i;
-
- spin_lock(&fusb300->lock);
-
- int_grp1 &= int_grp1_en;
- int_grp0 &= int_grp0_en;
-
- if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_WARM_RST_INT);
- printk(KERN_INFO"fusb300_warmreset\n");
- fusb300_reset();
- }
-
- if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_HOT_RST_INT);
- printk(KERN_INFO"fusb300_hotreset\n");
- fusb300_reset();
- }
-
- if (int_grp1 & FUSB300_IGR1_USBRST_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_USBRST_INT);
- fusb300_reset();
- }
- /* COMABT_INT has a highest priority */
-
- if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_CX_COMABT_INT);
- printk(KERN_INFO"fusb300_ep0abt\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_VBUS_CHG_INT);
- printk(KERN_INFO"fusb300_vbus_change\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U3_EXIT_FAIL_INT);
- }
-
- if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U2_EXIT_FAIL_INT);
- }
-
- if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U1_EXIT_FAIL_INT);
- }
-
- if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U2_ENTRY_FAIL_INT);
- }
-
- if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U1_ENTRY_FAIL_INT);
- }
-
- if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U3_EXIT_INT);
- printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U2_EXIT_INT);
- printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U1_EXIT_INT);
- printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U3_ENTRY_INT);
- printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n");
- fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1,
- FUSB300_SSCR1_GO_U3_DONE);
- }
-
- if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U2_ENTRY_INT);
- printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_U1_ENTRY_INT);
- printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_RESM_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_RESM_INT);
- printk(KERN_INFO "fusb300_resume\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_SUSP_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_SUSP_INT);
- printk(KERN_INFO "fusb300_suspend\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_HS_LPM_INT);
- printk(KERN_INFO "fusb300_HS_LPM_INT\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) {
- fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1,
- FUSB300_IGR1_DEV_MODE_CHG_INT);
- check_device_mode(fusb300);
- }
-
- if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) {
- fusb300_set_cxstall(fusb300);
- printk(KERN_INFO "fusb300_ep0fail\n");
- }
-
- if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) {
- printk(KERN_INFO "fusb300_ep0setup\n");
- if (setup_packet(fusb300, &ctrl)) {
- spin_unlock(&fusb300->lock);
- if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0)
- fusb300_set_cxstall(fusb300);
- spin_lock(&fusb300->lock);
- }
- }
-
- if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT)
- printk(KERN_INFO "fusb300_cmdend\n");
-
-
- if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) {
- printk(KERN_INFO "fusb300_cxout\n");
- fusb300_ep0out(fusb300);
- }
-
- if (int_grp1 & FUSB300_IGR1_CX_IN_INT) {
- printk(KERN_INFO "fusb300_cxin\n");
- fusb300_ep0in(fusb300);
- }
-
- if (int_grp1 & FUSB300_IGR1_INTGRP5)
- fusb300_grp5_handler();
-
- if (int_grp1 & FUSB300_IGR1_INTGRP4)
- fusb300_grp4_handler();
-
- if (int_grp1 & FUSB300_IGR1_INTGRP3)
- fusb300_grp3_handler();
-
- if (int_grp1 & FUSB300_IGR1_INTGRP2)
- fusb300_grp2_handler();
-
- if (int_grp0) {
- for (i = 1; i < FUSB300_MAX_NUM_EP; i++) {
- if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) {
- reg = ioread32(fusb300->reg +
- FUSB300_OFFSET_EPSET1(i));
- in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0;
- if (in)
- in_ep_fifo_handler(fusb300->ep[i]);
- else
- out_ep_fifo_handler(fusb300->ep[i]);
- }
- }
- }
-
- spin_unlock(&fusb300->lock);
-
- return IRQ_HANDLED;
-}
-
-static void fusb300_set_u2_timeout(struct fusb300 *fusb300,
- u32 time)
-{
- u32 reg;
-
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
- reg &= ~0xff;
- reg |= FUSB300_SSCR2_U2TIMEOUT(time);
-
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
-}
-
-static void fusb300_set_u1_timeout(struct fusb300 *fusb300,
- u32 time)
-{
- u32 reg;
-
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT);
- reg &= ~(0xff << 8);
- reg |= FUSB300_SSCR2_U1TIMEOUT(time);
-
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT);
-}
-
-static void init_controller(struct fusb300 *fusb300)
-{
- u32 reg;
- u32 mask = 0;
- u32 val = 0;
-
- /* split on */
- mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON;
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR);
- reg &= ~mask;
- reg |= val;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR);
-
- /* enable high-speed LPM */
- mask = val = FUSB300_HSCR_HS_LPM_PERMIT;
- reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR);
- reg &= ~mask;
- reg |= val;
- iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR);
-
- /*set u1 u2 timer*/
- fusb300_set_u2_timeout(fusb300, 0xff);
- fusb300_set_u1_timeout(fusb300, 0xff);
-
- /* enable all grp1 interrupt */
- iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1);
-}
-/*------------------------------------------------------------------------*/
-static int fusb300_udc_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct fusb300 *fusb300 = to_fusb300(g);
-
- /* hook up the driver */
- fusb300->driver = driver;
-
- return 0;
-}
-
-static int fusb300_udc_stop(struct usb_gadget *g)
-{
- struct fusb300 *fusb300 = to_fusb300(g);
-
- init_controller(fusb300);
- fusb300->driver = NULL;
-
- return 0;
-}
-/*--------------------------------------------------------------------------*/
-
-static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
-{
- return 0;
-}
-
-static const struct usb_gadget_ops fusb300_gadget_ops = {
- .pullup = fusb300_udc_pullup,
- .udc_start = fusb300_udc_start,
- .udc_stop = fusb300_udc_stop,
-};
-
-static void fusb300_remove(struct platform_device *pdev)
-{
- struct fusb300 *fusb300 = platform_get_drvdata(pdev);
- int i;
-
- usb_del_gadget_udc(&fusb300->gadget);
- iounmap(fusb300->reg);
- free_irq(platform_get_irq(pdev, 0), fusb300);
- free_irq(platform_get_irq(pdev, 1), fusb300);
-
- fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
- for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
- kfree(fusb300->ep[i]);
- kfree(fusb300);
-}
-
-static int fusb300_probe(struct platform_device *pdev)
-{
- struct resource *res, *ires, *ires1;
- void __iomem *reg = NULL;
- struct fusb300 *fusb300 = NULL;
- struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP];
- int ret = 0;
- int i;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENODEV;
- pr_err("platform_get_resource error.\n");
- goto clean_up;
- }
-
- ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!ires) {
- ret = -ENODEV;
- dev_err(&pdev->dev,
- "platform_get_resource IORESOURCE_IRQ error.\n");
- goto clean_up;
- }
-
- ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!ires1) {
- ret = -ENODEV;
- dev_err(&pdev->dev,
- "platform_get_resource IORESOURCE_IRQ 1 error.\n");
- goto clean_up;
- }
-
- reg = ioremap(res->start, resource_size(res));
- if (reg == NULL) {
- ret = -ENOMEM;
- pr_err("ioremap error.\n");
- goto clean_up;
- }
-
- /* initialize udc */
- fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL);
- if (fusb300 == NULL) {
- ret = -ENOMEM;
- goto clean_up;
- }
-
- for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {
- _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL);
- if (_ep[i] == NULL) {
- ret = -ENOMEM;
- goto clean_up;
- }
- fusb300->ep[i] = _ep[i];
- }
-
- spin_lock_init(&fusb300->lock);
-
- platform_set_drvdata(pdev, fusb300);
-
- fusb300->gadget.ops = &fusb300_gadget_ops;
-
- fusb300->gadget.max_speed = USB_SPEED_HIGH;
- fusb300->gadget.name = udc_name;
- fusb300->reg = reg;
-
- ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED,
- udc_name, fusb300);
- if (ret < 0) {
- pr_err("request_irq error (%d)\n", ret);
- goto clean_up;
- }
-
- ret = request_irq(ires1->start, fusb300_irq,
- IRQF_SHARED, udc_name, fusb300);
- if (ret < 0) {
- pr_err("request_irq1 error (%d)\n", ret);
- goto err_request_irq1;
- }
-
- INIT_LIST_HEAD(&fusb300->gadget.ep_list);
-
- for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) {
- struct fusb300_ep *ep = fusb300->ep[i];
-
- if (i != 0) {
- INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list);
- list_add_tail(&fusb300->ep[i]->ep.ep_list,
- &fusb300->gadget.ep_list);
- }
- ep->fusb300 = fusb300;
- INIT_LIST_HEAD(&ep->queue);
- ep->ep.name = fusb300_ep_name[i];
- ep->ep.ops = &fusb300_ep_ops;
- usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);
-
- if (i == 0) {
- ep->ep.caps.type_control = true;
- } else {
- ep->ep.caps.type_iso = true;
- ep->ep.caps.type_bulk = true;
- ep->ep.caps.type_int = true;
- }
-
- ep->ep.caps.dir_in = true;
- ep->ep.caps.dir_out = true;
- }
- usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);
- fusb300->ep[0]->epnum = 0;
- fusb300->gadget.ep0 = &fusb300->ep[0]->ep;
- INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list);
-
- fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
- GFP_KERNEL);
- if (fusb300->ep0_req == NULL) {
- ret = -ENOMEM;
- goto err_alloc_request;
- }
-
- init_controller(fusb300);
- ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
- if (ret)
- goto err_add_udc;
-
- dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
-
- return 0;
-
-err_add_udc:
- fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
-
-err_alloc_request:
- free_irq(ires1->start, fusb300);
-
-err_request_irq1:
- free_irq(ires->start, fusb300);
-
-clean_up:
- if (fusb300) {
- if (fusb300->ep0_req)
- fusb300_free_request(&fusb300->ep[0]->ep,
- fusb300->ep0_req);
- for (i = 0; i < FUSB300_MAX_NUM_EP; i++)
- kfree(fusb300->ep[i]);
- kfree(fusb300);
- }
- if (reg)
- iounmap(reg);
-
- return ret;
-}
-
-static struct platform_driver fusb300_driver = {
- .probe = fusb300_probe,
- .remove = fusb300_remove,
- .driver = {
- .name = udc_name,
- },
-};
-
-module_platform_driver(fusb300_driver);
diff --git a/drivers/usb/gadget/udc/fusb300_udc.h b/drivers/usb/gadget/udc/fusb300_udc.h
deleted file mode 100644
index eb3d6d379ba7..000000000000
--- a/drivers/usb/gadget/udc/fusb300_udc.h
+++ /dev/null
@@ -1,675 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Fusb300 UDC (USB gadget)
- *
- * Copyright (C) 2010 Faraday Technology Corp.
- *
- * Author : Yuan-hsin Chen <yhchen@faraday-tech.com>
- */
-
-
-#ifndef __FUSB300_UDC_H__
-#define __FUSB300_UDC_H__
-
-#include <linux/kernel.h>
-
-#define FUSB300_OFFSET_GCR 0x00
-#define FUSB300_OFFSET_GTM 0x04
-#define FUSB300_OFFSET_DAR 0x08
-#define FUSB300_OFFSET_CSR 0x0C
-#define FUSB300_OFFSET_CXPORT 0x10
-#define FUSB300_OFFSET_EPSET0(n) (0x20 + (n - 1) * 0x30)
-#define FUSB300_OFFSET_EPSET1(n) (0x24 + (n - 1) * 0x30)
-#define FUSB300_OFFSET_EPSET2(n) (0x28 + (n - 1) * 0x30)
-#define FUSB300_OFFSET_EPFFR(n) (0x2c + (n - 1) * 0x30)
-#define FUSB300_OFFSET_EPSTRID(n) (0x40 + (n - 1) * 0x30)
-#define FUSB300_OFFSET_HSPTM 0x300
-#define FUSB300_OFFSET_HSCR 0x304
-#define FUSB300_OFFSET_SSCR0 0x308
-#define FUSB300_OFFSET_SSCR1 0x30C
-#define FUSB300_OFFSET_TT 0x310
-#define FUSB300_OFFSET_DEVNOTF 0x314
-#define FUSB300_OFFSET_DNC1 0x318
-#define FUSB300_OFFSET_CS 0x31C
-#define FUSB300_OFFSET_SOF 0x324
-#define FUSB300_OFFSET_EFCS 0x328
-#define FUSB300_OFFSET_IGR0 0x400
-#define FUSB300_OFFSET_IGR1 0x404
-#define FUSB300_OFFSET_IGR2 0x408
-#define FUSB300_OFFSET_IGR3 0x40C
-#define FUSB300_OFFSET_IGR4 0x410
-#define FUSB300_OFFSET_IGR5 0x414
-#define FUSB300_OFFSET_IGER0 0x420
-#define FUSB300_OFFSET_IGER1 0x424
-#define FUSB300_OFFSET_IGER2 0x428
-#define FUSB300_OFFSET_IGER3 0x42C
-#define FUSB300_OFFSET_IGER4 0x430
-#define FUSB300_OFFSET_IGER5 0x434
-#define FUSB300_OFFSET_DMAHMER 0x500
-#define FUSB300_OFFSET_EPPRDRDY 0x504
-#define FUSB300_OFFSET_DMAEPMR 0x508
-#define FUSB300_OFFSET_DMAENR 0x50C
-#define FUSB300_OFFSET_DMAAPR 0x510
-#define FUSB300_OFFSET_AHBCR 0x514
-#define FUSB300_OFFSET_EPPRD_W0(n) (0x520 + (n - 1) * 0x10)
-#define FUSB300_OFFSET_EPPRD_W1(n) (0x524 + (n - 1) * 0x10)
-#define FUSB300_OFFSET_EPPRD_W2(n) (0x528 + (n - 1) * 0x10)
-#define FUSB300_OFFSET_EPRD_PTR(n) (0x52C + (n - 1) * 0x10)
-#define FUSB300_OFFSET_BUFDBG_START 0x800
-#define FUSB300_OFFSET_BUFDBG_END 0xBFC
-#define FUSB300_OFFSET_EPPORT(n) (0x1010 + (n - 1) * 0x10)
-
-/*
- * * Global Control Register (offset = 000H)
- * */
-#define FUSB300_GCR_SF_RST (1 << 8)
-#define FUSB300_GCR_VBUS_STATUS (1 << 7)
-#define FUSB300_GCR_FORCE_HS_SUSP (1 << 6)
-#define FUSB300_GCR_SYNC_FIFO1_CLR (1 << 5)
-#define FUSB300_GCR_SYNC_FIFO0_CLR (1 << 4)
-#define FUSB300_GCR_FIFOCLR (1 << 3)
-#define FUSB300_GCR_GLINTEN (1 << 2)
-#define FUSB300_GCR_DEVEN_FS 0x3
-#define FUSB300_GCR_DEVEN_HS 0x2
-#define FUSB300_GCR_DEVEN_SS 0x1
-#define FUSB300_GCR_DEVDIS 0x0
-#define FUSB300_GCR_DEVEN_MSK 0x3
-
-
-/*
- * *Global Test Mode (offset = 004H)
- * */
-#define FUSB300_GTM_TST_DIS_SOFGEN (1 << 16)
-#define FUSB300_GTM_TST_CUR_EP_ENTRY(n) ((n & 0xF) << 12)
-#define FUSB300_GTM_TST_EP_ENTRY(n) ((n & 0xF) << 8)
-#define FUSB300_GTM_TST_EP_NUM(n) ((n & 0xF) << 4)
-#define FUSB300_GTM_TST_FIFO_DEG (1 << 1)
-#define FUSB300_GTM_TSTMODE (1 << 0)
-
-/*
- * * Device Address Register (offset = 008H)
- * */
-#define FUSB300_DAR_SETCONFG (1 << 7)
-#define FUSB300_DAR_DRVADDR(x) (x & 0x7F)
-#define FUSB300_DAR_DRVADDR_MSK 0x7F
-
-/*
- * *Control Transfer Configuration and Status Register
- * (CX_Config_Status, offset = 00CH)
- * */
-#define FUSB300_CSR_LEN(x) ((x & 0xFFFF) << 8)
-#define FUSB300_CSR_LEN_MSK (0xFFFF << 8)
-#define FUSB300_CSR_EMP (1 << 4)
-#define FUSB300_CSR_FUL (1 << 3)
-#define FUSB300_CSR_CLR (1 << 2)
-#define FUSB300_CSR_STL (1 << 1)
-#define FUSB300_CSR_DONE (1 << 0)
-
-/*
- * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
- * */
-#define FUSB300_EPSET0_STL_CLR (1 << 3)
-#define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
-#define FUSB300_EPSET0_STL (1 << 0)
-
-/*
- * * EPn Setting 1 (EPn_SET1, offset = 024H+(n-1)*30H, n=1~15)
- * */
-#define FUSB300_EPSET1_START_ENTRY(x) ((x & 0xFF) << 24)
-#define FUSB300_EPSET1_START_ENTRY_MSK (0xFF << 24)
-#define FUSB300_EPSET1_FIFOENTRY(x) ((x & 0x1F) << 12)
-#define FUSB300_EPSET1_FIFOENTRY_MSK (0x1f << 12)
-#define FUSB300_EPSET1_INTERVAL(x) ((x & 0x7) << 6)
-#define FUSB300_EPSET1_BWNUM(x) ((x & 0x3) << 4)
-#define FUSB300_EPSET1_TYPEISO (1 << 2)
-#define FUSB300_EPSET1_TYPEBLK (2 << 2)
-#define FUSB300_EPSET1_TYPEINT (3 << 2)
-#define FUSB300_EPSET1_TYPE(x) ((x & 0x3) << 2)
-#define FUSB300_EPSET1_TYPE_MSK (0x3 << 2)
-#define FUSB300_EPSET1_DIROUT (0 << 1)
-#define FUSB300_EPSET1_DIRIN (1 << 1)
-#define FUSB300_EPSET1_DIR(x) ((x & 0x1) << 1)
-#define FUSB300_EPSET1_DIRIN (1 << 1)
-#define FUSB300_EPSET1_DIR_MSK ((0x1) << 1)
-#define FUSB300_EPSET1_ACTDIS 0
-#define FUSB300_EPSET1_ACTEN 1
-
-/*
- * *EPn Setting 2 (EPn_SET2, offset = 028H+(n-1)*30H, n=1~15)
- * */
-#define FUSB300_EPSET2_ADDROFS(x) ((x & 0x7FFF) << 16)
-#define FUSB300_EPSET2_ADDROFS_MSK (0x7fff << 16)
-#define FUSB300_EPSET2_MPS(x) (x & 0x7FF)
-#define FUSB300_EPSET2_MPS_MSK 0x7FF
-
-/*
- * * EPn FIFO Register (offset = 2cH+(n-1)*30H)
- * */
-#define FUSB300_FFR_RST (1 << 31)
-#define FUSB300_FF_FUL (1 << 30)
-#define FUSB300_FF_EMPTY (1 << 29)
-#define FUSB300_FFR_BYCNT 0x1FFFF
-
-/*
- * *EPn Stream ID (EPn_STR_ID, offset = 040H+(n-1)*30H, n=1~15)
- * */
-#define FUSB300_STRID_STREN (1 << 16)
-#define FUSB300_STRID_STRID(x) (x & 0xFFFF)
-
-/*
- * *HS PHY Test Mode (offset = 300H)
- * */
-#define FUSB300_HSPTM_TSTPKDONE (1 << 4)
-#define FUSB300_HSPTM_TSTPKT (1 << 3)
-#define FUSB300_HSPTM_TSTSET0NAK (1 << 2)
-#define FUSB300_HSPTM_TSTKSTA (1 << 1)
-#define FUSB300_HSPTM_TSTJSTA (1 << 0)
-
-/*
- * *HS Control Register (offset = 304H)
- * */
-#define FUSB300_HSCR_HS_LPM_PERMIT (1 << 8)
-#define FUSB300_HSCR_HS_LPM_RMWKUP (1 << 7)
-#define FUSB300_HSCR_CAP_LPM_RMWKUP (1 << 6)
-#define FUSB300_HSCR_HS_GOSUSP (1 << 5)
-#define FUSB300_HSCR_HS_GORMWKU (1 << 4)
-#define FUSB300_HSCR_CAP_RMWKUP (1 << 3)
-#define FUSB300_HSCR_IDLECNT_0MS 0
-#define FUSB300_HSCR_IDLECNT_1MS 1
-#define FUSB300_HSCR_IDLECNT_2MS 2
-#define FUSB300_HSCR_IDLECNT_3MS 3
-#define FUSB300_HSCR_IDLECNT_4MS 4
-#define FUSB300_HSCR_IDLECNT_5MS 5
-#define FUSB300_HSCR_IDLECNT_6MS 6
-#define FUSB300_HSCR_IDLECNT_7MS 7
-
-/*
- * * SS Controller Register 0 (offset = 308H)
- * */
-#define FUSB300_SSCR0_MAX_INTERVAL(x) ((x & 0x7) << 4)
-#define FUSB300_SSCR0_U2_FUN_EN (1 << 1)
-#define FUSB300_SSCR0_U1_FUN_EN (1 << 0)
-
-/*
- * * SS Controller Register 1 (offset = 30CH)
- * */
-#define FUSB300_SSCR1_GO_U3_DONE (1 << 8)
-#define FUSB300_SSCR1_TXDEEMPH_LEVEL (1 << 7)
-#define FUSB300_SSCR1_DIS_SCRMB (1 << 6)
-#define FUSB300_SSCR1_FORCE_RECOVERY (1 << 5)
-#define FUSB300_SSCR1_U3_WAKEUP_EN (1 << 4)
-#define FUSB300_SSCR1_U2_EXIT_EN (1 << 3)
-#define FUSB300_SSCR1_U1_EXIT_EN (1 << 2)
-#define FUSB300_SSCR1_U2_ENTRY_EN (1 << 1)
-#define FUSB300_SSCR1_U1_ENTRY_EN (1 << 0)
-
-/*
- * *SS Controller Register 2 (offset = 310H)
- * */
-#define FUSB300_SSCR2_SS_TX_SWING (1 << 25)
-#define FUSB300_SSCR2_FORCE_LINKPM_ACCEPT (1 << 24)
-#define FUSB300_SSCR2_U2_INACT_TIMEOUT(x) ((x & 0xFF) << 16)
-#define FUSB300_SSCR2_U1TIMEOUT(x) ((x & 0xFF) << 8)
-#define FUSB300_SSCR2_U2TIMEOUT(x) (x & 0xFF)
-
-/*
- * *SS Device Notification Control (DEV_NOTF, offset = 314H)
- * */
-#define FUSB300_DEVNOTF_CONTEXT0(x) ((x & 0xFFFFFF) << 8)
-#define FUSB300_DEVNOTF_TYPE_DIS 0
-#define FUSB300_DEVNOTF_TYPE_FUNCWAKE 1
-#define FUSB300_DEVNOTF_TYPE_LTM 2
-#define FUSB300_DEVNOTF_TYPE_BUSINT_ADJMSG 3
-
-/*
- * *BFM Arbiter Priority Register (BFM_ARB offset = 31CH)
- * */
-#define FUSB300_BFMARB_ARB_M1 (1 << 3)
-#define FUSB300_BFMARB_ARB_M0 (1 << 2)
-#define FUSB300_BFMARB_ARB_S1 (1 << 1)
-#define FUSB300_BFMARB_ARB_S0 1
-
-/*
- * *Vendor Specific IO Control Register (offset = 320H)
- * */
-#define FUSB300_VSIC_VCTLOAD_N (1 << 8)
-#define FUSB300_VSIC_VCTL(x) (x & 0x3F)
-
-/*
- * *SOF Mask Timer (offset = 324H)
- * */
-#define FUSB300_SOF_MASK_TIMER_HS 0x044c
-#define FUSB300_SOF_MASK_TIMER_FS 0x2710
-
-/*
- * *Error Flag and Control Status (offset = 328H)
- * */
-#define FUSB300_EFCS_PM_STATE_U3 3
-#define FUSB300_EFCS_PM_STATE_U2 2
-#define FUSB300_EFCS_PM_STATE_U1 1
-#define FUSB300_EFCS_PM_STATE_U0 0
-
-/*
- * *Interrupt Group 0 Register (offset = 400H)
- * */
-#define FUSB300_IGR0_EP15_PRD_INT (1 << 31)
-#define FUSB300_IGR0_EP14_PRD_INT (1 << 30)
-#define FUSB300_IGR0_EP13_PRD_INT (1 << 29)
-#define FUSB300_IGR0_EP12_PRD_INT (1 << 28)
-#define FUSB300_IGR0_EP11_PRD_INT (1 << 27)
-#define FUSB300_IGR0_EP10_PRD_INT (1 << 26)
-#define FUSB300_IGR0_EP9_PRD_INT (1 << 25)
-#define FUSB300_IGR0_EP8_PRD_INT (1 << 24)
-#define FUSB300_IGR0_EP7_PRD_INT (1 << 23)
-#define FUSB300_IGR0_EP6_PRD_INT (1 << 22)
-#define FUSB300_IGR0_EP5_PRD_INT (1 << 21)
-#define FUSB300_IGR0_EP4_PRD_INT (1 << 20)
-#define FUSB300_IGR0_EP3_PRD_INT (1 << 19)
-#define FUSB300_IGR0_EP2_PRD_INT (1 << 18)
-#define FUSB300_IGR0_EP1_PRD_INT (1 << 17)
-#define FUSB300_IGR0_EPn_PRD_INT(n) (1 << (n + 16))
-
-#define FUSB300_IGR0_EP15_FIFO_INT (1 << 15)
-#define FUSB300_IGR0_EP14_FIFO_INT (1 << 14)
-#define FUSB300_IGR0_EP13_FIFO_INT (1 << 13)
-#define FUSB300_IGR0_EP12_FIFO_INT (1 << 12)
-#define FUSB300_IGR0_EP11_FIFO_INT (1 << 11)
-#define FUSB300_IGR0_EP10_FIFO_INT (1 << 10)
-#define FUSB300_IGR0_EP9_FIFO_INT (1 << 9)
-#define FUSB300_IGR0_EP8_FIFO_INT (1 << 8)
-#define FUSB300_IGR0_EP7_FIFO_INT (1 << 7)
-#define FUSB300_IGR0_EP6_FIFO_INT (1 << 6)
-#define FUSB300_IGR0_EP5_FIFO_INT (1 << 5)
-#define FUSB300_IGR0_EP4_FIFO_INT (1 << 4)
-#define FUSB300_IGR0_EP3_FIFO_INT (1 << 3)
-#define FUSB300_IGR0_EP2_FIFO_INT (1 << 2)
-#define FUSB300_IGR0_EP1_FIFO_INT (1 << 1)
-#define FUSB300_IGR0_EPn_FIFO_INT(n) (1 << n)
-
-/*
- * *Interrupt Group 1 Register (offset = 404H)
- * */
-#define FUSB300_IGR1_INTGRP5 (1 << 31)
-#define FUSB300_IGR1_VBUS_CHG_INT (1 << 30)
-#define FUSB300_IGR1_SYNF1_EMPTY_INT (1 << 29)
-#define FUSB300_IGR1_SYNF0_EMPTY_INT (1 << 28)
-#define FUSB300_IGR1_U3_EXIT_FAIL_INT (1 << 27)
-#define FUSB300_IGR1_U2_EXIT_FAIL_INT (1 << 26)
-#define FUSB300_IGR1_U1_EXIT_FAIL_INT (1 << 25)
-#define FUSB300_IGR1_U2_ENTRY_FAIL_INT (1 << 24)
-#define FUSB300_IGR1_U1_ENTRY_FAIL_INT (1 << 23)
-#define FUSB300_IGR1_U3_EXIT_INT (1 << 22)
-#define FUSB300_IGR1_U2_EXIT_INT (1 << 21)
-#define FUSB300_IGR1_U1_EXIT_INT (1 << 20)
-#define FUSB300_IGR1_U3_ENTRY_INT (1 << 19)
-#define FUSB300_IGR1_U2_ENTRY_INT (1 << 18)
-#define FUSB300_IGR1_U1_ENTRY_INT (1 << 17)
-#define FUSB300_IGR1_HOT_RST_INT (1 << 16)
-#define FUSB300_IGR1_WARM_RST_INT (1 << 15)
-#define FUSB300_IGR1_RESM_INT (1 << 14)
-#define FUSB300_IGR1_SUSP_INT (1 << 13)
-#define FUSB300_IGR1_HS_LPM_INT (1 << 12)
-#define FUSB300_IGR1_USBRST_INT (1 << 11)
-#define FUSB300_IGR1_DEV_MODE_CHG_INT (1 << 9)
-#define FUSB300_IGR1_CX_COMABT_INT (1 << 8)
-#define FUSB300_IGR1_CX_COMFAIL_INT (1 << 7)
-#define FUSB300_IGR1_CX_CMDEND_INT (1 << 6)
-#define FUSB300_IGR1_CX_OUT_INT (1 << 5)
-#define FUSB300_IGR1_CX_IN_INT (1 << 4)
-#define FUSB300_IGR1_CX_SETUP_INT (1 << 3)
-#define FUSB300_IGR1_INTGRP4 (1 << 2)
-#define FUSB300_IGR1_INTGRP3 (1 << 1)
-#define FUSB300_IGR1_INTGRP2 (1 << 0)
-
-/*
- * *Interrupt Group 2 Register (offset = 408H)
- * */
-#define FUSB300_IGR2_EP6_STR_ACCEPT_INT (1 << 29)
-#define FUSB300_IGR2_EP6_STR_RESUME_INT (1 << 28)
-#define FUSB300_IGR2_EP6_STR_REQ_INT (1 << 27)
-#define FUSB300_IGR2_EP6_STR_NOTRDY_INT (1 << 26)
-#define FUSB300_IGR2_EP6_STR_PRIME_INT (1 << 25)
-#define FUSB300_IGR2_EP5_STR_ACCEPT_INT (1 << 24)
-#define FUSB300_IGR2_EP5_STR_RESUME_INT (1 << 23)
-#define FUSB300_IGR2_EP5_STR_REQ_INT (1 << 22)
-#define FUSB300_IGR2_EP5_STR_NOTRDY_INT (1 << 21)
-#define FUSB300_IGR2_EP5_STR_PRIME_INT (1 << 20)
-#define FUSB300_IGR2_EP4_STR_ACCEPT_INT (1 << 19)
-#define FUSB300_IGR2_EP4_STR_RESUME_INT (1 << 18)
-#define FUSB300_IGR2_EP4_STR_REQ_INT (1 << 17)
-#define FUSB300_IGR2_EP4_STR_NOTRDY_INT (1 << 16)
-#define FUSB300_IGR2_EP4_STR_PRIME_INT (1 << 15)
-#define FUSB300_IGR2_EP3_STR_ACCEPT_INT (1 << 14)
-#define FUSB300_IGR2_EP3_STR_RESUME_INT (1 << 13)
-#define FUSB300_IGR2_EP3_STR_REQ_INT (1 << 12)
-#define FUSB300_IGR2_EP3_STR_NOTRDY_INT (1 << 11)
-#define FUSB300_IGR2_EP3_STR_PRIME_INT (1 << 10)
-#define FUSB300_IGR2_EP2_STR_ACCEPT_INT (1 << 9)
-#define FUSB300_IGR2_EP2_STR_RESUME_INT (1 << 8)
-#define FUSB300_IGR2_EP2_STR_REQ_INT (1 << 7)
-#define FUSB300_IGR2_EP2_STR_NOTRDY_INT (1 << 6)
-#define FUSB300_IGR2_EP2_STR_PRIME_INT (1 << 5)
-#define FUSB300_IGR2_EP1_STR_ACCEPT_INT (1 << 4)
-#define FUSB300_IGR2_EP1_STR_RESUME_INT (1 << 3)
-#define FUSB300_IGR2_EP1_STR_REQ_INT (1 << 2)
-#define FUSB300_IGR2_EP1_STR_NOTRDY_INT (1 << 1)
-#define FUSB300_IGR2_EP1_STR_PRIME_INT (1 << 0)
-
-#define FUSB300_IGR2_EP_STR_ACCEPT_INT(n) (1 << (5 * n - 1))
-#define FUSB300_IGR2_EP_STR_RESUME_INT(n) (1 << (5 * n - 2))
-#define FUSB300_IGR2_EP_STR_REQ_INT(n) (1 << (5 * n - 3))
-#define FUSB300_IGR2_EP_STR_NOTRDY_INT(n) (1 << (5 * n - 4))
-#define FUSB300_IGR2_EP_STR_PRIME_INT(n) (1 << (5 * n - 5))
-
-/*
- * *Interrupt Group 3 Register (offset = 40CH)
- * */
-#define FUSB300_IGR3_EP12_STR_ACCEPT_INT (1 << 29)
-#define FUSB300_IGR3_EP12_STR_RESUME_INT (1 << 28)
-#define FUSB300_IGR3_EP12_STR_REQ_INT (1 << 27)
-#define FUSB300_IGR3_EP12_STR_NOTRDY_INT (1 << 26)
-#define FUSB300_IGR3_EP12_STR_PRIME_INT (1 << 25)
-#define FUSB300_IGR3_EP11_STR_ACCEPT_INT (1 << 24)
-#define FUSB300_IGR3_EP11_STR_RESUME_INT (1 << 23)
-#define FUSB300_IGR3_EP11_STR_REQ_INT (1 << 22)
-#define FUSB300_IGR3_EP11_STR_NOTRDY_INT (1 << 21)
-#define FUSB300_IGR3_EP11_STR_PRIME_INT (1 << 20)
-#define FUSB300_IGR3_EP10_STR_ACCEPT_INT (1 << 19)
-#define FUSB300_IGR3_EP10_STR_RESUME_INT (1 << 18)
-#define FUSB300_IGR3_EP10_STR_REQ_INT (1 << 17)
-#define FUSB300_IGR3_EP10_STR_NOTRDY_INT (1 << 16)
-#define FUSB300_IGR3_EP10_STR_PRIME_INT (1 << 15)
-#define FUSB300_IGR3_EP9_STR_ACCEPT_INT (1 << 14)
-#define FUSB300_IGR3_EP9_STR_RESUME_INT (1 << 13)
-#define FUSB300_IGR3_EP9_STR_REQ_INT (1 << 12)
-#define FUSB300_IGR3_EP9_STR_NOTRDY_INT (1 << 11)
-#define FUSB300_IGR3_EP9_STR_PRIME_INT (1 << 10)
-#define FUSB300_IGR3_EP8_STR_ACCEPT_INT (1 << 9)
-#define FUSB300_IGR3_EP8_STR_RESUME_INT (1 << 8)
-#define FUSB300_IGR3_EP8_STR_REQ_INT (1 << 7)
-#define FUSB300_IGR3_EP8_STR_NOTRDY_INT (1 << 6)
-#define FUSB300_IGR3_EP8_STR_PRIME_INT (1 << 5)
-#define FUSB300_IGR3_EP7_STR_ACCEPT_INT (1 << 4)
-#define FUSB300_IGR3_EP7_STR_RESUME_INT (1 << 3)
-#define FUSB300_IGR3_EP7_STR_REQ_INT (1 << 2)
-#define FUSB300_IGR3_EP7_STR_NOTRDY_INT (1 << 1)
-#define FUSB300_IGR3_EP7_STR_PRIME_INT (1 << 0)
-
-#define FUSB300_IGR3_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
-#define FUSB300_IGR3_EP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
-#define FUSB300_IGR3_EP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
-#define FUSB300_IGR3_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
-#define FUSB300_IGR3_EP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
-
-/*
- * *Interrupt Group 4 Register (offset = 410H)
- * */
-#define FUSB300_IGR4_EP15_RX0_INT (1 << 31)
-#define FUSB300_IGR4_EP14_RX0_INT (1 << 30)
-#define FUSB300_IGR4_EP13_RX0_INT (1 << 29)
-#define FUSB300_IGR4_EP12_RX0_INT (1 << 28)
-#define FUSB300_IGR4_EP11_RX0_INT (1 << 27)
-#define FUSB300_IGR4_EP10_RX0_INT (1 << 26)
-#define FUSB300_IGR4_EP9_RX0_INT (1 << 25)
-#define FUSB300_IGR4_EP8_RX0_INT (1 << 24)
-#define FUSB300_IGR4_EP7_RX0_INT (1 << 23)
-#define FUSB300_IGR4_EP6_RX0_INT (1 << 22)
-#define FUSB300_IGR4_EP5_RX0_INT (1 << 21)
-#define FUSB300_IGR4_EP4_RX0_INT (1 << 20)
-#define FUSB300_IGR4_EP3_RX0_INT (1 << 19)
-#define FUSB300_IGR4_EP2_RX0_INT (1 << 18)
-#define FUSB300_IGR4_EP1_RX0_INT (1 << 17)
-#define FUSB300_IGR4_EP_RX0_INT(x) (1 << (x + 16))
-#define FUSB300_IGR4_EP15_STR_ACCEPT_INT (1 << 14)
-#define FUSB300_IGR4_EP15_STR_RESUME_INT (1 << 13)
-#define FUSB300_IGR4_EP15_STR_REQ_INT (1 << 12)
-#define FUSB300_IGR4_EP15_STR_NOTRDY_INT (1 << 11)
-#define FUSB300_IGR4_EP15_STR_PRIME_INT (1 << 10)
-#define FUSB300_IGR4_EP14_STR_ACCEPT_INT (1 << 9)
-#define FUSB300_IGR4_EP14_STR_RESUME_INT (1 << 8)
-#define FUSB300_IGR4_EP14_STR_REQ_INT (1 << 7)
-#define FUSB300_IGR4_EP14_STR_NOTRDY_INT (1 << 6)
-#define FUSB300_IGR4_EP14_STR_PRIME_INT (1 << 5)
-#define FUSB300_IGR4_EP13_STR_ACCEPT_INT (1 << 4)
-#define FUSB300_IGR4_EP13_STR_RESUME_INT (1 << 3)
-#define FUSB300_IGR4_EP13_STR_REQ_INT (1 << 2)
-#define FUSB300_IGR4_EP13_STR_NOTRDY_INT (1 << 1)
-#define FUSB300_IGR4_EP13_STR_PRIME_INT (1 << 0)
-
-#define FUSB300_IGR4_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 12) - 1))
-#define FUSB300_IGR4_EP_STR_RESUME_INT(n) (1 << (5 * (n - 12) - 2))
-#define FUSB300_IGR4_EP_STR_REQ_INT(n) (1 << (5 * (n - 12) - 3))
-#define FUSB300_IGR4_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 12) - 4))
-#define FUSB300_IGR4_EP_STR_PRIME_INT(n) (1 << (5 * (n - 12) - 5))
-
-/*
- * *Interrupt Group 5 Register (offset = 414H)
- * */
-#define FUSB300_IGR5_EP_STL_INT(n) (1 << n)
-
-/*
- * *Interrupt Enable Group 0 Register (offset = 420H)
- * */
-#define FUSB300_IGER0_EEP15_PRD_INT (1 << 31)
-#define FUSB300_IGER0_EEP14_PRD_INT (1 << 30)
-#define FUSB300_IGER0_EEP13_PRD_INT (1 << 29)
-#define FUSB300_IGER0_EEP12_PRD_INT (1 << 28)
-#define FUSB300_IGER0_EEP11_PRD_INT (1 << 27)
-#define FUSB300_IGER0_EEP10_PRD_INT (1 << 26)
-#define FUSB300_IGER0_EEP9_PRD_INT (1 << 25)
-#define FUSB300_IGER0_EP8_PRD_INT (1 << 24)
-#define FUSB300_IGER0_EEP7_PRD_INT (1 << 23)
-#define FUSB300_IGER0_EEP6_PRD_INT (1 << 22)
-#define FUSB300_IGER0_EEP5_PRD_INT (1 << 21)
-#define FUSB300_IGER0_EEP4_PRD_INT (1 << 20)
-#define FUSB300_IGER0_EEP3_PRD_INT (1 << 19)
-#define FUSB300_IGER0_EEP2_PRD_INT (1 << 18)
-#define FUSB300_IGER0_EEP1_PRD_INT (1 << 17)
-#define FUSB300_IGER0_EEPn_PRD_INT(n) (1 << (n + 16))
-
-#define FUSB300_IGER0_EEP15_FIFO_INT (1 << 15)
-#define FUSB300_IGER0_EEP14_FIFO_INT (1 << 14)
-#define FUSB300_IGER0_EEP13_FIFO_INT (1 << 13)
-#define FUSB300_IGER0_EEP12_FIFO_INT (1 << 12)
-#define FUSB300_IGER0_EEP11_FIFO_INT (1 << 11)
-#define FUSB300_IGER0_EEP10_FIFO_INT (1 << 10)
-#define FUSB300_IGER0_EEP9_FIFO_INT (1 << 9)
-#define FUSB300_IGER0_EEP8_FIFO_INT (1 << 8)
-#define FUSB300_IGER0_EEP7_FIFO_INT (1 << 7)
-#define FUSB300_IGER0_EEP6_FIFO_INT (1 << 6)
-#define FUSB300_IGER0_EEP5_FIFO_INT (1 << 5)
-#define FUSB300_IGER0_EEP4_FIFO_INT (1 << 4)
-#define FUSB300_IGER0_EEP3_FIFO_INT (1 << 3)
-#define FUSB300_IGER0_EEP2_FIFO_INT (1 << 2)
-#define FUSB300_IGER0_EEP1_FIFO_INT (1 << 1)
-#define FUSB300_IGER0_EEPn_FIFO_INT(n) (1 << n)
-
-/*
- * *Interrupt Enable Group 1 Register (offset = 424H)
- * */
-#define FUSB300_IGER1_EINT_GRP5 (1 << 31)
-#define FUSB300_IGER1_VBUS_CHG_INT (1 << 30)
-#define FUSB300_IGER1_SYNF1_EMPTY_INT (1 << 29)
-#define FUSB300_IGER1_SYNF0_EMPTY_INT (1 << 28)
-#define FUSB300_IGER1_U3_EXIT_FAIL_INT (1 << 27)
-#define FUSB300_IGER1_U2_EXIT_FAIL_INT (1 << 26)
-#define FUSB300_IGER1_U1_EXIT_FAIL_INT (1 << 25)
-#define FUSB300_IGER1_U2_ENTRY_FAIL_INT (1 << 24)
-#define FUSB300_IGER1_U1_ENTRY_FAIL_INT (1 << 23)
-#define FUSB300_IGER1_U3_EXIT_INT (1 << 22)
-#define FUSB300_IGER1_U2_EXIT_INT (1 << 21)
-#define FUSB300_IGER1_U1_EXIT_INT (1 << 20)
-#define FUSB300_IGER1_U3_ENTRY_INT (1 << 19)
-#define FUSB300_IGER1_U2_ENTRY_INT (1 << 18)
-#define FUSB300_IGER1_U1_ENTRY_INT (1 << 17)
-#define FUSB300_IGER1_HOT_RST_INT (1 << 16)
-#define FUSB300_IGER1_WARM_RST_INT (1 << 15)
-#define FUSB300_IGER1_RESM_INT (1 << 14)
-#define FUSB300_IGER1_SUSP_INT (1 << 13)
-#define FUSB300_IGER1_LPM_INT (1 << 12)
-#define FUSB300_IGER1_HS_RST_INT (1 << 11)
-#define FUSB300_IGER1_EDEV_MODE_CHG_INT (1 << 9)
-#define FUSB300_IGER1_CX_COMABT_INT (1 << 8)
-#define FUSB300_IGER1_CX_COMFAIL_INT (1 << 7)
-#define FUSB300_IGER1_CX_CMDEND_INT (1 << 6)
-#define FUSB300_IGER1_CX_OUT_INT (1 << 5)
-#define FUSB300_IGER1_CX_IN_INT (1 << 4)
-#define FUSB300_IGER1_CX_SETUP_INT (1 << 3)
-#define FUSB300_IGER1_INTGRP4 (1 << 2)
-#define FUSB300_IGER1_INTGRP3 (1 << 1)
-#define FUSB300_IGER1_INTGRP2 (1 << 0)
-
-/*
- * *Interrupt Enable Group 2 Register (offset = 428H)
- * */
-#define FUSB300_IGER2_EEP_STR_ACCEPT_INT(n) (1 << (5 * n - 1))
-#define FUSB300_IGER2_EEP_STR_RESUME_INT(n) (1 << (5 * n - 2))
-#define FUSB300_IGER2_EEP_STR_REQ_INT(n) (1 << (5 * n - 3))
-#define FUSB300_IGER2_EEP_STR_NOTRDY_INT(n) (1 << (5 * n - 4))
-#define FUSB300_IGER2_EEP_STR_PRIME_INT(n) (1 << (5 * n - 5))
-
-/*
- * *Interrupt Enable Group 3 Register (offset = 42CH)
- * */
-
-#define FUSB300_IGER3_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
-#define FUSB300_IGER3_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
-#define FUSB300_IGER3_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
-#define FUSB300_IGER3_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
-#define FUSB300_IGER3_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
-
-/*
- * *Interrupt Enable Group 4 Register (offset = 430H)
- * */
-
-#define FUSB300_IGER4_EEP_RX0_INT(n) (1 << (n + 16))
-#define FUSB300_IGER4_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1))
-#define FUSB300_IGER4_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2))
-#define FUSB300_IGER4_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3))
-#define FUSB300_IGER4_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4))
-#define FUSB300_IGER4_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5))
-
-/* EP PRD Ready (EP_PRD_RDY, offset = 504H) */
-
-#define FUSB300_EPPRDR_EP15_PRD_RDY (1 << 15)
-#define FUSB300_EPPRDR_EP14_PRD_RDY (1 << 14)
-#define FUSB300_EPPRDR_EP13_PRD_RDY (1 << 13)
-#define FUSB300_EPPRDR_EP12_PRD_RDY (1 << 12)
-#define FUSB300_EPPRDR_EP11_PRD_RDY (1 << 11)
-#define FUSB300_EPPRDR_EP10_PRD_RDY (1 << 10)
-#define FUSB300_EPPRDR_EP9_PRD_RDY (1 << 9)
-#define FUSB300_EPPRDR_EP8_PRD_RDY (1 << 8)
-#define FUSB300_EPPRDR_EP7_PRD_RDY (1 << 7)
-#define FUSB300_EPPRDR_EP6_PRD_RDY (1 << 6)
-#define FUSB300_EPPRDR_EP5_PRD_RDY (1 << 5)
-#define FUSB300_EPPRDR_EP4_PRD_RDY (1 << 4)
-#define FUSB300_EPPRDR_EP3_PRD_RDY (1 << 3)
-#define FUSB300_EPPRDR_EP2_PRD_RDY (1 << 2)
-#define FUSB300_EPPRDR_EP1_PRD_RDY (1 << 1)
-#define FUSB300_EPPRDR_EP_PRD_RDY(n) (1 << n)
-
-/* AHB Bus Control Register (offset = 514H) */
-#define FUSB300_AHBBCR_S1_SPLIT_ON (1 << 17)
-#define FUSB300_AHBBCR_S0_SPLIT_ON (1 << 16)
-#define FUSB300_AHBBCR_S1_1entry (0 << 12)
-#define FUSB300_AHBBCR_S1_4entry (3 << 12)
-#define FUSB300_AHBBCR_S1_8entry (5 << 12)
-#define FUSB300_AHBBCR_S1_16entry (7 << 12)
-#define FUSB300_AHBBCR_S0_1entry (0 << 8)
-#define FUSB300_AHBBCR_S0_4entry (3 << 8)
-#define FUSB300_AHBBCR_S0_8entry (5 << 8)
-#define FUSB300_AHBBCR_S0_16entry (7 << 8)
-#define FUSB300_AHBBCR_M1_BURST_SINGLE (0 << 4)
-#define FUSB300_AHBBCR_M1_BURST_INCR (1 << 4)
-#define FUSB300_AHBBCR_M1_BURST_INCR4 (3 << 4)
-#define FUSB300_AHBBCR_M1_BURST_INCR8 (5 << 4)
-#define FUSB300_AHBBCR_M1_BURST_INCR16 (7 << 4)
-#define FUSB300_AHBBCR_M0_BURST_SINGLE 0
-#define FUSB300_AHBBCR_M0_BURST_INCR 1
-#define FUSB300_AHBBCR_M0_BURST_INCR4 3
-#define FUSB300_AHBBCR_M0_BURST_INCR8 5
-#define FUSB300_AHBBCR_M0_BURST_INCR16 7
-#define FUSB300_IGER5_EEP_STL_INT(n) (1 << n)
-
-/* WORD 0 Data Structure of PRD Table */
-#define FUSB300_EPPRD0_M (1 << 30)
-#define FUSB300_EPPRD0_O (1 << 29)
-/* The finished prd */
-#define FUSB300_EPPRD0_F (1 << 28)
-#define FUSB300_EPPRD0_I (1 << 27)
-#define FUSB300_EPPRD0_A (1 << 26)
-/* To decide HW point to first prd at next time */
-#define FUSB300_EPPRD0_L (1 << 25)
-#define FUSB300_EPPRD0_H (1 << 24)
-#define FUSB300_EPPRD0_BTC(n) (n & 0xFFFFFF)
-
-/*----------------------------------------------------------------------*/
-#define FUSB300_MAX_NUM_EP 16
-
-#define FUSB300_FIFO_ENTRY_NUM 8
-#define FUSB300_MAX_FIFO_ENTRY 8
-
-#define SS_CTL_MAX_PACKET_SIZE 0x200
-#define SS_BULK_MAX_PACKET_SIZE 0x400
-#define SS_INT_MAX_PACKET_SIZE 0x400
-#define SS_ISO_MAX_PACKET_SIZE 0x400
-
-#define HS_BULK_MAX_PACKET_SIZE 0x200
-#define HS_CTL_MAX_PACKET_SIZE 0x40
-#define HS_INT_MAX_PACKET_SIZE 0x400
-#define HS_ISO_MAX_PACKET_SIZE 0x400
-
-struct fusb300_ep_info {
- u8 epnum;
- u8 type;
- u8 interval;
- u8 dir_in;
- u16 maxpacket;
- u16 addrofs;
- u16 bw_num;
-};
-
-struct fusb300_request {
-
- struct usb_request req;
- struct list_head queue;
-};
-
-
-struct fusb300_ep {
- struct usb_ep ep;
- struct fusb300 *fusb300;
-
- struct list_head queue;
- unsigned stall:1;
- unsigned wedged:1;
- unsigned use_dma:1;
-
- unsigned char epnum;
- unsigned char type;
-};
-
-struct fusb300 {
- spinlock_t lock;
- void __iomem *reg;
-
- unsigned long irq_trigger;
-
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
-
- struct fusb300_ep *ep[FUSB300_MAX_NUM_EP];
-
- struct usb_request *ep0_req; /* for internal request */
- __le16 ep0_data;
- u32 ep0_length; /* for internal request */
- u8 ep0_dir; /* 0/0x80 out/in */
-
- u8 fifo_entry_num; /* next start fifo entry */
- u32 addrofs; /* next fifo address offset */
- u8 reenum; /* if re-enumeration */
-};
-
-#define to_fusb300(g) (container_of((g), struct fusb300, gadget))
-
-#endif
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 89d6daf2bda7..1a7d3c4f652f 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -1629,7 +1629,7 @@ static int lpc32xx_ep_enable(struct usb_ep *_ep,
return -ESHUTDOWN;
}
- tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ tmp = usb_endpoint_type(desc);
switch (tmp) {
case USB_ENDPOINT_XFER_CONTROL:
return -EINVAL;
diff --git a/drivers/usb/gadget/udc/mv_u3d.h b/drivers/usb/gadget/udc/mv_u3d.h
deleted file mode 100644
index 66b84f792f64..000000000000
--- a/drivers/usb/gadget/udc/mv_u3d.h
+++ /dev/null
@@ -1,317 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- */
-
-#ifndef __MV_U3D_H
-#define __MV_U3D_H
-
-#define MV_U3D_EP_CONTEXT_ALIGNMENT 32
-#define MV_U3D_TRB_ALIGNMENT 16
-#define MV_U3D_DMA_BOUNDARY 4096
-#define MV_U3D_EP0_MAX_PKT_SIZE 512
-
-/* ep0 transfer state */
-#define MV_U3D_WAIT_FOR_SETUP 0
-#define MV_U3D_DATA_STATE_XMIT 1
-#define MV_U3D_DATA_STATE_NEED_ZLP 2
-#define MV_U3D_WAIT_FOR_OUT_STATUS 3
-#define MV_U3D_DATA_STATE_RECV 4
-#define MV_U3D_STATUS_STAGE 5
-
-#define MV_U3D_EP_MAX_LENGTH_TRANSFER 0x10000
-
-/* USB3 Interrupt Status */
-#define MV_U3D_USBINT_SETUP 0x00000001
-#define MV_U3D_USBINT_RX_COMPLETE 0x00000002
-#define MV_U3D_USBINT_TX_COMPLETE 0x00000004
-#define MV_U3D_USBINT_UNDER_RUN 0x00000008
-#define MV_U3D_USBINT_RXDESC_ERR 0x00000010
-#define MV_U3D_USBINT_TXDESC_ERR 0x00000020
-#define MV_U3D_USBINT_RX_TRB_COMPLETE 0x00000040
-#define MV_U3D_USBINT_TX_TRB_COMPLETE 0x00000080
-#define MV_U3D_USBINT_VBUS_VALID 0x00010000
-#define MV_U3D_USBINT_STORAGE_CMD_FULL 0x00020000
-#define MV_U3D_USBINT_LINK_CHG 0x01000000
-
-/* USB3 Interrupt Enable */
-#define MV_U3D_INTR_ENABLE_SETUP 0x00000001
-#define MV_U3D_INTR_ENABLE_RX_COMPLETE 0x00000002
-#define MV_U3D_INTR_ENABLE_TX_COMPLETE 0x00000004
-#define MV_U3D_INTR_ENABLE_UNDER_RUN 0x00000008
-#define MV_U3D_INTR_ENABLE_RXDESC_ERR 0x00000010
-#define MV_U3D_INTR_ENABLE_TXDESC_ERR 0x00000020
-#define MV_U3D_INTR_ENABLE_RX_TRB_COMPLETE 0x00000040
-#define MV_U3D_INTR_ENABLE_TX_TRB_COMPLETE 0x00000080
-#define MV_U3D_INTR_ENABLE_RX_BUFFER_ERR 0x00000100
-#define MV_U3D_INTR_ENABLE_VBUS_VALID 0x00010000
-#define MV_U3D_INTR_ENABLE_STORAGE_CMD_FULL 0x00020000
-#define MV_U3D_INTR_ENABLE_LINK_CHG 0x01000000
-#define MV_U3D_INTR_ENABLE_PRIME_STATUS 0x02000000
-
-/* USB3 Link Change */
-#define MV_U3D_LINK_CHANGE_LINK_UP 0x00000001
-#define MV_U3D_LINK_CHANGE_SUSPEND 0x00000002
-#define MV_U3D_LINK_CHANGE_RESUME 0x00000004
-#define MV_U3D_LINK_CHANGE_WRESET 0x00000008
-#define MV_U3D_LINK_CHANGE_HRESET 0x00000010
-#define MV_U3D_LINK_CHANGE_VBUS_INVALID 0x00000020
-#define MV_U3D_LINK_CHANGE_INACT 0x00000040
-#define MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0 0x00000080
-#define MV_U3D_LINK_CHANGE_U1 0x00000100
-#define MV_U3D_LINK_CHANGE_U2 0x00000200
-#define MV_U3D_LINK_CHANGE_U3 0x00000400
-
-/* bridge setting */
-#define MV_U3D_BRIDGE_SETTING_VBUS_VALID (1 << 16)
-
-/* Command Register Bit Masks */
-#define MV_U3D_CMD_RUN_STOP 0x00000001
-#define MV_U3D_CMD_CTRL_RESET 0x00000002
-
-/* ep control register */
-#define MV_U3D_EPXCR_EP_TYPE_CONTROL 0
-#define MV_U3D_EPXCR_EP_TYPE_ISOC 1
-#define MV_U3D_EPXCR_EP_TYPE_BULK 2
-#define MV_U3D_EPXCR_EP_TYPE_INT 3
-#define MV_U3D_EPXCR_EP_ENABLE_SHIFT 4
-#define MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT 12
-#define MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT 16
-#define MV_U3D_USB_BULK_BURST_OUT 6
-#define MV_U3D_USB_BULK_BURST_IN 14
-
-#define MV_U3D_EPXCR_EP_FLUSH (1 << 7)
-#define MV_U3D_EPXCR_EP_HALT (1 << 1)
-#define MV_U3D_EPXCR_EP_INIT (1)
-
-/* TX/RX Status Register */
-#define MV_U3D_XFERSTATUS_COMPLETE_SHIFT 24
-#define MV_U3D_COMPLETE_INVALID 0
-#define MV_U3D_COMPLETE_SUCCESS 1
-#define MV_U3D_COMPLETE_BUFF_ERR 2
-#define MV_U3D_COMPLETE_SHORT_PACKET 3
-#define MV_U3D_COMPLETE_TRB_ERR 5
-#define MV_U3D_XFERSTATUS_TRB_LENGTH_MASK (0xFFFFFF)
-
-#define MV_U3D_USB_LINK_BYPASS_VBUS 0x8
-
-#define MV_U3D_LTSSM_PHY_INIT_DONE 0x80000000
-#define MV_U3D_LTSSM_NEVER_GO_COMPLIANCE 0x40000000
-
-#define MV_U3D_USB3_OP_REGS_OFFSET 0x100
-#define MV_U3D_USB3_PHY_OFFSET 0xB800
-
-#define DCS_ENABLE 0x1
-
-/* timeout */
-#define MV_U3D_RESET_TIMEOUT 10000
-#define MV_U3D_FLUSH_TIMEOUT 100000
-#define MV_U3D_OWN_TIMEOUT 10000
-#define LOOPS_USEC_SHIFT 4
-#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
-#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
-
-/* ep direction */
-#define MV_U3D_EP_DIR_IN 1
-#define MV_U3D_EP_DIR_OUT 0
-#define mv_u3d_ep_dir(ep) (((ep)->ep_num == 0) ? \
- ((ep)->u3d->ep0_dir) : ((ep)->direction))
-
-/* usb capability registers */
-struct mv_u3d_cap_regs {
- u32 rsvd[5];
- u32 dboff; /* doorbell register offset */
- u32 rtsoff; /* runtime register offset */
- u32 vuoff; /* vendor unique register offset */
-};
-
-/* operation registers */
-struct mv_u3d_op_regs {
- u32 usbcmd; /* Command register */
- u32 rsvd1[11];
- u32 dcbaapl; /* Device Context Base Address low register */
- u32 dcbaaph; /* Device Context Base Address high register */
- u32 rsvd2[243];
- u32 portsc; /* port status and control register*/
- u32 portlinkinfo; /* port link info register*/
- u32 rsvd3[9917];
- u32 doorbell; /* doorbell register */
-};
-
-/* control endpoint enable registers */
-struct epxcr {
- u32 epxoutcr0; /* ep out control 0 register */
- u32 epxoutcr1; /* ep out control 1 register */
- u32 epxincr0; /* ep in control 0 register */
- u32 epxincr1; /* ep in control 1 register */
-};
-
-/* transfer status registers */
-struct xferstatus {
- u32 curdeqlo; /* current TRB pointer low */
- u32 curdeqhi; /* current TRB pointer high */
- u32 statuslo; /* transfer status low */
- u32 statushi; /* transfer status high */
-};
-
-/* vendor unique control registers */
-struct mv_u3d_vuc_regs {
- u32 ctrlepenable; /* control endpoint enable register */
- u32 setuplock; /* setup lock register */
- u32 endcomplete; /* endpoint transfer complete register */
- u32 intrcause; /* interrupt cause register */
- u32 intrenable; /* interrupt enable register */
- u32 trbcomplete; /* TRB complete register */
- u32 linkchange; /* link change register */
- u32 rsvd1[5];
- u32 trbunderrun; /* TRB underrun register */
- u32 rsvd2[43];
- u32 bridgesetting; /* bridge setting register */
- u32 rsvd3[7];
- struct xferstatus txst[16]; /* TX status register */
- struct xferstatus rxst[16]; /* RX status register */
- u32 ltssm; /* LTSSM control register */
- u32 pipe; /* PIPE control register */
- u32 linkcr0; /* link control 0 register */
- u32 linkcr1; /* link control 1 register */
- u32 rsvd6[60];
- u32 mib0; /* MIB0 counter register */
- u32 usblink; /* usb link control register */
- u32 ltssmstate; /* LTSSM state register */
- u32 linkerrorcause; /* link error cause register */
- u32 rsvd7[60];
- u32 devaddrtiebrkr; /* device address and tie breaker */
- u32 itpinfo0; /* ITP info 0 register */
- u32 itpinfo1; /* ITP info 1 register */
- u32 rsvd8[61];
- struct epxcr epcr[16]; /* ep control register */
- u32 rsvd9[64];
- u32 phyaddr; /* PHY address register */
- u32 phydata; /* PHY data register */
-};
-
-/* Endpoint context structure */
-struct mv_u3d_ep_context {
- u32 rsvd0;
- u32 rsvd1;
- u32 trb_addr_lo; /* TRB address low 32 bit */
- u32 trb_addr_hi; /* TRB address high 32 bit */
- u32 rsvd2;
- u32 rsvd3;
- struct usb_ctrlrequest setup_buffer; /* setup data buffer */
-};
-
-/* TRB control data structure */
-struct mv_u3d_trb_ctrl {
- u32 own:1; /* owner of TRB */
- u32 rsvd1:3;
- u32 chain:1; /* associate this TRB with the
- next TRB on the Ring */
- u32 ioc:1; /* interrupt on complete */
- u32 rsvd2:4;
- u32 type:6; /* TRB type */
-#define TYPE_NORMAL 1
-#define TYPE_DATA 3
-#define TYPE_LINK 6
- u32 dir:1; /* Working at data stage of control endpoint
- operation. 0 is OUT and 1 is IN. */
- u32 rsvd3:15;
-};
-
-/* TRB data structure
- * For multiple TRB, all the TRBs' physical address should be continuous.
- */
-struct mv_u3d_trb_hw {
- u32 buf_addr_lo; /* data buffer address low 32 bit */
- u32 buf_addr_hi; /* data buffer address high 32 bit */
- u32 trb_len; /* transfer length */
- struct mv_u3d_trb_ctrl ctrl; /* TRB control data */
-};
-
-/* TRB structure */
-struct mv_u3d_trb {
- struct mv_u3d_trb_hw *trb_hw; /* point to the trb_hw structure */
- dma_addr_t trb_dma; /* dma address for this trb_hw */
- struct list_head trb_list; /* trb list */
-};
-
-/* device data structure */
-struct mv_u3d {
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
- spinlock_t lock; /* device lock */
- struct completion *done;
- struct device *dev;
- int irq;
-
- /* usb controller registers */
- struct mv_u3d_cap_regs __iomem *cap_regs;
- struct mv_u3d_op_regs __iomem *op_regs;
- struct mv_u3d_vuc_regs __iomem *vuc_regs;
- void __iomem *phy_regs;
-
- unsigned int max_eps;
- struct mv_u3d_ep_context *ep_context;
- size_t ep_context_size;
- dma_addr_t ep_context_dma;
-
- struct dma_pool *trb_pool; /* for TRB data structure */
- struct mv_u3d_ep *eps;
-
- struct mv_u3d_req *status_req; /* ep0 status request */
- struct usb_ctrlrequest local_setup_buff; /* store setup data*/
-
- unsigned int resume_state; /* USB state to resume */
- unsigned int usb_state; /* USB current state */
- unsigned int ep0_state; /* Endpoint zero state */
- unsigned int ep0_dir;
-
- unsigned int dev_addr; /* device address */
-
- unsigned int errors;
-
- unsigned softconnect:1;
- unsigned vbus_active:1; /* vbus is active or not */
- unsigned remote_wakeup:1; /* support remote wakeup */
- unsigned clock_gating:1; /* clock gating or not */
- unsigned active:1; /* udc is active or not */
- unsigned vbus_valid_detect:1; /* udc vbus detection */
-
- struct mv_usb_addon_irq *vbus;
- unsigned int power;
-
- struct clk *clk;
-};
-
-/* endpoint data structure */
-struct mv_u3d_ep {
- struct usb_ep ep;
- struct mv_u3d *u3d;
- struct list_head queue; /* ep request queued hardware */
- struct list_head req_list; /* list of ep request */
- struct mv_u3d_ep_context *ep_context; /* ep context */
- u32 direction;
- char name[14];
- u32 processing; /* there is ep request
- queued on haredware */
- spinlock_t req_lock; /* ep lock */
- unsigned wedge:1;
- unsigned enabled:1;
- unsigned ep_type:2;
- unsigned ep_num:8;
-};
-
-/* request data structure */
-struct mv_u3d_req {
- struct usb_request req;
- struct mv_u3d_ep *ep;
- struct list_head queue; /* ep requst queued on hardware */
- struct list_head list; /* ep request list */
- struct list_head trb_list; /* trb list of a request */
-
- struct mv_u3d_trb *trb_head; /* point to first trb of a request */
- unsigned trb_count; /* TRB number in the chain */
- unsigned chain; /* TRB chain or not */
-};
-
-#endif
diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c
deleted file mode 100644
index 062f43e146aa..000000000000
--- a/drivers/usb/gadget/udc/mv_u3d_core.c
+++ /dev/null
@@ -1,2062 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/pm.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/mv_usb.h>
-#include <linux/clk.h>
-
-#include "mv_u3d.h"
-
-#define DRIVER_DESC "Marvell PXA USB3.0 Device Controller driver"
-
-static const char driver_name[] = "mv_u3d";
-
-static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status);
-static void mv_u3d_stop_activity(struct mv_u3d *u3d,
- struct usb_gadget_driver *driver);
-
-/* for endpoint 0 operations */
-static const struct usb_endpoint_descriptor mv_u3d_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = MV_U3D_EP0_MAX_PKT_SIZE,
-};
-
-static void mv_u3d_ep0_reset(struct mv_u3d *u3d)
-{
- struct mv_u3d_ep *ep;
- u32 epxcr;
- int i;
-
- for (i = 0; i < 2; i++) {
- ep = &u3d->eps[i];
- ep->u3d = u3d;
-
- /* ep0 ep context, ep0 in and out share the same ep context */
- ep->ep_context = &u3d->ep_context[1];
- }
-
- /* reset ep state machine */
- /* reset ep0 out */
- epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
- epxcr |= MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0);
- udelay(5);
- epxcr &= ~MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr0);
-
- epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE
- << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | MV_U3D_EPXCR_EP_TYPE_CONTROL);
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxoutcr1);
-
- /* reset ep0 in */
- epxcr = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
- epxcr |= MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0);
- udelay(5);
- epxcr &= ~MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr0);
-
- epxcr = ((MV_U3D_EP0_MAX_PKT_SIZE
- << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | MV_U3D_EPXCR_EP_TYPE_CONTROL);
- iowrite32(epxcr, &u3d->vuc_regs->epcr[0].epxincr1);
-}
-
-static void mv_u3d_ep0_stall(struct mv_u3d *u3d)
-{
- u32 tmp;
- dev_dbg(u3d->dev, "%s\n", __func__);
-
- /* set TX and RX to stall */
- tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
- tmp |= MV_U3D_EPXCR_EP_HALT;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
-
- tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
- tmp |= MV_U3D_EPXCR_EP_HALT;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
-
- /* update ep0 state */
- u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
- u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
-}
-
-static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
- struct mv_u3d_req *curr_req)
-{
- struct mv_u3d_trb *curr_trb;
- int actual, remaining_length = 0;
- int direction, ep_num;
- int retval = 0;
- u32 tmp, status, length;
-
- direction = index % 2;
- ep_num = index / 2;
-
- actual = curr_req->req.length;
-
- while (!list_empty(&curr_req->trb_list)) {
- curr_trb = list_entry(curr_req->trb_list.next,
- struct mv_u3d_trb, trb_list);
- if (!curr_trb->trb_hw->ctrl.own) {
- dev_err(u3d->dev, "%s, TRB own error!\n",
- u3d->eps[index].name);
- return 1;
- }
-
- curr_trb->trb_hw->ctrl.own = 0;
- if (direction == MV_U3D_EP_DIR_OUT)
- tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo);
- else
- tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo);
-
- status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT;
- length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK;
-
- if (status == MV_U3D_COMPLETE_SUCCESS ||
- (status == MV_U3D_COMPLETE_SHORT_PACKET &&
- direction == MV_U3D_EP_DIR_OUT)) {
- remaining_length += length;
- actual -= remaining_length;
- } else {
- dev_err(u3d->dev,
- "complete_tr error: ep=%d %s: error = 0x%x\n",
- index >> 1, direction ? "SEND" : "RECV",
- status);
- retval = -EPROTO;
- }
-
- list_del_init(&curr_trb->trb_list);
- }
- if (retval)
- return retval;
-
- curr_req->req.actual = actual;
- return 0;
-}
-
-/*
- * mv_u3d_done() - retire a request; caller blocked irqs
- * @status : request status to be set, only works when
- * request is still in progress.
- */
-static
-void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
- __releases(&ep->udc->lock)
- __acquires(&ep->udc->lock)
-{
- struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
-
- dev_dbg(u3d->dev, "mv_u3d_done: remove req->queue\n");
- /* Removed the req from ep queue */
- list_del_init(&req->queue);
-
- /* req.status should be set as -EINPROGRESS in ep_queue() */
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- /* Free trb for the request */
- if (!req->chain)
- dma_pool_free(u3d->trb_pool,
- req->trb_head->trb_hw, req->trb_head->trb_dma);
- else {
- dma_unmap_single(ep->u3d->gadget.dev.parent,
- (dma_addr_t)req->trb_head->trb_dma,
- req->trb_count * sizeof(struct mv_u3d_trb_hw),
- DMA_BIDIRECTIONAL);
- kfree(req->trb_head->trb_hw);
- }
- kfree(req->trb_head);
-
- usb_gadget_unmap_request(&u3d->gadget, &req->req, mv_u3d_ep_dir(ep));
-
- if (status && (status != -ESHUTDOWN)) {
- dev_dbg(u3d->dev, "complete %s req %p stat %d len %u/%u",
- ep->ep.name, &req->req, status,
- req->req.actual, req->req.length);
- }
-
- spin_unlock(&ep->u3d->lock);
-
- usb_gadget_giveback_request(&ep->ep, &req->req);
-
- spin_lock(&ep->u3d->lock);
-}
-
-static int mv_u3d_queue_trb(struct mv_u3d_ep *ep, struct mv_u3d_req *req)
-{
- u32 tmp, direction;
- struct mv_u3d *u3d;
- struct mv_u3d_ep_context *ep_context;
- int retval = 0;
-
- u3d = ep->u3d;
- direction = mv_u3d_ep_dir(ep);
-
- /* ep0 in and out share the same ep context slot 1*/
- if (ep->ep_num == 0)
- ep_context = &(u3d->ep_context[1]);
- else
- ep_context = &(u3d->ep_context[ep->ep_num * 2 + direction]);
-
- /* check if the pipe is empty or not */
- if (!list_empty(&ep->queue)) {
- dev_err(u3d->dev, "add trb to non-empty queue!\n");
- retval = -ENOMEM;
- WARN_ON(1);
- } else {
- ep_context->rsvd0 = cpu_to_le32(1);
- ep_context->rsvd1 = 0;
-
- /* Configure the trb address and set the DCS bit.
- * Both DCS bit and own bit in trb should be set.
- */
- ep_context->trb_addr_lo =
- cpu_to_le32(req->trb_head->trb_dma | DCS_ENABLE);
- ep_context->trb_addr_hi = 0;
-
- /* Ensure that updates to the EP Context will
- * occure before Ring Bell.
- */
- wmb();
-
- /* ring bell the ep */
- if (ep->ep_num == 0)
- tmp = 0x1;
- else
- tmp = ep->ep_num * 2
- + ((direction == MV_U3D_EP_DIR_OUT) ? 0 : 1);
-
- iowrite32(tmp, &u3d->op_regs->doorbell);
- }
- return retval;
-}
-
-static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,
- unsigned *length, dma_addr_t *dma)
-{
- u32 temp;
- unsigned int direction;
- struct mv_u3d_trb *trb;
- struct mv_u3d_trb_hw *trb_hw;
- struct mv_u3d *u3d;
-
- /* how big will this transfer be? */
- *length = req->req.length - req->req.actual;
- BUG_ON(*length > (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER);
-
- u3d = req->ep->u3d;
-
- trb = kzalloc(sizeof(*trb), GFP_ATOMIC);
- if (!trb)
- return NULL;
-
- /*
- * Be careful that no _GFP_HIGHMEM is set,
- * or we can not use dma_to_virt
- * cannot use GFP_KERNEL in spin lock
- */
- trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma);
- if (!trb_hw) {
- kfree(trb);
- dev_err(u3d->dev,
- "%s, dma_pool_alloc fail\n", __func__);
- return NULL;
- }
- trb->trb_dma = *dma;
- trb->trb_hw = trb_hw;
-
- /* initialize buffer page pointers */
- temp = (u32)(req->req.dma + req->req.actual);
-
- trb_hw->buf_addr_lo = cpu_to_le32(temp);
- trb_hw->buf_addr_hi = 0;
- trb_hw->trb_len = cpu_to_le32(*length);
- trb_hw->ctrl.own = 1;
-
- if (req->ep->ep_num == 0)
- trb_hw->ctrl.type = TYPE_DATA;
- else
- trb_hw->ctrl.type = TYPE_NORMAL;
-
- req->req.actual += *length;
-
- direction = mv_u3d_ep_dir(req->ep);
- if (direction == MV_U3D_EP_DIR_IN)
- trb_hw->ctrl.dir = 1;
- else
- trb_hw->ctrl.dir = 0;
-
- /* Enable interrupt for the last trb of a request */
- if (!req->req.no_interrupt)
- trb_hw->ctrl.ioc = 1;
-
- trb_hw->ctrl.chain = 0;
-
- wmb();
- return trb;
-}
-
-static int mv_u3d_build_trb_chain(struct mv_u3d_req *req, unsigned *length,
- struct mv_u3d_trb *trb, int *is_last)
-{
- u32 temp;
- unsigned int direction;
- struct mv_u3d *u3d;
-
- /* how big will this transfer be? */
- *length = min(req->req.length - req->req.actual,
- (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER);
-
- u3d = req->ep->u3d;
-
- trb->trb_dma = 0;
-
- /* initialize buffer page pointers */
- temp = (u32)(req->req.dma + req->req.actual);
-
- trb->trb_hw->buf_addr_lo = cpu_to_le32(temp);
- trb->trb_hw->buf_addr_hi = 0;
- trb->trb_hw->trb_len = cpu_to_le32(*length);
- trb->trb_hw->ctrl.own = 1;
-
- if (req->ep->ep_num == 0)
- trb->trb_hw->ctrl.type = TYPE_DATA;
- else
- trb->trb_hw->ctrl.type = TYPE_NORMAL;
-
- req->req.actual += *length;
-
- direction = mv_u3d_ep_dir(req->ep);
- if (direction == MV_U3D_EP_DIR_IN)
- trb->trb_hw->ctrl.dir = 1;
- else
- trb->trb_hw->ctrl.dir = 0;
-
- /* zlp is needed if req->req.zero is set */
- if (req->req.zero) {
- if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
- *is_last = 1;
- else
- *is_last = 0;
- } else if (req->req.length == req->req.actual)
- *is_last = 1;
- else
- *is_last = 0;
-
- /* Enable interrupt for the last trb of a request */
- if (*is_last && !req->req.no_interrupt)
- trb->trb_hw->ctrl.ioc = 1;
-
- if (*is_last)
- trb->trb_hw->ctrl.chain = 0;
- else {
- trb->trb_hw->ctrl.chain = 1;
- dev_dbg(u3d->dev, "chain trb\n");
- }
-
- wmb();
-
- return 0;
-}
-
-/* generate TRB linked list for a request
- * usb controller only supports continous trb chain,
- * that trb structure physical address should be continous.
- */
-static int mv_u3d_req_to_trb(struct mv_u3d_req *req)
-{
- unsigned count;
- int is_last;
- struct mv_u3d_trb *trb;
- struct mv_u3d_trb_hw *trb_hw;
- struct mv_u3d *u3d;
- dma_addr_t dma;
- unsigned length;
- unsigned trb_num;
-
- u3d = req->ep->u3d;
-
- INIT_LIST_HEAD(&req->trb_list);
-
- length = req->req.length - req->req.actual;
- /* normally the request transfer length is less than 16KB.
- * we use buil_trb_one() to optimize it.
- */
- if (length <= (unsigned)MV_U3D_EP_MAX_LENGTH_TRANSFER) {
- trb = mv_u3d_build_trb_one(req, &count, &dma);
- list_add_tail(&trb->trb_list, &req->trb_list);
- req->trb_head = trb;
- req->trb_count = 1;
- req->chain = 0;
- } else {
- trb_num = length / MV_U3D_EP_MAX_LENGTH_TRANSFER;
- if (length % MV_U3D_EP_MAX_LENGTH_TRANSFER)
- trb_num++;
-
- trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC);
- if (!trb)
- return -ENOMEM;
-
- trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC);
- if (!trb_hw) {
- kfree(trb);
- return -ENOMEM;
- }
-
- do {
- trb->trb_hw = trb_hw;
- if (mv_u3d_build_trb_chain(req, &count,
- trb, &is_last)) {
- dev_err(u3d->dev,
- "%s, mv_u3d_build_trb_chain fail\n",
- __func__);
- return -EIO;
- }
-
- list_add_tail(&trb->trb_list, &req->trb_list);
- req->trb_count++;
- trb++;
- trb_hw++;
- } while (!is_last);
-
- req->trb_head = list_entry(req->trb_list.next,
- struct mv_u3d_trb, trb_list);
- req->trb_head->trb_dma = dma_map_single(u3d->gadget.dev.parent,
- req->trb_head->trb_hw,
- trb_num * sizeof(*trb_hw),
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(u3d->gadget.dev.parent,
- req->trb_head->trb_dma)) {
- kfree(req->trb_head->trb_hw);
- kfree(req->trb_head);
- return -EFAULT;
- }
-
- req->chain = 1;
- }
-
- return 0;
-}
-
-static int
-mv_u3d_start_queue(struct mv_u3d_ep *ep)
-{
- struct mv_u3d *u3d = ep->u3d;
- struct mv_u3d_req *req;
- int ret;
-
- if (!list_empty(&ep->req_list) && !ep->processing)
- req = list_entry(ep->req_list.next, struct mv_u3d_req, list);
- else
- return 0;
-
- ep->processing = 1;
-
- /* set up dma mapping */
- ret = usb_gadget_map_request(&u3d->gadget, &req->req,
- mv_u3d_ep_dir(ep));
- if (ret)
- goto break_processing;
-
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->trb_count = 0;
-
- /* build trbs */
- ret = mv_u3d_req_to_trb(req);
- if (ret) {
- dev_err(u3d->dev, "%s, mv_u3d_req_to_trb fail\n", __func__);
- goto break_processing;
- }
-
- /* and push them to device queue */
- ret = mv_u3d_queue_trb(ep, req);
- if (ret)
- goto break_processing;
-
- /* irq handler advances the queue */
- list_add_tail(&req->queue, &ep->queue);
-
- return 0;
-
-break_processing:
- ep->processing = 0;
- return ret;
-}
-
-static int mv_u3d_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct mv_u3d *u3d;
- struct mv_u3d_ep *ep;
- u16 max = 0;
- unsigned maxburst = 0;
- u32 epxcr, direction;
-
- if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
-
- ep = container_of(_ep, struct mv_u3d_ep, ep);
- u3d = ep->u3d;
-
- if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- direction = mv_u3d_ep_dir(ep);
- max = le16_to_cpu(desc->wMaxPacketSize);
-
- if (!_ep->maxburst)
- _ep->maxburst = 1;
- maxburst = _ep->maxburst;
-
- /* Set the max burst size */
- switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_BULK:
- if (maxburst > 16) {
- dev_dbg(u3d->dev,
- "max burst should not be greater "
- "than 16 on bulk ep\n");
- maxburst = 1;
- _ep->maxburst = maxburst;
- }
- dev_dbg(u3d->dev,
- "maxburst: %d on bulk %s\n", maxburst, ep->name);
- break;
- case USB_ENDPOINT_XFER_CONTROL:
- /* control transfer only supports maxburst as one */
- maxburst = 1;
- _ep->maxburst = maxburst;
- break;
- case USB_ENDPOINT_XFER_INT:
- if (maxburst != 1) {
- dev_dbg(u3d->dev,
- "max burst should be 1 on int ep "
- "if transfer size is not 1024\n");
- maxburst = 1;
- _ep->maxburst = maxburst;
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (maxburst != 1) {
- dev_dbg(u3d->dev,
- "max burst should be 1 on isoc ep "
- "if transfer size is not 1024\n");
- maxburst = 1;
- _ep->maxburst = maxburst;
- }
- break;
- default:
- goto en_done;
- }
-
- ep->ep.maxpacket = max;
- ep->ep.desc = desc;
- ep->enabled = 1;
-
- /* Enable the endpoint for Rx or Tx and set the endpoint type */
- if (direction == MV_U3D_EP_DIR_OUT) {
- epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
- epxcr |= MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
- udelay(5);
- epxcr &= ~MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
-
- epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
- | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
- } else {
- epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
- epxcr |= MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
- udelay(5);
- epxcr &= ~MV_U3D_EPXCR_EP_INIT;
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
-
- epxcr = ((max << MV_U3D_EPXCR_MAX_PACKET_SIZE_SHIFT)
- | ((maxburst - 1) << MV_U3D_EPXCR_MAX_BURST_SIZE_SHIFT)
- | (1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK));
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
- }
-
- return 0;
-en_done:
- return -EINVAL;
-}
-
-static int mv_u3d_ep_disable(struct usb_ep *_ep)
-{
- struct mv_u3d *u3d;
- struct mv_u3d_ep *ep;
- u32 epxcr, direction;
- unsigned long flags;
-
- if (!_ep)
- return -EINVAL;
-
- ep = container_of(_ep, struct mv_u3d_ep, ep);
- if (!ep->ep.desc)
- return -EINVAL;
-
- u3d = ep->u3d;
-
- direction = mv_u3d_ep_dir(ep);
-
- /* nuke all pending requests (does flush) */
- spin_lock_irqsave(&u3d->lock, flags);
- mv_u3d_nuke(ep, -ESHUTDOWN);
- spin_unlock_irqrestore(&u3d->lock, flags);
-
- /* Disable the endpoint for Rx or Tx and reset the endpoint type */
- if (direction == MV_U3D_EP_DIR_OUT) {
- epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
- epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | USB_ENDPOINT_XFERTYPE_MASK);
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr1);
- } else {
- epxcr = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
- epxcr &= ~((1 << MV_U3D_EPXCR_EP_ENABLE_SHIFT)
- | USB_ENDPOINT_XFERTYPE_MASK);
- iowrite32(epxcr, &u3d->vuc_regs->epcr[ep->ep_num].epxincr1);
- }
-
- ep->enabled = 0;
-
- ep->ep.desc = NULL;
- return 0;
-}
-
-static struct usb_request *
-mv_u3d_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct mv_u3d_req *req;
-
- req = kzalloc(sizeof *req, gfp_flags);
- if (!req)
- return NULL;
-
- INIT_LIST_HEAD(&req->queue);
-
- return &req->req;
-}
-
-static void mv_u3d_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct mv_u3d_req *req = container_of(_req, struct mv_u3d_req, req);
-
- kfree(req);
-}
-
-static void mv_u3d_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct mv_u3d *u3d;
- u32 direction;
- struct mv_u3d_ep *ep = container_of(_ep, struct mv_u3d_ep, ep);
- unsigned int loops;
- u32 tmp;
-
- /* if endpoint is not enabled, cannot flush endpoint */
- if (!ep->enabled)
- return;
-
- u3d = ep->u3d;
- direction = mv_u3d_ep_dir(ep);
-
- /* ep0 need clear bit after flushing fifo. */
- if (!ep->ep_num) {
- if (direction == MV_U3D_EP_DIR_OUT) {
- tmp = ioread32(&u3d->vuc_regs->epcr[0].epxoutcr0);
- tmp |= MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
- udelay(10);
- tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxoutcr0);
- } else {
- tmp = ioread32(&u3d->vuc_regs->epcr[0].epxincr0);
- tmp |= MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
- udelay(10);
- tmp &= ~MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[0].epxincr0);
- }
- return;
- }
-
- if (direction == MV_U3D_EP_DIR_OUT) {
- tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
- tmp |= MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
-
- /* Wait until flushing completed */
- loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
- while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0) &
- MV_U3D_EPXCR_EP_FLUSH) {
- /*
- * EP_FLUSH bit should be cleared to indicate this
- * operation is complete
- */
- if (loops == 0) {
- dev_dbg(u3d->dev,
- "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
- direction ? "in" : "out");
- return;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
- } else { /* EP_DIR_IN */
- tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
- tmp |= MV_U3D_EPXCR_EP_FLUSH;
- iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
-
- /* Wait until flushing completed */
- loops = LOOPS(MV_U3D_FLUSH_TIMEOUT);
- while (ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0) &
- MV_U3D_EPXCR_EP_FLUSH) {
- /*
- * EP_FLUSH bit should be cleared to indicate this
- * operation is complete
- */
- if (loops == 0) {
- dev_dbg(u3d->dev,
- "EP FLUSH TIMEOUT for ep%d%s\n", ep->ep_num,
- direction ? "in" : "out");
- return;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
- }
-}
-
-/* queues (submits) an I/O request to an endpoint */
-static int
-mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- struct mv_u3d_ep *ep;
- struct mv_u3d_req *req;
- struct mv_u3d *u3d;
- unsigned long flags;
- int is_first_req = 0;
-
- if (unlikely(!_ep || !_req))
- return -EINVAL;
-
- ep = container_of(_ep, struct mv_u3d_ep, ep);
- u3d = ep->u3d;
-
- req = container_of(_req, struct mv_u3d_req, req);
-
- if (!ep->ep_num
- && u3d->ep0_state == MV_U3D_STATUS_STAGE
- && !_req->length) {
- dev_dbg(u3d->dev, "ep0 status stage\n");
- u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
- return 0;
- }
-
- dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
- __func__, _ep->name, req);
-
- /* catch various bogus parameters */
- if (!req->req.complete || !req->req.buf
- || !list_empty(&req->queue)) {
- dev_err(u3d->dev,
- "%s, bad params, _req: 0x%p,"
- "req->req.complete: 0x%p, req->req.buf: 0x%p,"
- "list_empty: 0x%x\n",
- __func__, _req,
- req->req.complete, req->req.buf,
- list_empty(&req->queue));
- return -EINVAL;
- }
- if (unlikely(!ep->ep.desc)) {
- dev_err(u3d->dev, "%s, bad ep\n", __func__);
- return -EINVAL;
- }
- if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- if (req->req.length > ep->ep.maxpacket)
- return -EMSGSIZE;
- }
-
- if (!u3d->driver || u3d->gadget.speed == USB_SPEED_UNKNOWN) {
- dev_err(u3d->dev,
- "bad params of driver/speed\n");
- return -ESHUTDOWN;
- }
-
- req->ep = ep;
-
- /* Software list handles usb request. */
- spin_lock_irqsave(&ep->req_lock, flags);
- is_first_req = list_empty(&ep->req_list);
- list_add_tail(&req->list, &ep->req_list);
- spin_unlock_irqrestore(&ep->req_lock, flags);
- if (!is_first_req) {
- dev_dbg(u3d->dev, "list is not empty\n");
- return 0;
- }
-
- dev_dbg(u3d->dev, "call mv_u3d_start_queue from usb_ep_queue\n");
- spin_lock_irqsave(&u3d->lock, flags);
- mv_u3d_start_queue(ep);
- spin_unlock_irqrestore(&u3d->lock, flags);
- return 0;
-}
-
-/* dequeues (cancels, unlinks) an I/O request from an endpoint */
-static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct mv_u3d_ep *ep;
- struct mv_u3d_req *req = NULL, *iter;
- struct mv_u3d *u3d;
- struct mv_u3d_ep_context *ep_context;
- struct mv_u3d_req *next_req;
-
- unsigned long flags;
- int ret = 0;
-
- if (!_ep || !_req)
- return -EINVAL;
-
- ep = container_of(_ep, struct mv_u3d_ep, ep);
- u3d = ep->u3d;
-
- spin_lock_irqsave(&ep->u3d->lock, flags);
-
- /* make sure it's actually queued on this endpoint */
- list_for_each_entry(iter, &ep->queue, queue) {
- if (&iter->req != _req)
- continue;
- req = iter;
- break;
- }
- if (!req) {
- ret = -EINVAL;
- goto out;
- }
-
- /* The request is in progress, or completed but not dequeued */
- if (ep->queue.next == &req->queue) {
- _req->status = -ECONNRESET;
- mv_u3d_ep_fifo_flush(_ep);
-
- /* The request isn't the last request in this ep queue */
- if (req->queue.next != &ep->queue) {
- dev_dbg(u3d->dev,
- "it is the last request in this ep queue\n");
- ep_context = ep->ep_context;
- next_req = list_entry(req->queue.next,
- struct mv_u3d_req, queue);
-
- /* Point first TRB of next request to the EP context. */
- iowrite32((unsigned long) next_req->trb_head,
- &ep_context->trb_addr_lo);
- } else {
- struct mv_u3d_ep_context *ep_context;
- ep_context = ep->ep_context;
- ep_context->trb_addr_lo = 0;
- ep_context->trb_addr_hi = 0;
- }
-
- } else
- WARN_ON(1);
-
- mv_u3d_done(ep, req, -ECONNRESET);
-
- /* remove the req from the ep req list */
- if (!list_empty(&ep->req_list)) {
- struct mv_u3d_req *curr_req;
- curr_req = list_entry(ep->req_list.next,
- struct mv_u3d_req, list);
- if (curr_req == req) {
- list_del_init(&req->list);
- ep->processing = 0;
- }
- }
-
-out:
- spin_unlock_irqrestore(&ep->u3d->lock, flags);
- return ret;
-}
-
-static void
-mv_u3d_ep_set_stall(struct mv_u3d *u3d, u8 ep_num, u8 direction, int stall)
-{
- u32 tmp;
- struct mv_u3d_ep *ep = u3d->eps;
-
- dev_dbg(u3d->dev, "%s\n", __func__);
- if (direction == MV_U3D_EP_DIR_OUT) {
- tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
- if (stall)
- tmp |= MV_U3D_EPXCR_EP_HALT;
- else
- tmp &= ~MV_U3D_EPXCR_EP_HALT;
- iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxoutcr0);
- } else {
- tmp = ioread32(&u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
- if (stall)
- tmp |= MV_U3D_EPXCR_EP_HALT;
- else
- tmp &= ~MV_U3D_EPXCR_EP_HALT;
- iowrite32(tmp, &u3d->vuc_regs->epcr[ep->ep_num].epxincr0);
- }
-}
-
-static int mv_u3d_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
-{
- struct mv_u3d_ep *ep;
- unsigned long flags;
- int status = 0;
- struct mv_u3d *u3d;
-
- ep = container_of(_ep, struct mv_u3d_ep, ep);
- u3d = ep->u3d;
- if (!ep->ep.desc) {
- status = -EINVAL;
- goto out;
- }
-
- if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- status = -EOPNOTSUPP;
- goto out;
- }
-
- /*
- * Attempt to halt IN ep will fail if any transfer requests
- * are still queue
- */
- if (halt && (mv_u3d_ep_dir(ep) == MV_U3D_EP_DIR_IN)
- && !list_empty(&ep->queue)) {
- status = -EAGAIN;
- goto out;
- }
-
- spin_lock_irqsave(&ep->u3d->lock, flags);
- mv_u3d_ep_set_stall(u3d, ep->ep_num, mv_u3d_ep_dir(ep), halt);
- if (halt && wedge)
- ep->wedge = 1;
- else if (!halt)
- ep->wedge = 0;
- spin_unlock_irqrestore(&ep->u3d->lock, flags);
-
- if (ep->ep_num == 0)
- u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
-out:
- return status;
-}
-
-static int mv_u3d_ep_set_halt(struct usb_ep *_ep, int halt)
-{
- return mv_u3d_ep_set_halt_wedge(_ep, halt, 0);
-}
-
-static int mv_u3d_ep_set_wedge(struct usb_ep *_ep)
-{
- return mv_u3d_ep_set_halt_wedge(_ep, 1, 1);
-}
-
-static const struct usb_ep_ops mv_u3d_ep_ops = {
- .enable = mv_u3d_ep_enable,
- .disable = mv_u3d_ep_disable,
-
- .alloc_request = mv_u3d_alloc_request,
- .free_request = mv_u3d_free_request,
-
- .queue = mv_u3d_ep_queue,
- .dequeue = mv_u3d_ep_dequeue,
-
- .set_wedge = mv_u3d_ep_set_wedge,
- .set_halt = mv_u3d_ep_set_halt,
- .fifo_flush = mv_u3d_ep_fifo_flush,
-};
-
-static void mv_u3d_controller_stop(struct mv_u3d *u3d)
-{
- u32 tmp;
-
- if (!u3d->clock_gating && u3d->vbus_valid_detect)
- iowrite32(MV_U3D_INTR_ENABLE_VBUS_VALID,
- &u3d->vuc_regs->intrenable);
- else
- iowrite32(0, &u3d->vuc_regs->intrenable);
- iowrite32(~0x0, &u3d->vuc_regs->endcomplete);
- iowrite32(~0x0, &u3d->vuc_regs->trbunderrun);
- iowrite32(~0x0, &u3d->vuc_regs->trbcomplete);
- iowrite32(~0x0, &u3d->vuc_regs->linkchange);
- iowrite32(0x1, &u3d->vuc_regs->setuplock);
-
- /* Reset the RUN bit in the command register to stop USB */
- tmp = ioread32(&u3d->op_regs->usbcmd);
- tmp &= ~MV_U3D_CMD_RUN_STOP;
- iowrite32(tmp, &u3d->op_regs->usbcmd);
- dev_dbg(u3d->dev, "after u3d_stop, USBCMD 0x%x\n",
- ioread32(&u3d->op_regs->usbcmd));
-}
-
-static void mv_u3d_controller_start(struct mv_u3d *u3d)
-{
- u32 usbintr;
- u32 temp;
-
- /* enable link LTSSM state machine */
- temp = ioread32(&u3d->vuc_regs->ltssm);
- temp |= MV_U3D_LTSSM_PHY_INIT_DONE;
- iowrite32(temp, &u3d->vuc_regs->ltssm);
-
- /* Enable interrupts */
- usbintr = MV_U3D_INTR_ENABLE_LINK_CHG | MV_U3D_INTR_ENABLE_TXDESC_ERR |
- MV_U3D_INTR_ENABLE_RXDESC_ERR | MV_U3D_INTR_ENABLE_TX_COMPLETE |
- MV_U3D_INTR_ENABLE_RX_COMPLETE | MV_U3D_INTR_ENABLE_SETUP |
- (u3d->vbus_valid_detect ? MV_U3D_INTR_ENABLE_VBUS_VALID : 0);
- iowrite32(usbintr, &u3d->vuc_regs->intrenable);
-
- /* Enable ctrl ep */
- iowrite32(0x1, &u3d->vuc_regs->ctrlepenable);
-
- /* Set the Run bit in the command register */
- iowrite32(MV_U3D_CMD_RUN_STOP, &u3d->op_regs->usbcmd);
- dev_dbg(u3d->dev, "after u3d_start, USBCMD 0x%x\n",
- ioread32(&u3d->op_regs->usbcmd));
-}
-
-static int mv_u3d_controller_reset(struct mv_u3d *u3d)
-{
- unsigned int loops;
- u32 tmp;
-
- /* Stop the controller */
- tmp = ioread32(&u3d->op_regs->usbcmd);
- tmp &= ~MV_U3D_CMD_RUN_STOP;
- iowrite32(tmp, &u3d->op_regs->usbcmd);
-
- /* Reset the controller to get default values */
- iowrite32(MV_U3D_CMD_CTRL_RESET, &u3d->op_regs->usbcmd);
-
- /* wait for reset to complete */
- loops = LOOPS(MV_U3D_RESET_TIMEOUT);
- while (ioread32(&u3d->op_regs->usbcmd) & MV_U3D_CMD_CTRL_RESET) {
- if (loops == 0) {
- dev_err(u3d->dev,
- "Wait for RESET completed TIMEOUT\n");
- return -ETIMEDOUT;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
-
- /* Configure the Endpoint Context Address */
- iowrite32(u3d->ep_context_dma, &u3d->op_regs->dcbaapl);
- iowrite32(0, &u3d->op_regs->dcbaaph);
-
- return 0;
-}
-
-static int mv_u3d_enable(struct mv_u3d *u3d)
-{
- struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
- int retval;
-
- if (u3d->active)
- return 0;
-
- if (!u3d->clock_gating) {
- u3d->active = 1;
- return 0;
- }
-
- dev_dbg(u3d->dev, "enable u3d\n");
- clk_enable(u3d->clk);
- if (pdata->phy_init) {
- retval = pdata->phy_init(u3d->phy_regs);
- if (retval) {
- dev_err(u3d->dev,
- "init phy error %d\n", retval);
- clk_disable(u3d->clk);
- return retval;
- }
- }
- u3d->active = 1;
-
- return 0;
-}
-
-static void mv_u3d_disable(struct mv_u3d *u3d)
-{
- struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
- if (u3d->clock_gating && u3d->active) {
- dev_dbg(u3d->dev, "disable u3d\n");
- if (pdata->phy_deinit)
- pdata->phy_deinit(u3d->phy_regs);
- clk_disable(u3d->clk);
- u3d->active = 0;
- }
-}
-
-static int mv_u3d_vbus_session(struct usb_gadget *gadget, int is_active)
-{
- struct mv_u3d *u3d;
- unsigned long flags;
- int retval = 0;
-
- u3d = container_of(gadget, struct mv_u3d, gadget);
-
- spin_lock_irqsave(&u3d->lock, flags);
-
- u3d->vbus_active = (is_active != 0);
- dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n",
- __func__, u3d->softconnect, u3d->vbus_active);
- /*
- * 1. external VBUS detect: we can disable/enable clock on demand.
- * 2. UDC VBUS detect: we have to enable clock all the time.
- * 3. No VBUS detect: we have to enable clock all the time.
- */
- if (u3d->driver && u3d->softconnect && u3d->vbus_active) {
- retval = mv_u3d_enable(u3d);
- if (retval == 0) {
- /*
- * after clock is disabled, we lost all the register
- * context. We have to re-init registers
- */
- mv_u3d_controller_reset(u3d);
- mv_u3d_ep0_reset(u3d);
- mv_u3d_controller_start(u3d);
- }
- } else if (u3d->driver && u3d->softconnect) {
- if (!u3d->active)
- goto out;
-
- /* stop all the transfer in queue*/
- mv_u3d_stop_activity(u3d, u3d->driver);
- mv_u3d_controller_stop(u3d);
- mv_u3d_disable(u3d);
- }
-
-out:
- spin_unlock_irqrestore(&u3d->lock, flags);
- return retval;
-}
-
-/* constrain controller's VBUS power usage
- * This call is used by gadget drivers during SET_CONFIGURATION calls,
- * reporting how much power the device may consume. For example, this
- * could affect how quickly batteries are recharged.
- *
- * Returns zero on success, else negative errno.
- */
-static int mv_u3d_vbus_draw(struct usb_gadget *gadget, unsigned mA)
-{
- struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget);
-
- u3d->power = mA;
-
- return 0;
-}
-
-static int mv_u3d_pullup(struct usb_gadget *gadget, int is_on)
-{
- struct mv_u3d *u3d = container_of(gadget, struct mv_u3d, gadget);
- unsigned long flags;
- int retval = 0;
-
- spin_lock_irqsave(&u3d->lock, flags);
-
- dev_dbg(u3d->dev, "%s: softconnect %d, vbus_active %d\n",
- __func__, u3d->softconnect, u3d->vbus_active);
- u3d->softconnect = (is_on != 0);
- if (u3d->driver && u3d->softconnect && u3d->vbus_active) {
- retval = mv_u3d_enable(u3d);
- if (retval == 0) {
- /*
- * after clock is disabled, we lost all the register
- * context. We have to re-init registers
- */
- mv_u3d_controller_reset(u3d);
- mv_u3d_ep0_reset(u3d);
- mv_u3d_controller_start(u3d);
- }
- } else if (u3d->driver && u3d->vbus_active) {
- /* stop all the transfer in queue*/
- mv_u3d_stop_activity(u3d, u3d->driver);
- mv_u3d_controller_stop(u3d);
- mv_u3d_disable(u3d);
- }
-
- spin_unlock_irqrestore(&u3d->lock, flags);
-
- return retval;
-}
-
-static int mv_u3d_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
- struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
- unsigned long flags;
-
- if (u3d->driver)
- return -EBUSY;
-
- spin_lock_irqsave(&u3d->lock, flags);
-
- if (!u3d->clock_gating) {
- clk_enable(u3d->clk);
- if (pdata->phy_init)
- pdata->phy_init(u3d->phy_regs);
- }
-
- /* hook up the driver ... */
- u3d->driver = driver;
-
- u3d->ep0_dir = USB_DIR_OUT;
-
- spin_unlock_irqrestore(&u3d->lock, flags);
-
- u3d->vbus_valid_detect = 1;
-
- return 0;
-}
-
-static int mv_u3d_stop(struct usb_gadget *g)
-{
- struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
- struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
- unsigned long flags;
-
- u3d->vbus_valid_detect = 0;
- spin_lock_irqsave(&u3d->lock, flags);
-
- /* enable clock to access controller register */
- clk_enable(u3d->clk);
- if (pdata->phy_init)
- pdata->phy_init(u3d->phy_regs);
-
- mv_u3d_controller_stop(u3d);
- /* stop all usb activities */
- u3d->gadget.speed = USB_SPEED_UNKNOWN;
- mv_u3d_stop_activity(u3d, NULL);
- mv_u3d_disable(u3d);
-
- if (pdata->phy_deinit)
- pdata->phy_deinit(u3d->phy_regs);
- clk_disable(u3d->clk);
-
- spin_unlock_irqrestore(&u3d->lock, flags);
-
- u3d->driver = NULL;
-
- return 0;
-}
-
-/* device controller usb_gadget_ops structure */
-static const struct usb_gadget_ops mv_u3d_ops = {
- /* notify controller that VBUS is powered or not */
- .vbus_session = mv_u3d_vbus_session,
-
- /* constrain controller's VBUS power usage */
- .vbus_draw = mv_u3d_vbus_draw,
-
- .pullup = mv_u3d_pullup,
- .udc_start = mv_u3d_start,
- .udc_stop = mv_u3d_stop,
-};
-
-static int mv_u3d_eps_init(struct mv_u3d *u3d)
-{
- struct mv_u3d_ep *ep;
- char name[14];
- int i;
-
- /* initialize ep0, ep0 in/out use eps[1] */
- ep = &u3d->eps[1];
- ep->u3d = u3d;
- strscpy(ep->name, "ep0");
- ep->ep.name = ep->name;
- ep->ep.ops = &mv_u3d_ep_ops;
- ep->wedge = 0;
- usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE);
- ep->ep.caps.type_control = true;
- ep->ep.caps.dir_in = true;
- ep->ep.caps.dir_out = true;
- ep->ep_num = 0;
- ep->ep.desc = &mv_u3d_ep0_desc;
- INIT_LIST_HEAD(&ep->queue);
- INIT_LIST_HEAD(&ep->req_list);
- ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
- /* add ep0 ep_context */
- ep->ep_context = &u3d->ep_context[1];
-
- /* initialize other endpoints */
- for (i = 2; i < u3d->max_eps * 2; i++) {
- ep = &u3d->eps[i];
- if (i & 1) {
- snprintf(name, sizeof(name), "ep%din", i >> 1);
- ep->direction = MV_U3D_EP_DIR_IN;
- ep->ep.caps.dir_in = true;
- } else {
- snprintf(name, sizeof(name), "ep%dout", i >> 1);
- ep->direction = MV_U3D_EP_DIR_OUT;
- ep->ep.caps.dir_out = true;
- }
- ep->u3d = u3d;
- strscpy(ep->name, name);
- ep->ep.name = ep->name;
-
- ep->ep.caps.type_iso = true;
- ep->ep.caps.type_bulk = true;
- ep->ep.caps.type_int = true;
-
- ep->ep.ops = &mv_u3d_ep_ops;
- usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
- ep->ep_num = i / 2;
-
- INIT_LIST_HEAD(&ep->queue);
- list_add_tail(&ep->ep.ep_list, &u3d->gadget.ep_list);
-
- INIT_LIST_HEAD(&ep->req_list);
- spin_lock_init(&ep->req_lock);
- ep->ep_context = &u3d->ep_context[i];
- }
-
- return 0;
-}
-
-/* delete all endpoint requests, called with spinlock held */
-static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status)
-{
- /* endpoint fifo flush */
- mv_u3d_ep_fifo_flush(&ep->ep);
-
- while (!list_empty(&ep->queue)) {
- struct mv_u3d_req *req = NULL;
- req = list_entry(ep->queue.next, struct mv_u3d_req, queue);
- mv_u3d_done(ep, req, status);
- }
-}
-
-/* stop all USB activities */
-static
-void mv_u3d_stop_activity(struct mv_u3d *u3d, struct usb_gadget_driver *driver)
-{
- struct mv_u3d_ep *ep;
-
- mv_u3d_nuke(&u3d->eps[1], -ESHUTDOWN);
-
- list_for_each_entry(ep, &u3d->gadget.ep_list, ep.ep_list) {
- mv_u3d_nuke(ep, -ESHUTDOWN);
- }
-
- /* report disconnect; the driver is already quiesced */
- if (driver) {
- spin_unlock(&u3d->lock);
- driver->disconnect(&u3d->gadget);
- spin_lock(&u3d->lock);
- }
-}
-
-static void mv_u3d_irq_process_error(struct mv_u3d *u3d)
-{
- /* Increment the error count */
- u3d->errors++;
- dev_err(u3d->dev, "%s\n", __func__);
-}
-
-static void mv_u3d_irq_process_link_change(struct mv_u3d *u3d)
-{
- u32 linkchange;
-
- linkchange = ioread32(&u3d->vuc_regs->linkchange);
- iowrite32(linkchange, &u3d->vuc_regs->linkchange);
-
- dev_dbg(u3d->dev, "linkchange: 0x%x\n", linkchange);
-
- if (linkchange & MV_U3D_LINK_CHANGE_LINK_UP) {
- dev_dbg(u3d->dev, "link up: ltssm state: 0x%x\n",
- ioread32(&u3d->vuc_regs->ltssmstate));
-
- u3d->usb_state = USB_STATE_DEFAULT;
- u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
- u3d->ep0_state = MV_U3D_WAIT_FOR_SETUP;
-
- /* set speed */
- u3d->gadget.speed = USB_SPEED_SUPER;
- }
-
- if (linkchange & MV_U3D_LINK_CHANGE_SUSPEND) {
- dev_dbg(u3d->dev, "link suspend\n");
- u3d->resume_state = u3d->usb_state;
- u3d->usb_state = USB_STATE_SUSPENDED;
- }
-
- if (linkchange & MV_U3D_LINK_CHANGE_RESUME) {
- dev_dbg(u3d->dev, "link resume\n");
- u3d->usb_state = u3d->resume_state;
- u3d->resume_state = 0;
- }
-
- if (linkchange & MV_U3D_LINK_CHANGE_WRESET) {
- dev_dbg(u3d->dev, "warm reset\n");
- u3d->usb_state = USB_STATE_POWERED;
- }
-
- if (linkchange & MV_U3D_LINK_CHANGE_HRESET) {
- dev_dbg(u3d->dev, "hot reset\n");
- u3d->usb_state = USB_STATE_DEFAULT;
- }
-
- if (linkchange & MV_U3D_LINK_CHANGE_INACT)
- dev_dbg(u3d->dev, "inactive\n");
-
- if (linkchange & MV_U3D_LINK_CHANGE_DISABLE_AFTER_U0)
- dev_dbg(u3d->dev, "ss.disabled\n");
-
- if (linkchange & MV_U3D_LINK_CHANGE_VBUS_INVALID) {
- dev_dbg(u3d->dev, "vbus invalid\n");
- u3d->usb_state = USB_STATE_ATTACHED;
- u3d->vbus_valid_detect = 1;
- /* if external vbus detect is not supported,
- * we handle it here.
- */
- if (!u3d->vbus) {
- spin_unlock(&u3d->lock);
- mv_u3d_vbus_session(&u3d->gadget, 0);
- spin_lock(&u3d->lock);
- }
- }
-}
-
-static void mv_u3d_ch9setaddress(struct mv_u3d *u3d,
- struct usb_ctrlrequest *setup)
-{
- u32 tmp;
-
- if (u3d->usb_state != USB_STATE_DEFAULT) {
- dev_err(u3d->dev,
- "%s, cannot setaddr in this state (%d)\n",
- __func__, u3d->usb_state);
- goto err;
- }
-
- u3d->dev_addr = (u8)setup->wValue;
-
- dev_dbg(u3d->dev, "%s: 0x%x\n", __func__, u3d->dev_addr);
-
- if (u3d->dev_addr > 127) {
- dev_err(u3d->dev,
- "%s, u3d address is wrong (out of range)\n", __func__);
- u3d->dev_addr = 0;
- goto err;
- }
-
- /* update usb state */
- u3d->usb_state = USB_STATE_ADDRESS;
-
- /* set the new address */
- tmp = ioread32(&u3d->vuc_regs->devaddrtiebrkr);
- tmp &= ~0x7F;
- tmp |= (u32)u3d->dev_addr;
- iowrite32(tmp, &u3d->vuc_regs->devaddrtiebrkr);
-
- return;
-err:
- mv_u3d_ep0_stall(u3d);
-}
-
-static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
-{
- if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
- if (setup->bRequest == USB_REQ_SET_CONFIGURATION)
- return 1;
-
- return 0;
-}
-
-static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
- struct usb_ctrlrequest *setup)
- __releases(&u3c->lock)
- __acquires(&u3c->lock)
-{
- bool delegate = false;
-
- mv_u3d_nuke(&u3d->eps[ep_num * 2 + MV_U3D_EP_DIR_IN], -ESHUTDOWN);
-
- dev_dbg(u3d->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
- setup->bRequestType, setup->bRequest,
- setup->wValue, setup->wIndex, setup->wLength);
-
- /* We process some stardard setup requests here */
- if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- switch (setup->bRequest) {
- case USB_REQ_GET_STATUS:
- delegate = true;
- break;
-
- case USB_REQ_SET_ADDRESS:
- mv_u3d_ch9setaddress(u3d, setup);
- break;
-
- case USB_REQ_CLEAR_FEATURE:
- delegate = true;
- break;
-
- case USB_REQ_SET_FEATURE:
- delegate = true;
- break;
-
- default:
- delegate = true;
- }
- } else
- delegate = true;
-
- /* delegate USB standard requests to the gadget driver */
- if (delegate) {
- /* USB requests handled by gadget */
- if (setup->wLength) {
- /* DATA phase from gadget, STATUS phase from u3d */
- u3d->ep0_dir = (setup->bRequestType & USB_DIR_IN)
- ? MV_U3D_EP_DIR_IN : MV_U3D_EP_DIR_OUT;
- spin_unlock(&u3d->lock);
- if (u3d->driver->setup(&u3d->gadget,
- &u3d->local_setup_buff) < 0) {
- dev_err(u3d->dev, "setup error!\n");
- mv_u3d_ep0_stall(u3d);
- }
- spin_lock(&u3d->lock);
- } else {
- /* no DATA phase, STATUS phase from gadget */
- u3d->ep0_dir = MV_U3D_EP_DIR_IN;
- u3d->ep0_state = MV_U3D_STATUS_STAGE;
- spin_unlock(&u3d->lock);
- if (u3d->driver->setup(&u3d->gadget,
- &u3d->local_setup_buff) < 0)
- mv_u3d_ep0_stall(u3d);
- spin_lock(&u3d->lock);
- }
-
- if (mv_u3d_is_set_configuration(setup)) {
- dev_dbg(u3d->dev, "u3d configured\n");
- u3d->usb_state = USB_STATE_CONFIGURED;
- }
- }
-}
-
-static void mv_u3d_get_setup_data(struct mv_u3d *u3d, u8 ep_num, u8 *buffer_ptr)
-{
- struct mv_u3d_ep_context *epcontext;
-
- epcontext = &u3d->ep_context[ep_num * 2 + MV_U3D_EP_DIR_IN];
-
- /* Copy the setup packet to local buffer */
- memcpy(buffer_ptr, (u8 *) &epcontext->setup_buffer, 8);
-}
-
-static void mv_u3d_irq_process_setup(struct mv_u3d *u3d)
-{
- u32 tmp, i;
- /* Process all Setup packet received interrupts */
- tmp = ioread32(&u3d->vuc_regs->setuplock);
- if (tmp) {
- for (i = 0; i < u3d->max_eps; i++) {
- if (tmp & (1 << i)) {
- mv_u3d_get_setup_data(u3d, i,
- (u8 *)(&u3d->local_setup_buff));
- mv_u3d_handle_setup_packet(u3d, i,
- &u3d->local_setup_buff);
- }
- }
- }
-
- iowrite32(tmp, &u3d->vuc_regs->setuplock);
-}
-
-static void mv_u3d_irq_process_tr_complete(struct mv_u3d *u3d)
-{
- u32 tmp, bit_pos;
- int i, ep_num = 0, direction = 0;
- struct mv_u3d_ep *curr_ep;
- struct mv_u3d_req *curr_req, *temp_req;
- int status;
-
- tmp = ioread32(&u3d->vuc_regs->endcomplete);
-
- dev_dbg(u3d->dev, "tr_complete: ep: 0x%x\n", tmp);
- if (!tmp)
- return;
- iowrite32(tmp, &u3d->vuc_regs->endcomplete);
-
- for (i = 0; i < u3d->max_eps * 2; i++) {
- ep_num = i >> 1;
- direction = i % 2;
-
- bit_pos = 1 << (ep_num + 16 * direction);
-
- if (!(bit_pos & tmp))
- continue;
-
- if (i == 0)
- curr_ep = &u3d->eps[1];
- else
- curr_ep = &u3d->eps[i];
-
- /* remove req out of ep request list after completion */
- dev_dbg(u3d->dev, "tr comp: check req_list\n");
- spin_lock(&curr_ep->req_lock);
- if (!list_empty(&curr_ep->req_list)) {
- struct mv_u3d_req *req;
- req = list_entry(curr_ep->req_list.next,
- struct mv_u3d_req, list);
- list_del_init(&req->list);
- curr_ep->processing = 0;
- }
- spin_unlock(&curr_ep->req_lock);
-
- /* process the req queue until an uncomplete request */
- list_for_each_entry_safe(curr_req, temp_req,
- &curr_ep->queue, queue) {
- status = mv_u3d_process_ep_req(u3d, i, curr_req);
- if (status)
- break;
- /* write back status to req */
- curr_req->req.status = status;
-
- /* ep0 request completion */
- if (ep_num == 0) {
- mv_u3d_done(curr_ep, curr_req, 0);
- break;
- } else {
- mv_u3d_done(curr_ep, curr_req, status);
- }
- }
-
- dev_dbg(u3d->dev, "call mv_u3d_start_queue from ep complete\n");
- mv_u3d_start_queue(curr_ep);
- }
-}
-
-static irqreturn_t mv_u3d_irq(int irq, void *dev)
-{
- struct mv_u3d *u3d = (struct mv_u3d *)dev;
- u32 status, intr;
- u32 bridgesetting;
- u32 trbunderrun;
-
- spin_lock(&u3d->lock);
-
- status = ioread32(&u3d->vuc_regs->intrcause);
- intr = ioread32(&u3d->vuc_regs->intrenable);
- status &= intr;
-
- if (status == 0) {
- spin_unlock(&u3d->lock);
- dev_err(u3d->dev, "irq error!\n");
- return IRQ_NONE;
- }
-
- if (status & MV_U3D_USBINT_VBUS_VALID) {
- bridgesetting = ioread32(&u3d->vuc_regs->bridgesetting);
- if (bridgesetting & MV_U3D_BRIDGE_SETTING_VBUS_VALID) {
- /* write vbus valid bit of bridge setting to clear */
- bridgesetting = MV_U3D_BRIDGE_SETTING_VBUS_VALID;
- iowrite32(bridgesetting, &u3d->vuc_regs->bridgesetting);
- dev_dbg(u3d->dev, "vbus valid\n");
-
- u3d->usb_state = USB_STATE_POWERED;
- u3d->vbus_valid_detect = 0;
- /* if external vbus detect is not supported,
- * we handle it here.
- */
- if (!u3d->vbus) {
- spin_unlock(&u3d->lock);
- mv_u3d_vbus_session(&u3d->gadget, 1);
- spin_lock(&u3d->lock);
- }
- } else
- dev_err(u3d->dev, "vbus bit is not set\n");
- }
-
- /* RX data is already in the 16KB FIFO.*/
- if (status & MV_U3D_USBINT_UNDER_RUN) {
- trbunderrun = ioread32(&u3d->vuc_regs->trbunderrun);
- dev_err(u3d->dev, "under run, ep%d\n", trbunderrun);
- iowrite32(trbunderrun, &u3d->vuc_regs->trbunderrun);
- mv_u3d_irq_process_error(u3d);
- }
-
- if (status & (MV_U3D_USBINT_RXDESC_ERR | MV_U3D_USBINT_TXDESC_ERR)) {
- /* write one to clear */
- iowrite32(status & (MV_U3D_USBINT_RXDESC_ERR
- | MV_U3D_USBINT_TXDESC_ERR),
- &u3d->vuc_regs->intrcause);
- dev_err(u3d->dev, "desc err 0x%x\n", status);
- mv_u3d_irq_process_error(u3d);
- }
-
- if (status & MV_U3D_USBINT_LINK_CHG)
- mv_u3d_irq_process_link_change(u3d);
-
- if (status & MV_U3D_USBINT_TX_COMPLETE)
- mv_u3d_irq_process_tr_complete(u3d);
-
- if (status & MV_U3D_USBINT_RX_COMPLETE)
- mv_u3d_irq_process_tr_complete(u3d);
-
- if (status & MV_U3D_USBINT_SETUP)
- mv_u3d_irq_process_setup(u3d);
-
- spin_unlock(&u3d->lock);
- return IRQ_HANDLED;
-}
-
-static void mv_u3d_remove(struct platform_device *dev)
-{
- struct mv_u3d *u3d = platform_get_drvdata(dev);
-
- BUG_ON(u3d == NULL);
-
- usb_del_gadget_udc(&u3d->gadget);
-
- /* free memory allocated in probe */
- dma_pool_destroy(u3d->trb_pool);
-
- if (u3d->ep_context)
- dma_free_coherent(&dev->dev, u3d->ep_context_size,
- u3d->ep_context, u3d->ep_context_dma);
-
- kfree(u3d->eps);
-
- if (u3d->irq)
- free_irq(u3d->irq, u3d);
-
- if (u3d->cap_regs)
- iounmap(u3d->cap_regs);
- u3d->cap_regs = NULL;
-
- kfree(u3d->status_req);
-
- clk_put(u3d->clk);
-
- kfree(u3d);
-}
-
-static int mv_u3d_probe(struct platform_device *dev)
-{
- struct mv_u3d *u3d;
- struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev);
- int retval = 0;
- struct resource *r;
- size_t size;
-
- if (!dev_get_platdata(&dev->dev)) {
- dev_err(&dev->dev, "missing platform_data\n");
- retval = -ENODEV;
- goto err_pdata;
- }
-
- u3d = kzalloc(sizeof(*u3d), GFP_KERNEL);
- if (!u3d) {
- retval = -ENOMEM;
- goto err_alloc_private;
- }
-
- spin_lock_init(&u3d->lock);
-
- platform_set_drvdata(dev, u3d);
-
- u3d->dev = &dev->dev;
- u3d->vbus = pdata->vbus;
-
- u3d->clk = clk_get(&dev->dev, NULL);
- if (IS_ERR(u3d->clk)) {
- retval = PTR_ERR(u3d->clk);
- goto err_get_clk;
- }
-
- r = platform_get_resource_byname(dev, IORESOURCE_MEM, "capregs");
- if (!r) {
- dev_err(&dev->dev, "no I/O memory resource defined\n");
- retval = -ENODEV;
- goto err_get_cap_regs;
- }
-
- u3d->cap_regs = (struct mv_u3d_cap_regs __iomem *)
- ioremap(r->start, resource_size(r));
- if (!u3d->cap_regs) {
- dev_err(&dev->dev, "failed to map I/O memory\n");
- retval = -EBUSY;
- goto err_map_cap_regs;
- } else {
- dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
- (unsigned long) r->start,
- (unsigned long) u3d->cap_regs);
- }
-
- /* we will access controller register, so enable the u3d controller */
- retval = clk_enable(u3d->clk);
- if (retval) {
- dev_err(&dev->dev, "clk_enable error %d\n", retval);
- goto err_u3d_enable;
- }
-
- if (pdata->phy_init) {
- retval = pdata->phy_init(u3d->phy_regs);
- if (retval) {
- dev_err(&dev->dev, "init phy error %d\n", retval);
- clk_disable(u3d->clk);
- goto err_phy_init;
- }
- }
-
- u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
- + MV_U3D_USB3_OP_REGS_OFFSET);
-
- u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
- + ioread32(&u3d->cap_regs->vuoff));
-
- u3d->max_eps = 16;
-
- /*
- * some platform will use usb to download image, it may not disconnect
- * usb gadget before loading kernel. So first stop u3d here.
- */
- mv_u3d_controller_stop(u3d);
- iowrite32(0xFFFFFFFF, &u3d->vuc_regs->intrcause);
-
- if (pdata->phy_deinit)
- pdata->phy_deinit(u3d->phy_regs);
- clk_disable(u3d->clk);
-
- size = u3d->max_eps * sizeof(struct mv_u3d_ep_context) * 2;
- size = (size + MV_U3D_EP_CONTEXT_ALIGNMENT - 1)
- & ~(MV_U3D_EP_CONTEXT_ALIGNMENT - 1);
- u3d->ep_context = dma_alloc_coherent(&dev->dev, size,
- &u3d->ep_context_dma, GFP_KERNEL);
- if (!u3d->ep_context) {
- dev_err(&dev->dev, "allocate ep context memory failed\n");
- retval = -ENOMEM;
- goto err_alloc_ep_context;
- }
- u3d->ep_context_size = size;
-
- /* create TRB dma_pool resource */
- u3d->trb_pool = dma_pool_create("u3d_trb",
- &dev->dev,
- sizeof(struct mv_u3d_trb_hw),
- MV_U3D_TRB_ALIGNMENT,
- MV_U3D_DMA_BOUNDARY);
-
- if (!u3d->trb_pool) {
- retval = -ENOMEM;
- goto err_alloc_trb_pool;
- }
-
- size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2;
- u3d->eps = kzalloc(size, GFP_KERNEL);
- if (!u3d->eps) {
- retval = -ENOMEM;
- goto err_alloc_eps;
- }
-
- /* initialize ep0 status request structure */
- u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL);
- if (!u3d->status_req) {
- retval = -ENOMEM;
- goto err_alloc_status_req;
- }
- INIT_LIST_HEAD(&u3d->status_req->queue);
-
- /* allocate a small amount of memory to get valid address */
- u3d->status_req->req.buf = (char *)u3d->status_req
- + sizeof(struct mv_u3d_req);
- u3d->status_req->req.dma = virt_to_phys(u3d->status_req->req.buf);
-
- u3d->resume_state = USB_STATE_NOTATTACHED;
- u3d->usb_state = USB_STATE_ATTACHED;
- u3d->ep0_dir = MV_U3D_EP_DIR_OUT;
- u3d->remote_wakeup = 0;
-
- r = platform_get_resource(dev, IORESOURCE_IRQ, 0);
- if (!r) {
- dev_err(&dev->dev, "no IRQ resource defined\n");
- retval = -ENODEV;
- goto err_get_irq;
- }
- u3d->irq = r->start;
-
- /* initialize gadget structure */
- u3d->gadget.ops = &mv_u3d_ops; /* usb_gadget_ops */
- u3d->gadget.ep0 = &u3d->eps[1].ep; /* gadget ep0 */
- INIT_LIST_HEAD(&u3d->gadget.ep_list); /* ep_list */
- u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
-
- /* the "gadget" abstracts/virtualizes the controller */
- u3d->gadget.name = driver_name; /* gadget name */
-
- mv_u3d_eps_init(u3d);
-
- if (request_irq(u3d->irq, mv_u3d_irq,
- IRQF_SHARED, driver_name, u3d)) {
- u3d->irq = 0;
- dev_err(&dev->dev, "Request irq %d for u3d failed\n",
- u3d->irq);
- retval = -ENODEV;
- goto err_request_irq;
- }
-
- /* external vbus detection */
- if (u3d->vbus) {
- u3d->clock_gating = 1;
- dev_err(&dev->dev, "external vbus detection\n");
- }
-
- if (!u3d->clock_gating)
- u3d->vbus_active = 1;
-
- /* enable usb3 controller vbus detection */
- u3d->vbus_valid_detect = 1;
-
- retval = usb_add_gadget_udc(&dev->dev, &u3d->gadget);
- if (retval)
- goto err_unregister;
-
- dev_dbg(&dev->dev, "successful probe usb3 device %s clock gating.\n",
- u3d->clock_gating ? "with" : "without");
-
- return 0;
-
-err_unregister:
- free_irq(u3d->irq, u3d);
-err_get_irq:
-err_request_irq:
- kfree(u3d->status_req);
-err_alloc_status_req:
- kfree(u3d->eps);
-err_alloc_eps:
- dma_pool_destroy(u3d->trb_pool);
-err_alloc_trb_pool:
- dma_free_coherent(&dev->dev, u3d->ep_context_size,
- u3d->ep_context, u3d->ep_context_dma);
-err_alloc_ep_context:
-err_phy_init:
-err_u3d_enable:
- iounmap(u3d->cap_regs);
-err_map_cap_regs:
-err_get_cap_regs:
- clk_put(u3d->clk);
-err_get_clk:
- kfree(u3d);
-err_alloc_private:
-err_pdata:
- return retval;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int mv_u3d_suspend(struct device *dev)
-{
- struct mv_u3d *u3d = dev_get_drvdata(dev);
-
- /*
- * only cable is unplugged, usb can suspend.
- * So do not care about clock_gating == 1, it is handled by
- * vbus session.
- */
- if (!u3d->clock_gating) {
- mv_u3d_controller_stop(u3d);
-
- spin_lock_irq(&u3d->lock);
- /* stop all usb activities */
- mv_u3d_stop_activity(u3d, u3d->driver);
- spin_unlock_irq(&u3d->lock);
-
- mv_u3d_disable(u3d);
- }
-
- return 0;
-}
-
-static int mv_u3d_resume(struct device *dev)
-{
- struct mv_u3d *u3d = dev_get_drvdata(dev);
- int retval;
-
- if (!u3d->clock_gating) {
- retval = mv_u3d_enable(u3d);
- if (retval)
- return retval;
-
- if (u3d->driver && u3d->softconnect) {
- mv_u3d_controller_reset(u3d);
- mv_u3d_ep0_reset(u3d);
- mv_u3d_controller_start(u3d);
- }
- }
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
-
-static void mv_u3d_shutdown(struct platform_device *dev)
-{
- struct mv_u3d *u3d = platform_get_drvdata(dev);
- u32 tmp;
-
- tmp = ioread32(&u3d->op_regs->usbcmd);
- tmp &= ~MV_U3D_CMD_RUN_STOP;
- iowrite32(tmp, &u3d->op_regs->usbcmd);
-}
-
-static struct platform_driver mv_u3d_driver = {
- .probe = mv_u3d_probe,
- .remove = mv_u3d_remove,
- .shutdown = mv_u3d_shutdown,
- .driver = {
- .name = "mv-u3d",
- .pm = &mv_u3d_pm_ops,
- },
-};
-
-module_platform_driver(mv_u3d_driver);
-MODULE_ALIAS("platform:mv-u3d");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/mv_udc.h b/drivers/usb/gadget/udc/mv_udc.h
deleted file mode 100644
index b3f759c0962c..000000000000
--- a/drivers/usb/gadget/udc/mv_udc.h
+++ /dev/null
@@ -1,309 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- */
-
-#ifndef __MV_UDC_H
-#define __MV_UDC_H
-
-#define VUSBHS_MAX_PORTS 8
-
-#define DQH_ALIGNMENT 2048
-#define DTD_ALIGNMENT 64
-#define DMA_BOUNDARY 4096
-
-#define EP_DIR_IN 1
-#define EP_DIR_OUT 0
-
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-#define EP0_MAX_PKT_SIZE 64
-/* ep0 transfer state */
-#define WAIT_FOR_SETUP 0
-#define DATA_STATE_XMIT 1
-#define DATA_STATE_NEED_ZLP 2
-#define WAIT_FOR_OUT_STATUS 3
-#define DATA_STATE_RECV 4
-
-#define CAPLENGTH_MASK (0xff)
-#define DCCPARAMS_DEN_MASK (0x1f)
-
-#define HCSPARAMS_PPC (0x10)
-
-/* Frame Index Register Bit Masks */
-#define USB_FRINDEX_MASKS 0x3fff
-
-/* Command Register Bit Masks */
-#define USBCMD_RUN_STOP (0x00000001)
-#define USBCMD_CTRL_RESET (0x00000002)
-#define USBCMD_SETUP_TRIPWIRE_SET (0x00002000)
-#define USBCMD_SETUP_TRIPWIRE_CLEAR (~USBCMD_SETUP_TRIPWIRE_SET)
-
-#define USBCMD_ATDTW_TRIPWIRE_SET (0x00004000)
-#define USBCMD_ATDTW_TRIPWIRE_CLEAR (~USBCMD_ATDTW_TRIPWIRE_SET)
-
-/* bit 15,3,2 are for frame list size */
-#define USBCMD_FRAME_SIZE_1024 (0x00000000) /* 000 */
-#define USBCMD_FRAME_SIZE_512 (0x00000004) /* 001 */
-#define USBCMD_FRAME_SIZE_256 (0x00000008) /* 010 */
-#define USBCMD_FRAME_SIZE_128 (0x0000000C) /* 011 */
-#define USBCMD_FRAME_SIZE_64 (0x00008000) /* 100 */
-#define USBCMD_FRAME_SIZE_32 (0x00008004) /* 101 */
-#define USBCMD_FRAME_SIZE_16 (0x00008008) /* 110 */
-#define USBCMD_FRAME_SIZE_8 (0x0000800C) /* 111 */
-
-#define EPCTRL_TX_ALL_MASK (0xFFFF0000)
-#define EPCTRL_RX_ALL_MASK (0x0000FFFF)
-
-#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000)
-#define EPCTRL_TX_EP_STALL (0x00010000)
-#define EPCTRL_RX_EP_STALL (0x00000001)
-#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040)
-#define EPCTRL_RX_ENABLE (0x00000080)
-#define EPCTRL_TX_ENABLE (0x00800000)
-#define EPCTRL_CONTROL (0x00000000)
-#define EPCTRL_ISOCHRONOUS (0x00040000)
-#define EPCTRL_BULK (0x00080000)
-#define EPCTRL_INT (0x000C0000)
-#define EPCTRL_TX_TYPE (0x000C0000)
-#define EPCTRL_RX_TYPE (0x0000000C)
-#define EPCTRL_DATA_TOGGLE_INHIBIT (0x00000020)
-#define EPCTRL_TX_EP_TYPE_SHIFT (18)
-#define EPCTRL_RX_EP_TYPE_SHIFT (2)
-
-#define EPCOMPLETE_MAX_ENDPOINTS (16)
-
-/* endpoint list address bit masks */
-#define USB_EP_LIST_ADDRESS_MASK 0xfffff800
-
-#define PORTSCX_W1C_BITS 0x2a
-#define PORTSCX_PORT_RESET 0x00000100
-#define PORTSCX_PORT_POWER 0x00001000
-#define PORTSCX_FORCE_FULL_SPEED_CONNECT 0x01000000
-#define PORTSCX_PAR_XCVR_SELECT 0xC0000000
-#define PORTSCX_PORT_FORCE_RESUME 0x00000040
-#define PORTSCX_PORT_SUSPEND 0x00000080
-#define PORTSCX_PORT_SPEED_FULL 0x00000000
-#define PORTSCX_PORT_SPEED_LOW 0x04000000
-#define PORTSCX_PORT_SPEED_HIGH 0x08000000
-#define PORTSCX_PORT_SPEED_MASK 0x0C000000
-
-/* USB MODE Register Bit Masks */
-#define USBMODE_CTRL_MODE_IDLE 0x00000000
-#define USBMODE_CTRL_MODE_DEVICE 0x00000002
-#define USBMODE_CTRL_MODE_HOST 0x00000003
-#define USBMODE_CTRL_MODE_RSV 0x00000001
-#define USBMODE_SETUP_LOCK_OFF 0x00000008
-#define USBMODE_STREAM_DISABLE 0x00000010
-
-/* USB STS Register Bit Masks */
-#define USBSTS_INT 0x00000001
-#define USBSTS_ERR 0x00000002
-#define USBSTS_PORT_CHANGE 0x00000004
-#define USBSTS_FRM_LST_ROLL 0x00000008
-#define USBSTS_SYS_ERR 0x00000010
-#define USBSTS_IAA 0x00000020
-#define USBSTS_RESET 0x00000040
-#define USBSTS_SOF 0x00000080
-#define USBSTS_SUSPEND 0x00000100
-#define USBSTS_HC_HALTED 0x00001000
-#define USBSTS_RCL 0x00002000
-#define USBSTS_PERIODIC_SCHEDULE 0x00004000
-#define USBSTS_ASYNC_SCHEDULE 0x00008000
-
-
-/* Interrupt Enable Register Bit Masks */
-#define USBINTR_INT_EN (0x00000001)
-#define USBINTR_ERR_INT_EN (0x00000002)
-#define USBINTR_PORT_CHANGE_DETECT_EN (0x00000004)
-
-#define USBINTR_ASYNC_ADV_AAE (0x00000020)
-#define USBINTR_ASYNC_ADV_AAE_ENABLE (0x00000020)
-#define USBINTR_ASYNC_ADV_AAE_DISABLE (0xFFFFFFDF)
-
-#define USBINTR_RESET_EN (0x00000040)
-#define USBINTR_SOF_UFRAME_EN (0x00000080)
-#define USBINTR_DEVICE_SUSPEND (0x00000100)
-
-#define USB_DEVICE_ADDRESS_MASK (0xfe000000)
-#define USB_DEVICE_ADDRESS_BIT_SHIFT (25)
-
-struct mv_cap_regs {
- u32 caplength_hciversion;
- u32 hcsparams; /* HC structural parameters */
- u32 hccparams; /* HC Capability Parameters*/
- u32 reserved[5];
- u32 dciversion; /* DC version number and reserved 16 bits */
- u32 dccparams; /* DC Capability Parameters */
-};
-
-struct mv_op_regs {
- u32 usbcmd; /* Command register */
- u32 usbsts; /* Status register */
- u32 usbintr; /* Interrupt enable */
- u32 frindex; /* Frame index */
- u32 reserved1[1];
- u32 deviceaddr; /* Device Address */
- u32 eplistaddr; /* Endpoint List Address */
- u32 ttctrl; /* HOST TT status and control */
- u32 burstsize; /* Programmable Burst Size */
- u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */
- u32 reserved[4];
- u32 epnak; /* Endpoint NAK */
- u32 epnaken; /* Endpoint NAK Enable */
- u32 configflag; /* Configured Flag register */
- u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */
- u32 otgsc;
- u32 usbmode; /* USB Host/Device mode */
- u32 epsetupstat; /* Endpoint Setup Status */
- u32 epprime; /* Endpoint Initialize */
- u32 epflush; /* Endpoint De-initialize */
- u32 epstatus; /* Endpoint Status */
- u32 epcomplete; /* Endpoint Interrupt On Complete */
- u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */
- u32 mcr; /* Mux Control */
- u32 isr; /* Interrupt Status */
- u32 ier; /* Interrupt Enable */
-};
-
-struct mv_udc {
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
- spinlock_t lock;
- struct completion *done;
- struct platform_device *dev;
- int irq;
-
- struct mv_cap_regs __iomem *cap_regs;
- struct mv_op_regs __iomem *op_regs;
- void __iomem *phy_regs;
- unsigned int max_eps;
- struct mv_dqh *ep_dqh;
- size_t ep_dqh_size;
- dma_addr_t ep_dqh_dma;
-
- struct dma_pool *dtd_pool;
- struct mv_ep *eps;
-
- struct mv_dtd *dtd_head;
- struct mv_dtd *dtd_tail;
- unsigned int dtd_entries;
-
- struct mv_req *status_req;
- struct usb_ctrlrequest local_setup_buff;
-
- unsigned int resume_state; /* USB state to resume */
- unsigned int usb_state; /* USB current state */
- unsigned int ep0_state; /* Endpoint zero state */
- unsigned int ep0_dir;
-
- unsigned int dev_addr;
- unsigned int test_mode;
-
- int errors;
- unsigned softconnect:1,
- vbus_active:1,
- remote_wakeup:1,
- softconnected:1,
- force_fs:1,
- clock_gating:1,
- active:1,
- stopped:1; /* stop bit is setted */
-
- struct work_struct vbus_work;
- struct workqueue_struct *qwork;
-
- struct usb_phy *transceiver;
-
- struct mv_usb_platform_data *pdata;
-
- /* some SOC has mutiple clock sources for USB*/
- struct clk *clk;
-};
-
-/* endpoint data structure */
-struct mv_ep {
- struct usb_ep ep;
- struct mv_udc *udc;
- struct list_head queue;
- struct mv_dqh *dqh;
- u32 direction;
- char name[14];
- unsigned stopped:1,
- wedge:1,
- ep_type:2,
- ep_num:8;
-};
-
-/* request data structure */
-struct mv_req {
- struct usb_request req;
- struct mv_dtd *dtd, *head, *tail;
- struct mv_ep *ep;
- struct list_head queue;
- unsigned int test_mode;
- unsigned dtd_count;
- unsigned mapped:1;
-};
-
-#define EP_QUEUE_HEAD_MULT_POS 30
-#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000
-#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16
-#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
-#define EP_QUEUE_HEAD_IOS 0x00008000
-#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001
-#define EP_QUEUE_HEAD_IOC 0x00008000
-#define EP_QUEUE_HEAD_MULTO 0x00000C00
-#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040
-#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080
-#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF
-#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0
-#define EP_QUEUE_FRINDEX_MASK 0x000007FF
-#define EP_MAX_LENGTH_TRANSFER 0x4000
-
-struct mv_dqh {
- /* Bits 16..26 Bit 15 is Interrupt On Setup */
- u32 max_packet_length;
- u32 curr_dtd_ptr; /* Current dTD Pointer */
- u32 next_dtd_ptr; /* Next dTD Pointer */
- /* Total bytes (16..30), IOC (15), INT (8), STS (0-7) */
- u32 size_ioc_int_sts;
- u32 buff_ptr0; /* Buffer pointer Page 0 (12-31) */
- u32 buff_ptr1; /* Buffer pointer Page 1 (12-31) */
- u32 buff_ptr2; /* Buffer pointer Page 2 (12-31) */
- u32 buff_ptr3; /* Buffer pointer Page 3 (12-31) */
- u32 buff_ptr4; /* Buffer pointer Page 4 (12-31) */
- u32 reserved1;
- /* 8 bytes of setup data that follows the Setup PID */
- u8 setup_buffer[8];
- u32 reserved2[4];
-};
-
-
-#define DTD_NEXT_TERMINATE (0x00000001)
-#define DTD_IOC (0x00008000)
-#define DTD_STATUS_ACTIVE (0x00000080)
-#define DTD_STATUS_HALTED (0x00000040)
-#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
-#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
-#define DTD_RESERVED_FIELDS (0x00007F00)
-#define DTD_ERROR_MASK (0x68)
-#define DTD_ADDR_MASK (0xFFFFFFE0)
-#define DTD_PACKET_SIZE 0x7FFF0000
-#define DTD_LENGTH_BIT_POS (16)
-
-struct mv_dtd {
- u32 dtd_next;
- u32 size_ioc_sts;
- u32 buff_ptr0; /* Buffer pointer Page 0 */
- u32 buff_ptr1; /* Buffer pointer Page 1 */
- u32 buff_ptr2; /* Buffer pointer Page 2 */
- u32 buff_ptr3; /* Buffer pointer Page 3 */
- u32 buff_ptr4; /* Buffer pointer Page 4 */
- u32 scratch_ptr;
- /* 32 bytes */
- dma_addr_t td_dma; /* dma address for this td */
- struct mv_dtd *next_dtd_virt;
-};
-
-#endif
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
deleted file mode 100644
index ff103e6b3048..000000000000
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ /dev/null
@@ -1,2426 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- * Author: Chao Xie <chao.xie@marvell.com>
- * Neil Zhang <zhangwm@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/pm.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/platform_data/mv_usb.h>
-#include <linux/unaligned.h>
-
-#include "mv_udc.h"
-
-#define DRIVER_DESC "Marvell PXA USB Device Controller driver"
-
-#define ep_dir(ep) (((ep)->ep_num == 0) ? \
- ((ep)->udc->ep0_dir) : ((ep)->direction))
-
-/* timeout value -- usec */
-#define RESET_TIMEOUT 10000
-#define FLUSH_TIMEOUT 10000
-#define EPSTATUS_TIMEOUT 10000
-#define PRIME_TIMEOUT 10000
-#define READSAFE_TIMEOUT 1000
-
-#define LOOPS_USEC_SHIFT 1
-#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT)
-#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT)
-
-static DECLARE_COMPLETION(release_done);
-
-static const char driver_name[] = "mv_udc";
-
-static void nuke(struct mv_ep *ep, int status);
-static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
-
-/* for endpoint 0 operations */
-static const struct usb_endpoint_descriptor mv_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = EP0_MAX_PKT_SIZE,
-};
-
-static void ep0_reset(struct mv_udc *udc)
-{
- struct mv_ep *ep;
- u32 epctrlx;
- int i = 0;
-
- /* ep0 in and out */
- for (i = 0; i < 2; i++) {
- ep = &udc->eps[i];
- ep->udc = udc;
-
- /* ep0 dQH */
- ep->dqh = &udc->ep_dqh[i];
-
- /* configure ep0 endpoint capabilities in dQH */
- ep->dqh->max_packet_length =
- (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
- | EP_QUEUE_HEAD_IOS;
-
- ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE;
-
- epctrlx = readl(&udc->op_regs->epctrlx[0]);
- if (i) { /* TX */
- epctrlx |= EPCTRL_TX_ENABLE
- | (USB_ENDPOINT_XFER_CONTROL
- << EPCTRL_TX_EP_TYPE_SHIFT);
-
- } else { /* RX */
- epctrlx |= EPCTRL_RX_ENABLE
- | (USB_ENDPOINT_XFER_CONTROL
- << EPCTRL_RX_EP_TYPE_SHIFT);
- }
-
- writel(epctrlx, &udc->op_regs->epctrlx[0]);
- }
-}
-
-/* protocol ep0 stall, will automatically be cleared on new transaction */
-static void ep0_stall(struct mv_udc *udc)
-{
- u32 epctrlx;
-
- /* set TX and RX to stall */
- epctrlx = readl(&udc->op_regs->epctrlx[0]);
- epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL;
- writel(epctrlx, &udc->op_regs->epctrlx[0]);
-
- /* update ep0 state */
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = EP_DIR_OUT;
-}
-
-static int process_ep_req(struct mv_udc *udc, int index,
- struct mv_req *curr_req)
-{
- struct mv_dtd *curr_dtd;
- struct mv_dqh *curr_dqh;
- int actual, remaining_length;
- int i, direction;
- int retval = 0;
- u32 errors;
- u32 bit_pos;
-
- curr_dqh = &udc->ep_dqh[index];
- direction = index % 2;
-
- curr_dtd = curr_req->head;
- actual = curr_req->req.length;
-
- for (i = 0; i < curr_req->dtd_count; i++) {
- if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) {
- dev_dbg(&udc->dev->dev, "%s, dTD not completed\n",
- udc->eps[index].name);
- return 1;
- }
-
- errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK;
- if (!errors) {
- remaining_length =
- (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE)
- >> DTD_LENGTH_BIT_POS;
- actual -= remaining_length;
-
- if (remaining_length) {
- if (direction) {
- dev_dbg(&udc->dev->dev,
- "TX dTD remains data\n");
- retval = -EPROTO;
- break;
- } else
- break;
- }
- } else {
- dev_info(&udc->dev->dev,
- "complete_tr error: ep=%d %s: error = 0x%x\n",
- index >> 1, direction ? "SEND" : "RECV",
- errors);
- if (errors & DTD_STATUS_HALTED) {
- /* Clear the errors and Halt condition */
- curr_dqh->size_ioc_int_sts &= ~errors;
- retval = -EPIPE;
- } else if (errors & DTD_STATUS_DATA_BUFF_ERR) {
- retval = -EPROTO;
- } else if (errors & DTD_STATUS_TRANSACTION_ERR) {
- retval = -EILSEQ;
- }
- }
- if (i != curr_req->dtd_count - 1)
- curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt;
- }
- if (retval)
- return retval;
-
- if (direction == EP_DIR_OUT)
- bit_pos = 1 << curr_req->ep->ep_num;
- else
- bit_pos = 1 << (16 + curr_req->ep->ep_num);
-
- while (curr_dqh->curr_dtd_ptr == curr_dtd->td_dma) {
- if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) {
- while (readl(&udc->op_regs->epstatus) & bit_pos)
- udelay(1);
- break;
- }
- udelay(1);
- }
-
- curr_req->req.actual = actual;
-
- return 0;
-}
-
-/*
- * done() - retire a request; caller blocked irqs
- * @status : request status to be set, only works when
- * request is still in progress.
- */
-static void done(struct mv_ep *ep, struct mv_req *req, int status)
- __releases(&ep->udc->lock)
- __acquires(&ep->udc->lock)
-{
- struct mv_udc *udc = NULL;
- unsigned char stopped = ep->stopped;
- struct mv_dtd *curr_td, *next_td;
- int j;
-
- udc = (struct mv_udc *)ep->udc;
- /* Removed the req from fsl_ep->queue */
- list_del_init(&req->queue);
-
- /* req.status should be set as -EINPROGRESS in ep_queue() */
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- /* Free dtd for the request */
- next_td = req->head;
- for (j = 0; j < req->dtd_count; j++) {
- curr_td = next_td;
- if (j != req->dtd_count - 1)
- next_td = curr_td->next_dtd_virt;
- dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
- }
-
- usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
-
- if (status && (status != -ESHUTDOWN))
- dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
- ep->ep.name, &req->req, status,
- req->req.actual, req->req.length);
-
- ep->stopped = 1;
-
- spin_unlock(&ep->udc->lock);
-
- usb_gadget_giveback_request(&ep->ep, &req->req);
-
- spin_lock(&ep->udc->lock);
- ep->stopped = stopped;
-}
-
-static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
-{
- struct mv_udc *udc;
- struct mv_dqh *dqh;
- u32 bit_pos, direction;
- u32 usbcmd, epstatus;
- unsigned int loops;
- int retval = 0;
-
- udc = ep->udc;
- direction = ep_dir(ep);
- dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]);
- bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
-
- /* check if the pipe is empty */
- if (!(list_empty(&ep->queue))) {
- struct mv_req *lastreq;
- lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
- lastreq->tail->dtd_next =
- req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-
- wmb();
-
- if (readl(&udc->op_regs->epprime) & bit_pos)
- goto done;
-
- loops = LOOPS(READSAFE_TIMEOUT);
- while (1) {
- /* start with setting the semaphores */
- usbcmd = readl(&udc->op_regs->usbcmd);
- usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
- writel(usbcmd, &udc->op_regs->usbcmd);
-
- /* read the endpoint status */
- epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
-
- /*
- * Reread the ATDTW semaphore bit to check if it is
- * cleared. When hardware see a hazard, it will clear
- * the bit or else we remain set to 1 and we can
- * proceed with priming of endpoint if not already
- * primed.
- */
- if (readl(&udc->op_regs->usbcmd)
- & USBCMD_ATDTW_TRIPWIRE_SET)
- break;
-
- loops--;
- if (loops == 0) {
- dev_err(&udc->dev->dev,
- "Timeout for ATDTW_TRIPWIRE...\n");
- retval = -ETIME;
- goto done;
- }
- udelay(LOOPS_USEC);
- }
-
- /* Clear the semaphore */
- usbcmd = readl(&udc->op_regs->usbcmd);
- usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
- writel(usbcmd, &udc->op_regs->usbcmd);
-
- if (epstatus)
- goto done;
- }
-
- /* Write dQH next pointer and terminate bit to 0 */
- dqh->next_dtd_ptr = req->head->td_dma
- & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-
- /* clear active and halt bit, in case set from a previous error */
- dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
-
- /* Ensure that updates to the QH will occur before priming. */
- wmb();
-
- /* Prime the Endpoint */
- writel(bit_pos, &udc->op_regs->epprime);
-
-done:
- return retval;
-}
-
-static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
- dma_addr_t *dma, int *is_last)
-{
- struct mv_dtd *dtd;
- struct mv_udc *udc;
- struct mv_dqh *dqh;
- u32 temp, mult = 0;
-
- /* how big will this transfer be? */
- if (usb_endpoint_xfer_isoc(req->ep->ep.desc)) {
- dqh = req->ep->dqh;
- mult = (dqh->max_packet_length >> EP_QUEUE_HEAD_MULT_POS)
- & 0x3;
- *length = min(req->req.length - req->req.actual,
- (unsigned)(mult * req->ep->ep.maxpacket));
- } else
- *length = min(req->req.length - req->req.actual,
- (unsigned)EP_MAX_LENGTH_TRANSFER);
-
- udc = req->ep->udc;
-
- /*
- * Be careful that no _GFP_HIGHMEM is set,
- * or we can not use dma_to_virt
- */
- dtd = dma_pool_alloc(udc->dtd_pool, GFP_ATOMIC, dma);
- if (dtd == NULL)
- return dtd;
-
- dtd->td_dma = *dma;
- /* initialize buffer page pointers */
- temp = (u32)(req->req.dma + req->req.actual);
- dtd->buff_ptr0 = cpu_to_le32(temp);
- temp &= ~0xFFF;
- dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000);
- dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000);
- dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000);
- dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000);
-
- req->req.actual += *length;
-
- /* zlp is needed if req->req.zero is set */
- if (req->req.zero) {
- if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
- *is_last = 1;
- else
- *is_last = 0;
- } else if (req->req.length == req->req.actual)
- *is_last = 1;
- else
- *is_last = 0;
-
- /* Fill in the transfer size; set active bit */
- temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
-
- /* Enable interrupt for the last dtd of a request */
- if (*is_last && !req->req.no_interrupt)
- temp |= DTD_IOC;
-
- temp |= mult << 10;
-
- dtd->size_ioc_sts = temp;
-
- mb();
-
- return dtd;
-}
-
-/* generate dTD linked list for a request */
-static int req_to_dtd(struct mv_req *req)
-{
- unsigned count;
- int is_last, is_first = 1;
- struct mv_dtd *dtd, *last_dtd = NULL;
- dma_addr_t dma;
-
- do {
- dtd = build_dtd(req, &count, &dma, &is_last);
- if (dtd == NULL)
- return -ENOMEM;
-
- if (is_first) {
- is_first = 0;
- req->head = dtd;
- } else {
- last_dtd->dtd_next = dma;
- last_dtd->next_dtd_virt = dtd;
- }
- last_dtd = dtd;
- req->dtd_count++;
- } while (!is_last);
-
- /* set terminate bit to 1 for the last dTD */
- dtd->dtd_next = DTD_NEXT_TERMINATE;
-
- req->tail = dtd;
-
- return 0;
-}
-
-static int mv_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct mv_udc *udc;
- struct mv_ep *ep;
- struct mv_dqh *dqh;
- u16 max = 0;
- u32 bit_pos, epctrlx, direction;
- const unsigned char zlt = 1;
- unsigned char ios, mult;
- unsigned long flags;
-
- ep = container_of(_ep, struct mv_ep, ep);
- udc = ep->udc;
-
- if (!_ep || !desc
- || desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
-
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- direction = ep_dir(ep);
- max = usb_endpoint_maxp(desc);
-
- /*
- * disable HW zero length termination select
- * driver handles zero length packet through req->req.zero
- */
- bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
-
- /* Check if the Endpoint is Primed */
- if ((readl(&udc->op_regs->epprime) & bit_pos)
- || (readl(&udc->op_regs->epstatus) & bit_pos)) {
- dev_info(&udc->dev->dev,
- "ep=%d %s: Init ERROR: ENDPTPRIME=0x%x,"
- " ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
- (unsigned)ep->ep_num, direction ? "SEND" : "RECV",
- (unsigned)readl(&udc->op_regs->epprime),
- (unsigned)readl(&udc->op_regs->epstatus),
- (unsigned)bit_pos);
- goto en_done;
- }
-
- /* Set the max packet length, interrupt on Setup and Mult fields */
- ios = 0;
- mult = 0;
- switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- break;
- case USB_ENDPOINT_XFER_CONTROL:
- ios = 1;
- break;
- case USB_ENDPOINT_XFER_ISOC:
- /* Calculate transactions needed for high bandwidth iso */
- mult = usb_endpoint_maxp_mult(desc);
- /* 3 transactions at most */
- if (mult > 3)
- goto en_done;
- break;
- default:
- goto en_done;
- }
-
- spin_lock_irqsave(&udc->lock, flags);
- /* Get the endpoint queue head address */
- dqh = ep->dqh;
- dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
- | (mult << EP_QUEUE_HEAD_MULT_POS)
- | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
- | (ios ? EP_QUEUE_HEAD_IOS : 0);
- dqh->next_dtd_ptr = 1;
- dqh->size_ioc_int_sts = 0;
-
- ep->ep.maxpacket = max;
- ep->ep.desc = desc;
- ep->stopped = 0;
-
- /* Enable the endpoint for Rx or Tx and set the endpoint type */
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- if (direction == EP_DIR_IN) {
- epctrlx &= ~EPCTRL_TX_ALL_MASK;
- epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST
- | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- << EPCTRL_TX_EP_TYPE_SHIFT);
- } else {
- epctrlx &= ~EPCTRL_RX_ALL_MASK;
- epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST
- | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- << EPCTRL_RX_EP_TYPE_SHIFT);
- }
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
-
- /*
- * Implement Guideline (GL# USB-7) The unused endpoint type must
- * be programmed to bulk.
- */
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- if ((epctrlx & EPCTRL_RX_ENABLE) == 0) {
- epctrlx |= (USB_ENDPOINT_XFER_BULK
- << EPCTRL_RX_EP_TYPE_SHIFT);
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
- }
-
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- if ((epctrlx & EPCTRL_TX_ENABLE) == 0) {
- epctrlx |= (USB_ENDPOINT_XFER_BULK
- << EPCTRL_TX_EP_TYPE_SHIFT);
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
- }
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-en_done:
- return -EINVAL;
-}
-
-static int mv_ep_disable(struct usb_ep *_ep)
-{
- struct mv_udc *udc;
- struct mv_ep *ep;
- struct mv_dqh *dqh;
- u32 epctrlx, direction;
- unsigned long flags;
-
- ep = container_of(_ep, struct mv_ep, ep);
- if ((_ep == NULL) || !ep->ep.desc)
- return -EINVAL;
-
- udc = ep->udc;
-
- /* Get the endpoint queue head address */
- dqh = ep->dqh;
-
- spin_lock_irqsave(&udc->lock, flags);
-
- direction = ep_dir(ep);
-
- /* Reset the max packet length and the interrupt on Setup */
- dqh->max_packet_length = 0;
-
- /* Disable the endpoint for Rx or Tx and reset the endpoint type */
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- epctrlx &= ~((direction == EP_DIR_IN)
- ? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE)
- : (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE));
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
-
- /* nuke all pending requests (does flush) */
- nuke(ep, -ESHUTDOWN);
-
- ep->ep.desc = NULL;
- ep->stopped = 1;
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-}
-
-static struct usb_request *
-mv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct mv_req *req;
-
- req = kzalloc(sizeof *req, gfp_flags);
- if (!req)
- return NULL;
-
- req->req.dma = DMA_ADDR_INVALID;
- INIT_LIST_HEAD(&req->queue);
-
- return &req->req;
-}
-
-static void mv_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct mv_req *req = NULL;
-
- req = container_of(_req, struct mv_req, req);
-
- if (_req)
- kfree(req);
-}
-
-static void mv_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct mv_udc *udc;
- u32 bit_pos, direction;
- struct mv_ep *ep;
- unsigned int loops;
-
- if (!_ep)
- return;
-
- ep = container_of(_ep, struct mv_ep, ep);
- if (!ep->ep.desc)
- return;
-
- udc = ep->udc;
- direction = ep_dir(ep);
-
- if (ep->ep_num == 0)
- bit_pos = (1 << 16) | 1;
- else if (direction == EP_DIR_OUT)
- bit_pos = 1 << ep->ep_num;
- else
- bit_pos = 1 << (16 + ep->ep_num);
-
- loops = LOOPS(EPSTATUS_TIMEOUT);
- do {
- unsigned int inter_loops;
-
- if (loops == 0) {
- dev_err(&udc->dev->dev,
- "TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
- (unsigned)readl(&udc->op_regs->epstatus),
- (unsigned)bit_pos);
- return;
- }
- /* Write 1 to the Flush register */
- writel(bit_pos, &udc->op_regs->epflush);
-
- /* Wait until flushing completed */
- inter_loops = LOOPS(FLUSH_TIMEOUT);
- while (readl(&udc->op_regs->epflush)) {
- /*
- * ENDPTFLUSH bit should be cleared to indicate this
- * operation is complete
- */
- if (inter_loops == 0) {
- dev_err(&udc->dev->dev,
- "TIMEOUT for ENDPTFLUSH=0x%x,"
- "bit_pos=0x%x\n",
- (unsigned)readl(&udc->op_regs->epflush),
- (unsigned)bit_pos);
- return;
- }
- inter_loops--;
- udelay(LOOPS_USEC);
- }
- loops--;
- } while (readl(&udc->op_regs->epstatus) & bit_pos);
-}
-
-/* queues (submits) an I/O request to an endpoint */
-static int
-mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
- struct mv_req *req = container_of(_req, struct mv_req, req);
- struct mv_udc *udc = ep->udc;
- unsigned long flags;
- int retval;
-
- /* catch various bogus parameters */
- if (!_req || !req->req.complete || !req->req.buf
- || !list_empty(&req->queue)) {
- dev_err(&udc->dev->dev, "%s, bad params", __func__);
- return -EINVAL;
- }
- if (unlikely(!_ep || !ep->ep.desc)) {
- dev_err(&udc->dev->dev, "%s, bad ep", __func__);
- return -EINVAL;
- }
-
- udc = ep->udc;
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- req->ep = ep;
-
- /* map virtual address to hardware */
- retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
- if (retval)
- return retval;
-
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->dtd_count = 0;
-
- spin_lock_irqsave(&udc->lock, flags);
-
- /* build dtds and push them to device queue */
- if (!req_to_dtd(req)) {
- retval = queue_dtd(ep, req);
- if (retval) {
- spin_unlock_irqrestore(&udc->lock, flags);
- dev_err(&udc->dev->dev, "Failed to queue dtd\n");
- goto err_unmap_dma;
- }
- } else {
- spin_unlock_irqrestore(&udc->lock, flags);
- dev_err(&udc->dev->dev, "Failed to dma_pool_alloc\n");
- retval = -ENOMEM;
- goto err_unmap_dma;
- }
-
- /* Update ep0 state */
- if (ep->ep_num == 0)
- udc->ep0_state = DATA_STATE_XMIT;
-
- /* irq handler advances the queue */
- list_add_tail(&req->queue, &ep->queue);
- spin_unlock_irqrestore(&udc->lock, flags);
-
- return 0;
-
-err_unmap_dma:
- usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
-
- return retval;
-}
-
-static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
-{
- struct mv_dqh *dqh = ep->dqh;
- u32 bit_pos;
-
- /* Write dQH next pointer and terminate bit to 0 */
- dqh->next_dtd_ptr = req->head->td_dma
- & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-
- /* clear active and halt bit, in case set from a previous error */
- dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
-
- /* Ensure that updates to the QH will occure before priming. */
- wmb();
-
- bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
-
- /* Prime the Endpoint */
- writel(bit_pos, &ep->udc->op_regs->epprime);
-}
-
-/* dequeues (cancels, unlinks) an I/O request from an endpoint */
-static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
- struct mv_req *req = NULL, *iter;
- struct mv_udc *udc = ep->udc;
- unsigned long flags;
- int stopped, ret = 0;
- u32 epctrlx;
-
- if (!_ep || !_req)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->udc->lock, flags);
- stopped = ep->stopped;
-
- /* Stop the ep before we deal with the queue */
- ep->stopped = 1;
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- if (ep_dir(ep) == EP_DIR_IN)
- epctrlx &= ~EPCTRL_TX_ENABLE;
- else
- epctrlx &= ~EPCTRL_RX_ENABLE;
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
-
- /* make sure it's actually queued on this endpoint */
- list_for_each_entry(iter, &ep->queue, queue) {
- if (&iter->req != _req)
- continue;
- req = iter;
- break;
- }
- if (!req) {
- ret = -EINVAL;
- goto out;
- }
-
- /* The request is in progress, or completed but not dequeued */
- if (ep->queue.next == &req->queue) {
- _req->status = -ECONNRESET;
- mv_ep_fifo_flush(_ep); /* flush current transfer */
-
- /* The request isn't the last request in this ep queue */
- if (req->queue.next != &ep->queue) {
- struct mv_req *next_req;
-
- next_req = list_entry(req->queue.next,
- struct mv_req, queue);
-
- /* Point the QH to the first TD of next request */
- mv_prime_ep(ep, next_req);
- } else {
- struct mv_dqh *qh;
-
- qh = ep->dqh;
- qh->next_dtd_ptr = 1;
- qh->size_ioc_int_sts = 0;
- }
-
- /* The request hasn't been processed, patch up the TD chain */
- } else {
- struct mv_req *prev_req;
-
- prev_req = list_entry(req->queue.prev, struct mv_req, queue);
- writel(readl(&req->tail->dtd_next),
- &prev_req->tail->dtd_next);
-
- }
-
- done(ep, req, -ECONNRESET);
-
- /* Enable EP */
-out:
- epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
- if (ep_dir(ep) == EP_DIR_IN)
- epctrlx |= EPCTRL_TX_ENABLE;
- else
- epctrlx |= EPCTRL_RX_ENABLE;
- writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
- ep->stopped = stopped;
-
- spin_unlock_irqrestore(&ep->udc->lock, flags);
- return ret;
-}
-
-static void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall)
-{
- u32 epctrlx;
-
- epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
-
- if (stall) {
- if (direction == EP_DIR_IN)
- epctrlx |= EPCTRL_TX_EP_STALL;
- else
- epctrlx |= EPCTRL_RX_EP_STALL;
- } else {
- if (direction == EP_DIR_IN) {
- epctrlx &= ~EPCTRL_TX_EP_STALL;
- epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST;
- } else {
- epctrlx &= ~EPCTRL_RX_EP_STALL;
- epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST;
- }
- }
- writel(epctrlx, &udc->op_regs->epctrlx[ep_num]);
-}
-
-static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
-{
- u32 epctrlx;
-
- epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
-
- if (direction == EP_DIR_OUT)
- return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0;
- else
- return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0;
-}
-
-static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
-{
- struct mv_ep *ep;
- unsigned long flags;
- int status = 0;
- struct mv_udc *udc;
-
- ep = container_of(_ep, struct mv_ep, ep);
- udc = ep->udc;
- if (!_ep || !ep->ep.desc) {
- status = -EINVAL;
- goto out;
- }
-
- if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
- status = -EOPNOTSUPP;
- goto out;
- }
-
- /*
- * Attempt to halt IN ep will fail if any transfer requests
- * are still queue
- */
- if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) {
- status = -EAGAIN;
- goto out;
- }
-
- spin_lock_irqsave(&ep->udc->lock, flags);
- ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt);
- if (halt && wedge)
- ep->wedge = 1;
- else if (!halt)
- ep->wedge = 0;
- spin_unlock_irqrestore(&ep->udc->lock, flags);
-
- if (ep->ep_num == 0) {
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = EP_DIR_OUT;
- }
-out:
- return status;
-}
-
-static int mv_ep_set_halt(struct usb_ep *_ep, int halt)
-{
- return mv_ep_set_halt_wedge(_ep, halt, 0);
-}
-
-static int mv_ep_set_wedge(struct usb_ep *_ep)
-{
- return mv_ep_set_halt_wedge(_ep, 1, 1);
-}
-
-static const struct usb_ep_ops mv_ep_ops = {
- .enable = mv_ep_enable,
- .disable = mv_ep_disable,
-
- .alloc_request = mv_alloc_request,
- .free_request = mv_free_request,
-
- .queue = mv_ep_queue,
- .dequeue = mv_ep_dequeue,
-
- .set_wedge = mv_ep_set_wedge,
- .set_halt = mv_ep_set_halt,
- .fifo_flush = mv_ep_fifo_flush, /* flush fifo */
-};
-
-static int udc_clock_enable(struct mv_udc *udc)
-{
- return clk_prepare_enable(udc->clk);
-}
-
-static void udc_clock_disable(struct mv_udc *udc)
-{
- clk_disable_unprepare(udc->clk);
-}
-
-static void udc_stop(struct mv_udc *udc)
-{
- u32 tmp;
-
- /* Disable interrupts */
- tmp = readl(&udc->op_regs->usbintr);
- tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN |
- USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
- writel(tmp, &udc->op_regs->usbintr);
-
- udc->stopped = 1;
-
- /* Reset the Run the bit in the command register to stop VUSB */
- tmp = readl(&udc->op_regs->usbcmd);
- tmp &= ~USBCMD_RUN_STOP;
- writel(tmp, &udc->op_regs->usbcmd);
-}
-
-static void udc_start(struct mv_udc *udc)
-{
- u32 usbintr;
-
- usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN
- | USBINTR_PORT_CHANGE_DETECT_EN
- | USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND;
- /* Enable interrupts */
- writel(usbintr, &udc->op_regs->usbintr);
-
- udc->stopped = 0;
-
- /* Set the Run bit in the command register */
- writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
-}
-
-static int udc_reset(struct mv_udc *udc)
-{
- unsigned int loops;
- u32 tmp, portsc;
-
- /* Stop the controller */
- tmp = readl(&udc->op_regs->usbcmd);
- tmp &= ~USBCMD_RUN_STOP;
- writel(tmp, &udc->op_regs->usbcmd);
-
- /* Reset the controller to get default values */
- writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd);
-
- /* wait for reset to complete */
- loops = LOOPS(RESET_TIMEOUT);
- while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
- if (loops == 0) {
- dev_err(&udc->dev->dev,
- "Wait for RESET completed TIMEOUT\n");
- return -ETIMEDOUT;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
-
- /* set controller to device mode */
- tmp = readl(&udc->op_regs->usbmode);
- tmp |= USBMODE_CTRL_MODE_DEVICE;
-
- /* turn setup lockout off, require setup tripwire in usbcmd */
- tmp |= USBMODE_SETUP_LOCK_OFF;
-
- writel(tmp, &udc->op_regs->usbmode);
-
- writel(0x0, &udc->op_regs->epsetupstat);
-
- /* Configure the Endpoint List Address */
- writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK,
- &udc->op_regs->eplistaddr);
-
- portsc = readl(&udc->op_regs->portsc[0]);
- if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC)
- portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER);
-
- if (udc->force_fs)
- portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT;
- else
- portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT);
-
- writel(portsc, &udc->op_regs->portsc[0]);
-
- tmp = readl(&udc->op_regs->epctrlx[0]);
- tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL);
- writel(tmp, &udc->op_regs->epctrlx[0]);
-
- return 0;
-}
-
-static int mv_udc_enable_internal(struct mv_udc *udc)
-{
- int retval;
-
- if (udc->active)
- return 0;
-
- dev_dbg(&udc->dev->dev, "enable udc\n");
- retval = udc_clock_enable(udc);
- if (retval)
- return retval;
-
- if (udc->pdata->phy_init) {
- retval = udc->pdata->phy_init(udc->phy_regs);
- if (retval) {
- dev_err(&udc->dev->dev,
- "init phy error %d\n", retval);
- udc_clock_disable(udc);
- return retval;
- }
- }
- udc->active = 1;
-
- return 0;
-}
-
-static int mv_udc_enable(struct mv_udc *udc)
-{
- if (udc->clock_gating)
- return mv_udc_enable_internal(udc);
-
- return 0;
-}
-
-static void mv_udc_disable_internal(struct mv_udc *udc)
-{
- if (udc->active) {
- dev_dbg(&udc->dev->dev, "disable udc\n");
- if (udc->pdata->phy_deinit)
- udc->pdata->phy_deinit(udc->phy_regs);
- udc_clock_disable(udc);
- udc->active = 0;
- }
-}
-
-static void mv_udc_disable(struct mv_udc *udc)
-{
- if (udc->clock_gating)
- mv_udc_disable_internal(udc);
-}
-
-static int mv_udc_get_frame(struct usb_gadget *gadget)
-{
- struct mv_udc *udc;
- u16 retval;
-
- if (!gadget)
- return -ENODEV;
-
- udc = container_of(gadget, struct mv_udc, gadget);
-
- retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
-
- return retval;
-}
-
-/* Tries to wake up the host connected to this gadget */
-static int mv_udc_wakeup(struct usb_gadget *gadget)
-{
- struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget);
- u32 portsc;
-
- /* Remote wakeup feature not enabled by host */
- if (!udc->remote_wakeup)
- return -ENOTSUPP;
-
- portsc = readl(&udc->op_regs->portsc);
- /* not suspended? */
- if (!(portsc & PORTSCX_PORT_SUSPEND))
- return 0;
- /* trigger force resume */
- portsc |= PORTSCX_PORT_FORCE_RESUME;
- writel(portsc, &udc->op_regs->portsc[0]);
- return 0;
-}
-
-static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
-{
- struct mv_udc *udc;
- unsigned long flags;
- int retval = 0;
-
- udc = container_of(gadget, struct mv_udc, gadget);
- spin_lock_irqsave(&udc->lock, flags);
-
- udc->vbus_active = (is_active != 0);
-
- dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
- __func__, udc->softconnect, udc->vbus_active);
-
- if (udc->driver && udc->softconnect && udc->vbus_active) {
- retval = mv_udc_enable(udc);
- if (retval == 0) {
- /* Clock is disabled, need re-init registers */
- udc_reset(udc);
- ep0_reset(udc);
- udc_start(udc);
- }
- } else if (udc->driver && udc->softconnect) {
- if (!udc->active)
- goto out;
-
- /* stop all the transfer in queue*/
- stop_activity(udc, udc->driver);
- udc_stop(udc);
- mv_udc_disable(udc);
- }
-
-out:
- spin_unlock_irqrestore(&udc->lock, flags);
- return retval;
-}
-
-static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
-{
- struct mv_udc *udc;
- unsigned long flags;
- int retval = 0;
-
- udc = container_of(gadget, struct mv_udc, gadget);
- spin_lock_irqsave(&udc->lock, flags);
-
- udc->softconnect = (is_on != 0);
-
- dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
- __func__, udc->softconnect, udc->vbus_active);
-
- if (udc->driver && udc->softconnect && udc->vbus_active) {
- retval = mv_udc_enable(udc);
- if (retval == 0) {
- /* Clock is disabled, need re-init registers */
- udc_reset(udc);
- ep0_reset(udc);
- udc_start(udc);
- }
- } else if (udc->driver && udc->vbus_active) {
- /* stop all the transfer in queue*/
- stop_activity(udc, udc->driver);
- udc_stop(udc);
- mv_udc_disable(udc);
- }
-
- spin_unlock_irqrestore(&udc->lock, flags);
- return retval;
-}
-
-static int mv_udc_start(struct usb_gadget *, struct usb_gadget_driver *);
-static int mv_udc_stop(struct usb_gadget *);
-/* device controller usb_gadget_ops structure */
-static const struct usb_gadget_ops mv_ops = {
-
- /* returns the current frame number */
- .get_frame = mv_udc_get_frame,
-
- /* tries to wake up the host connected to this gadget */
- .wakeup = mv_udc_wakeup,
-
- /* notify controller that VBUS is powered or not */
- .vbus_session = mv_udc_vbus_session,
-
- /* D+ pullup, software-controlled connect/disconnect to USB host */
- .pullup = mv_udc_pullup,
- .udc_start = mv_udc_start,
- .udc_stop = mv_udc_stop,
-};
-
-static int eps_init(struct mv_udc *udc)
-{
- struct mv_ep *ep;
- char name[14];
- int i;
-
- /* initialize ep0 */
- ep = &udc->eps[0];
- ep->udc = udc;
- strncpy(ep->name, "ep0", sizeof(ep->name));
- ep->ep.name = ep->name;
- ep->ep.ops = &mv_ep_ops;
- ep->wedge = 0;
- ep->stopped = 0;
- usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE);
- ep->ep.caps.type_control = true;
- ep->ep.caps.dir_in = true;
- ep->ep.caps.dir_out = true;
- ep->ep_num = 0;
- ep->ep.desc = &mv_ep0_desc;
- INIT_LIST_HEAD(&ep->queue);
-
- ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
- /* initialize other endpoints */
- for (i = 2; i < udc->max_eps * 2; i++) {
- ep = &udc->eps[i];
- if (i % 2) {
- snprintf(name, sizeof(name), "ep%din", i / 2);
- ep->direction = EP_DIR_IN;
- ep->ep.caps.dir_in = true;
- } else {
- snprintf(name, sizeof(name), "ep%dout", i / 2);
- ep->direction = EP_DIR_OUT;
- ep->ep.caps.dir_out = true;
- }
- ep->udc = udc;
- strncpy(ep->name, name, sizeof(ep->name));
- ep->ep.name = ep->name;
-
- ep->ep.caps.type_iso = true;
- ep->ep.caps.type_bulk = true;
- ep->ep.caps.type_int = true;
-
- ep->ep.ops = &mv_ep_ops;
- ep->stopped = 0;
- usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
- ep->ep_num = i / 2;
-
- INIT_LIST_HEAD(&ep->queue);
- list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-
- ep->dqh = &udc->ep_dqh[i];
- }
-
- return 0;
-}
-
-/* delete all endpoint requests, called with spinlock held */
-static void nuke(struct mv_ep *ep, int status)
-{
- /* called with spinlock held */
- ep->stopped = 1;
-
- /* endpoint fifo flush */
- mv_ep_fifo_flush(&ep->ep);
-
- while (!list_empty(&ep->queue)) {
- struct mv_req *req = NULL;
- req = list_entry(ep->queue.next, struct mv_req, queue);
- done(ep, req, status);
- }
-}
-
-static void gadget_reset(struct mv_udc *udc, struct usb_gadget_driver *driver)
-{
- struct mv_ep *ep;
-
- nuke(&udc->eps[0], -ESHUTDOWN);
-
- list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- nuke(ep, -ESHUTDOWN);
- }
-
- /* report reset; the driver is already quiesced */
- if (driver) {
- spin_unlock(&udc->lock);
- usb_gadget_udc_reset(&udc->gadget, driver);
- spin_lock(&udc->lock);
- }
-}
-/* stop all USB activities */
-static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
-{
- struct mv_ep *ep;
-
- nuke(&udc->eps[0], -ESHUTDOWN);
-
- list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- nuke(ep, -ESHUTDOWN);
- }
-
- /* report disconnect; the driver is already quiesced */
- if (driver) {
- spin_unlock(&udc->lock);
- driver->disconnect(&udc->gadget);
- spin_lock(&udc->lock);
- }
-}
-
-static int mv_udc_start(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- struct mv_udc *udc;
- int retval = 0;
- unsigned long flags;
-
- udc = container_of(gadget, struct mv_udc, gadget);
-
- if (udc->driver)
- return -EBUSY;
-
- spin_lock_irqsave(&udc->lock, flags);
-
- /* hook up the driver ... */
- udc->driver = driver;
-
- udc->usb_state = USB_STATE_ATTACHED;
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->ep0_dir = EP_DIR_OUT;
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver->otg,
- &udc->gadget);
- if (retval) {
- dev_err(&udc->dev->dev,
- "unable to register peripheral to otg\n");
- udc->driver = NULL;
- return retval;
- }
- }
-
- /* When boot with cable attached, there will be no vbus irq occurred */
- if (udc->qwork)
- queue_work(udc->qwork, &udc->vbus_work);
-
- return 0;
-}
-
-static int mv_udc_stop(struct usb_gadget *gadget)
-{
- struct mv_udc *udc;
- unsigned long flags;
-
- udc = container_of(gadget, struct mv_udc, gadget);
-
- spin_lock_irqsave(&udc->lock, flags);
-
- mv_udc_enable(udc);
- udc_stop(udc);
-
- /* stop all usb activities */
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- stop_activity(udc, NULL);
- mv_udc_disable(udc);
-
- spin_unlock_irqrestore(&udc->lock, flags);
-
- /* unbind gadget driver */
- udc->driver = NULL;
-
- return 0;
-}
-
-static void mv_set_ptc(struct mv_udc *udc, u32 mode)
-{
- u32 portsc;
-
- portsc = readl(&udc->op_regs->portsc[0]);
- portsc |= mode << 16;
- writel(portsc, &udc->op_regs->portsc[0]);
-}
-
-static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
-{
- struct mv_ep *mvep = container_of(ep, struct mv_ep, ep);
- struct mv_req *req = container_of(_req, struct mv_req, req);
- struct mv_udc *udc;
- unsigned long flags;
-
- udc = mvep->udc;
-
- dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
-
- spin_lock_irqsave(&udc->lock, flags);
- if (req->test_mode) {
- mv_set_ptc(udc, req->test_mode);
- req->test_mode = 0;
- }
- spin_unlock_irqrestore(&udc->lock, flags);
-}
-
-static int
-udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
-{
- int retval = 0;
- struct mv_req *req;
- struct mv_ep *ep;
-
- ep = &udc->eps[0];
- udc->ep0_dir = direction;
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
-
- req = udc->status_req;
-
- /* fill in the request structure */
- if (empty == false) {
- *((u16 *) req->req.buf) = cpu_to_le16(status);
- req->req.length = 2;
- } else
- req->req.length = 0;
-
- req->ep = ep;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- if (udc->test_mode) {
- req->req.complete = prime_status_complete;
- req->test_mode = udc->test_mode;
- udc->test_mode = 0;
- } else
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
- }
-
- /* prime the data phase */
- if (!req_to_dtd(req)) {
- retval = queue_dtd(ep, req);
- if (retval) {
- dev_err(&udc->dev->dev,
- "Failed to queue dtd when prime status\n");
- goto out;
- }
- } else{ /* no mem */
- retval = -ENOMEM;
- dev_err(&udc->dev->dev,
- "Failed to dma_pool_alloc when prime status\n");
- goto out;
- }
-
- list_add_tail(&req->queue, &ep->queue);
-
- return 0;
-out:
- usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
-
- return retval;
-}
-
-static void mv_udc_testmode(struct mv_udc *udc, u16 index)
-{
- if (index <= USB_TEST_FORCE_ENABLE) {
- udc->test_mode = index;
- if (udc_prime_status(udc, EP_DIR_IN, 0, true))
- ep0_stall(udc);
- } else
- dev_err(&udc->dev->dev,
- "This test mode(%d) is not supported\n", index);
-}
-
-static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup)
-{
- udc->dev_addr = (u8)setup->wValue;
-
- /* update usb state */
- udc->usb_state = USB_STATE_ADDRESS;
-
- if (udc_prime_status(udc, EP_DIR_IN, 0, true))
- ep0_stall(udc);
-}
-
-static void ch9getstatus(struct mv_udc *udc, u8 ep_num,
- struct usb_ctrlrequest *setup)
-{
- u16 status = 0;
- int retval;
-
- if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
- != (USB_DIR_IN | USB_TYPE_STANDARD))
- return;
-
- if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- status = 1 << USB_DEVICE_SELF_POWERED;
- status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
- } else if ((setup->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_INTERFACE) {
- /* get interface status */
- status = 0;
- } else if ((setup->bRequestType & USB_RECIP_MASK)
- == USB_RECIP_ENDPOINT) {
- u8 ep_num, direction;
-
- ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
- direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
- ? EP_DIR_IN : EP_DIR_OUT;
- status = ep_is_stall(udc, ep_num, direction)
- << USB_ENDPOINT_HALT;
- }
-
- retval = udc_prime_status(udc, EP_DIR_IN, status, false);
- if (retval)
- ep0_stall(udc);
- else
- udc->ep0_state = DATA_STATE_XMIT;
-}
-
-static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
-{
- u8 ep_num;
- u8 direction;
- struct mv_ep *ep;
-
- if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
- == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
- switch (setup->wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- udc->remote_wakeup = 0;
- break;
- default:
- goto out;
- }
- } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
- == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
- switch (setup->wValue) {
- case USB_ENDPOINT_HALT:
- ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
- direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
- ? EP_DIR_IN : EP_DIR_OUT;
- if (setup->wValue != 0 || setup->wLength != 0
- || ep_num > udc->max_eps)
- goto out;
- ep = &udc->eps[ep_num * 2 + direction];
- if (ep->wedge == 1)
- break;
- spin_unlock(&udc->lock);
- ep_set_stall(udc, ep_num, direction, 0);
- spin_lock(&udc->lock);
- break;
- default:
- goto out;
- }
- } else
- goto out;
-
- if (udc_prime_status(udc, EP_DIR_IN, 0, true))
- ep0_stall(udc);
-out:
- return;
-}
-
-static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
-{
- u8 ep_num;
- u8 direction;
-
- if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
- == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
- switch (setup->wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- udc->remote_wakeup = 1;
- break;
- case USB_DEVICE_TEST_MODE:
- if (setup->wIndex & 0xFF
- || udc->gadget.speed != USB_SPEED_HIGH)
- ep0_stall(udc);
-
- if (udc->usb_state != USB_STATE_CONFIGURED
- && udc->usb_state != USB_STATE_ADDRESS
- && udc->usb_state != USB_STATE_DEFAULT)
- ep0_stall(udc);
-
- mv_udc_testmode(udc, (setup->wIndex >> 8));
- goto out;
- default:
- goto out;
- }
- } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
- == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
- switch (setup->wValue) {
- case USB_ENDPOINT_HALT:
- ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
- direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
- ? EP_DIR_IN : EP_DIR_OUT;
- if (setup->wValue != 0 || setup->wLength != 0
- || ep_num > udc->max_eps)
- goto out;
- spin_unlock(&udc->lock);
- ep_set_stall(udc, ep_num, direction, 1);
- spin_lock(&udc->lock);
- break;
- default:
- goto out;
- }
- } else
- goto out;
-
- if (udc_prime_status(udc, EP_DIR_IN, 0, true))
- ep0_stall(udc);
-out:
- return;
-}
-
-static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
- struct usb_ctrlrequest *setup)
- __releases(&ep->udc->lock)
- __acquires(&ep->udc->lock)
-{
- bool delegate = false;
-
- nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN);
-
- dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
- setup->bRequestType, setup->bRequest,
- setup->wValue, setup->wIndex, setup->wLength);
- /* We process some standard setup requests here */
- if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- switch (setup->bRequest) {
- case USB_REQ_GET_STATUS:
- ch9getstatus(udc, ep_num, setup);
- break;
-
- case USB_REQ_SET_ADDRESS:
- ch9setaddress(udc, setup);
- break;
-
- case USB_REQ_CLEAR_FEATURE:
- ch9clearfeature(udc, setup);
- break;
-
- case USB_REQ_SET_FEATURE:
- ch9setfeature(udc, setup);
- break;
-
- default:
- delegate = true;
- }
- } else
- delegate = true;
-
- /* delegate USB standard requests to the gadget driver */
- if (delegate == true) {
- /* USB requests handled by gadget */
- if (setup->wLength) {
- /* DATA phase from gadget, STATUS phase from udc */
- udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
- ? EP_DIR_IN : EP_DIR_OUT;
- spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
- &udc->local_setup_buff) < 0)
- ep0_stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
- ? DATA_STATE_XMIT : DATA_STATE_RECV;
- } else {
- /* no DATA phase, IN STATUS phase from gadget */
- udc->ep0_dir = EP_DIR_IN;
- spin_unlock(&udc->lock);
- if (udc->driver->setup(&udc->gadget,
- &udc->local_setup_buff) < 0)
- ep0_stall(udc);
- spin_lock(&udc->lock);
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
- }
- }
-}
-
-/* complete DATA or STATUS phase of ep0 prime status phase if needed */
-static void ep0_req_complete(struct mv_udc *udc,
- struct mv_ep *ep0, struct mv_req *req)
-{
- u32 new_addr;
-
- if (udc->usb_state == USB_STATE_ADDRESS) {
- /* set the new address */
- new_addr = (u32)udc->dev_addr;
- writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT,
- &udc->op_regs->deviceaddr);
- }
-
- done(ep0, req, 0);
-
- switch (udc->ep0_state) {
- case DATA_STATE_XMIT:
- /* receive status phase */
- if (udc_prime_status(udc, EP_DIR_OUT, 0, true))
- ep0_stall(udc);
- break;
- case DATA_STATE_RECV:
- /* send status phase */
- if (udc_prime_status(udc, EP_DIR_IN, 0 , true))
- ep0_stall(udc);
- break;
- case WAIT_FOR_OUT_STATUS:
- udc->ep0_state = WAIT_FOR_SETUP;
- break;
- case WAIT_FOR_SETUP:
- dev_err(&udc->dev->dev, "unexpect ep0 packets\n");
- break;
- default:
- ep0_stall(udc);
- break;
- }
-}
-
-static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr)
-{
- u32 temp;
- struct mv_dqh *dqh;
-
- dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT];
-
- /* Clear bit in ENDPTSETUPSTAT */
- writel((1 << ep_num), &udc->op_regs->epsetupstat);
-
- /* while a hazard exists when setup package arrives */
- do {
- /* Set Setup Tripwire */
- temp = readl(&udc->op_regs->usbcmd);
- writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
-
- /* Copy the setup packet to local buffer */
- memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8);
- } while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET));
-
- /* Clear Setup Tripwire */
- temp = readl(&udc->op_regs->usbcmd);
- writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
-}
-
-static void irq_process_tr_complete(struct mv_udc *udc)
-{
- u32 tmp, bit_pos;
- int i, ep_num = 0, direction = 0;
- struct mv_ep *curr_ep;
- struct mv_req *curr_req, *temp_req;
- int status;
-
- /*
- * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE
- * because the setup packets are to be read ASAP
- */
-
- /* Process all Setup packet received interrupts */
- tmp = readl(&udc->op_regs->epsetupstat);
-
- if (tmp) {
- for (i = 0; i < udc->max_eps; i++) {
- if (tmp & (1 << i)) {
- get_setup_data(udc, i,
- (u8 *)(&udc->local_setup_buff));
- handle_setup_packet(udc, i,
- &udc->local_setup_buff);
- }
- }
- }
-
- /* Don't clear the endpoint setup status register here.
- * It is cleared as a setup packet is read out of the buffer
- */
-
- /* Process non-setup transaction complete interrupts */
- tmp = readl(&udc->op_regs->epcomplete);
-
- if (!tmp)
- return;
-
- writel(tmp, &udc->op_regs->epcomplete);
-
- for (i = 0; i < udc->max_eps * 2; i++) {
- ep_num = i >> 1;
- direction = i % 2;
-
- bit_pos = 1 << (ep_num + 16 * direction);
-
- if (!(bit_pos & tmp))
- continue;
-
- if (i == 1)
- curr_ep = &udc->eps[0];
- else
- curr_ep = &udc->eps[i];
- /* process the req queue until an uncomplete request */
- list_for_each_entry_safe(curr_req, temp_req,
- &curr_ep->queue, queue) {
- status = process_ep_req(udc, i, curr_req);
- if (status)
- break;
-
- /* write back status to req */
- curr_req->req.status = status;
-
- /* ep0 request completion */
- if (ep_num == 0) {
- ep0_req_complete(udc, curr_ep, curr_req);
- break;
- } else {
- done(curr_ep, curr_req, status);
- }
- }
- }
-}
-
-static void irq_process_reset(struct mv_udc *udc)
-{
- u32 tmp;
- unsigned int loops;
-
- udc->ep0_dir = EP_DIR_OUT;
- udc->ep0_state = WAIT_FOR_SETUP;
- udc->remote_wakeup = 0; /* default to 0 on reset */
-
- /* The address bits are past bit 25-31. Set the address */
- tmp = readl(&udc->op_regs->deviceaddr);
- tmp &= ~(USB_DEVICE_ADDRESS_MASK);
- writel(tmp, &udc->op_regs->deviceaddr);
-
- /* Clear all the setup token semaphores */
- tmp = readl(&udc->op_regs->epsetupstat);
- writel(tmp, &udc->op_regs->epsetupstat);
-
- /* Clear all the endpoint complete status bits */
- tmp = readl(&udc->op_regs->epcomplete);
- writel(tmp, &udc->op_regs->epcomplete);
-
- /* wait until all endptprime bits cleared */
- loops = LOOPS(PRIME_TIMEOUT);
- while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) {
- if (loops == 0) {
- dev_err(&udc->dev->dev,
- "Timeout for ENDPTPRIME = 0x%x\n",
- readl(&udc->op_regs->epprime));
- break;
- }
- loops--;
- udelay(LOOPS_USEC);
- }
-
- /* Write 1s to the Flush register */
- writel((u32)~0, &udc->op_regs->epflush);
-
- if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) {
- dev_info(&udc->dev->dev, "usb bus reset\n");
- udc->usb_state = USB_STATE_DEFAULT;
- /* reset all the queues, stop all USB activities */
- gadget_reset(udc, udc->driver);
- } else {
- dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n",
- readl(&udc->op_regs->portsc));
-
- /*
- * re-initialize
- * controller reset
- */
- udc_reset(udc);
-
- /* reset all the queues, stop all USB activities */
- stop_activity(udc, udc->driver);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(udc);
-
- /* enable interrupt and set controller to run state */
- udc_start(udc);
-
- udc->usb_state = USB_STATE_ATTACHED;
- }
-}
-
-static void handle_bus_resume(struct mv_udc *udc)
-{
- udc->usb_state = udc->resume_state;
- udc->resume_state = 0;
-
- /* report resume to the driver */
- if (udc->driver) {
- if (udc->driver->resume) {
- spin_unlock(&udc->lock);
- udc->driver->resume(&udc->gadget);
- spin_lock(&udc->lock);
- }
- }
-}
-
-static void irq_process_suspend(struct mv_udc *udc)
-{
- udc->resume_state = udc->usb_state;
- udc->usb_state = USB_STATE_SUSPENDED;
-
- if (udc->driver->suspend) {
- spin_unlock(&udc->lock);
- udc->driver->suspend(&udc->gadget);
- spin_lock(&udc->lock);
- }
-}
-
-static void irq_process_port_change(struct mv_udc *udc)
-{
- u32 portsc;
-
- portsc = readl(&udc->op_regs->portsc[0]);
- if (!(portsc & PORTSCX_PORT_RESET)) {
- /* Get the speed */
- u32 speed = portsc & PORTSCX_PORT_SPEED_MASK;
- switch (speed) {
- case PORTSCX_PORT_SPEED_HIGH:
- udc->gadget.speed = USB_SPEED_HIGH;
- break;
- case PORTSCX_PORT_SPEED_FULL:
- udc->gadget.speed = USB_SPEED_FULL;
- break;
- case PORTSCX_PORT_SPEED_LOW:
- udc->gadget.speed = USB_SPEED_LOW;
- break;
- default:
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- break;
- }
- }
-
- if (portsc & PORTSCX_PORT_SUSPEND) {
- udc->resume_state = udc->usb_state;
- udc->usb_state = USB_STATE_SUSPENDED;
- if (udc->driver->suspend) {
- spin_unlock(&udc->lock);
- udc->driver->suspend(&udc->gadget);
- spin_lock(&udc->lock);
- }
- }
-
- if (!(portsc & PORTSCX_PORT_SUSPEND)
- && udc->usb_state == USB_STATE_SUSPENDED) {
- handle_bus_resume(udc);
- }
-
- if (!udc->resume_state)
- udc->usb_state = USB_STATE_DEFAULT;
-}
-
-static void irq_process_error(struct mv_udc *udc)
-{
- /* Increment the error count */
- udc->errors++;
-}
-
-static irqreturn_t mv_udc_irq(int irq, void *dev)
-{
- struct mv_udc *udc = (struct mv_udc *)dev;
- u32 status, intr;
-
- /* Disable ISR when stopped bit is set */
- if (udc->stopped)
- return IRQ_NONE;
-
- spin_lock(&udc->lock);
-
- status = readl(&udc->op_regs->usbsts);
- intr = readl(&udc->op_regs->usbintr);
- status &= intr;
-
- if (status == 0) {
- spin_unlock(&udc->lock);
- return IRQ_NONE;
- }
-
- /* Clear all the interrupts occurred */
- writel(status, &udc->op_regs->usbsts);
-
- if (status & USBSTS_ERR)
- irq_process_error(udc);
-
- if (status & USBSTS_RESET)
- irq_process_reset(udc);
-
- if (status & USBSTS_PORT_CHANGE)
- irq_process_port_change(udc);
-
- if (status & USBSTS_INT)
- irq_process_tr_complete(udc);
-
- if (status & USBSTS_SUSPEND)
- irq_process_suspend(udc);
-
- spin_unlock(&udc->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t mv_udc_vbus_irq(int irq, void *dev)
-{
- struct mv_udc *udc = (struct mv_udc *)dev;
-
- /* polling VBUS and init phy may cause too much time*/
- if (udc->qwork)
- queue_work(udc->qwork, &udc->vbus_work);
-
- return IRQ_HANDLED;
-}
-
-static void mv_udc_vbus_work(struct work_struct *work)
-{
- struct mv_udc *udc;
- unsigned int vbus;
-
- udc = container_of(work, struct mv_udc, vbus_work);
- if (!udc->pdata->vbus)
- return;
-
- vbus = udc->pdata->vbus->poll();
- dev_info(&udc->dev->dev, "vbus is %d\n", vbus);
-
- if (vbus == VBUS_HIGH)
- mv_udc_vbus_session(&udc->gadget, 1);
- else if (vbus == VBUS_LOW)
- mv_udc_vbus_session(&udc->gadget, 0);
-}
-
-/* release device structure */
-static void gadget_release(struct device *_dev)
-{
- struct mv_udc *udc;
-
- udc = dev_get_drvdata(_dev);
-
- complete(udc->done);
-}
-
-static void mv_udc_remove(struct platform_device *pdev)
-{
- struct mv_udc *udc;
-
- udc = platform_get_drvdata(pdev);
-
- usb_del_gadget_udc(&udc->gadget);
-
- if (udc->qwork)
- destroy_workqueue(udc->qwork);
-
- /* free memory allocated in probe */
- dma_pool_destroy(udc->dtd_pool);
-
- if (udc->ep_dqh)
- dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
- udc->ep_dqh, udc->ep_dqh_dma);
-
- mv_udc_disable(udc);
-
- /* free dev, wait for the release() finished */
- wait_for_completion(udc->done);
-}
-
-static int mv_udc_probe(struct platform_device *pdev)
-{
- struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct mv_udc *udc;
- int retval = 0;
- struct resource *r;
- size_t size;
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "missing platform_data\n");
- return -ENODEV;
- }
-
- udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
- if (udc == NULL)
- return -ENOMEM;
-
- udc->done = &release_done;
- udc->pdata = dev_get_platdata(&pdev->dev);
- spin_lock_init(&udc->lock);
-
- udc->dev = pdev;
-
- if (pdata->mode == MV_USB_MODE_OTG) {
- udc->transceiver = devm_usb_get_phy(&pdev->dev,
- USB_PHY_TYPE_USB2);
- if (IS_ERR(udc->transceiver)) {
- retval = PTR_ERR(udc->transceiver);
-
- if (retval == -ENXIO)
- return retval;
-
- udc->transceiver = NULL;
- return -EPROBE_DEFER;
- }
- }
-
- /* udc only have one sysclk. */
- udc->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(udc->clk))
- return PTR_ERR(udc->clk);
-
- r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
- if (r == NULL) {
- dev_err(&pdev->dev, "no I/O memory resource defined\n");
- return -ENODEV;
- }
-
- udc->cap_regs = (struct mv_cap_regs __iomem *)
- devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (udc->cap_regs == NULL) {
- dev_err(&pdev->dev, "failed to map I/O memory\n");
- return -EBUSY;
- }
-
- r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
- if (r == NULL) {
- dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
- return -ENODEV;
- }
-
- udc->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (udc->phy_regs == NULL) {
- dev_err(&pdev->dev, "failed to map phy I/O memory\n");
- return -EBUSY;
- }
-
- /* we will acces controller register, so enable the clk */
- retval = mv_udc_enable_internal(udc);
- if (retval)
- return retval;
-
- udc->op_regs =
- (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
- + (readl(&udc->cap_regs->caplength_hciversion)
- & CAPLENGTH_MASK));
- udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
-
- /*
- * some platform will use usb to download image, it may not disconnect
- * usb gadget before loading kernel. So first stop udc here.
- */
- udc_stop(udc);
- writel(0xFFFFFFFF, &udc->op_regs->usbsts);
-
- size = udc->max_eps * sizeof(struct mv_dqh) *2;
- size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
- udc->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
- &udc->ep_dqh_dma, GFP_KERNEL);
-
- if (udc->ep_dqh == NULL) {
- dev_err(&pdev->dev, "allocate dQH memory failed\n");
- retval = -ENOMEM;
- goto err_disable_clock;
- }
- udc->ep_dqh_size = size;
-
- /* create dTD dma_pool resource */
- udc->dtd_pool = dma_pool_create("mv_dtd",
- &pdev->dev,
- sizeof(struct mv_dtd),
- DTD_ALIGNMENT,
- DMA_BOUNDARY);
-
- if (!udc->dtd_pool) {
- retval = -ENOMEM;
- goto err_free_dma;
- }
-
- size = udc->max_eps * sizeof(struct mv_ep) *2;
- udc->eps = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
- if (udc->eps == NULL) {
- retval = -ENOMEM;
- goto err_destroy_dma;
- }
-
- /* initialize ep0 status request structure */
- udc->status_req = devm_kzalloc(&pdev->dev, sizeof(struct mv_req),
- GFP_KERNEL);
- if (!udc->status_req) {
- retval = -ENOMEM;
- goto err_destroy_dma;
- }
- INIT_LIST_HEAD(&udc->status_req->queue);
-
- /* allocate a small amount of memory to get valid address */
- udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL);
- if (!udc->status_req->req.buf) {
- retval = -ENOMEM;
- goto err_destroy_dma;
- }
- udc->status_req->req.dma = DMA_ADDR_INVALID;
-
- udc->resume_state = USB_STATE_NOTATTACHED;
- udc->usb_state = USB_STATE_POWERED;
- udc->ep0_dir = EP_DIR_OUT;
- udc->remote_wakeup = 0;
-
- r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no IRQ resource defined\n");
- retval = -ENODEV;
- goto err_destroy_dma;
- }
- udc->irq = r->start;
- if (devm_request_irq(&pdev->dev, udc->irq, mv_udc_irq,
- IRQF_SHARED, driver_name, udc)) {
- dev_err(&pdev->dev, "Request irq %d for UDC failed\n",
- udc->irq);
- retval = -ENODEV;
- goto err_destroy_dma;
- }
-
- /* initialize gadget structure */
- udc->gadget.ops = &mv_ops; /* usb_gadget_ops */
- udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */
- INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */
- udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
- udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
-
- /* the "gadget" abstracts/virtualizes the controller */
- udc->gadget.name = driver_name; /* gadget name */
-
- eps_init(udc);
-
- /* VBUS detect: we can disable/enable clock on demand.*/
- if (udc->transceiver)
- udc->clock_gating = 1;
- else if (pdata->vbus) {
- udc->clock_gating = 1;
- retval = devm_request_threaded_irq(&pdev->dev,
- pdata->vbus->irq, NULL,
- mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
- if (retval) {
- dev_info(&pdev->dev,
- "Can not request irq for VBUS, "
- "disable clock gating\n");
- udc->clock_gating = 0;
- }
-
- udc->qwork = create_singlethread_workqueue("mv_udc_queue");
- if (!udc->qwork) {
- dev_err(&pdev->dev, "cannot create workqueue\n");
- retval = -ENOMEM;
- goto err_destroy_dma;
- }
-
- INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
- }
-
- /*
- * When clock gating is supported, we can disable clk and phy.
- * If not, it means that VBUS detection is not supported, we
- * have to enable vbus active all the time to let controller work.
- */
- if (udc->clock_gating)
- mv_udc_disable_internal(udc);
- else
- udc->vbus_active = 1;
-
- retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
- gadget_release);
- if (retval)
- goto err_create_workqueue;
-
- platform_set_drvdata(pdev, udc);
- dev_info(&pdev->dev, "successful probe UDC device %s clock gating.\n",
- udc->clock_gating ? "with" : "without");
-
- return 0;
-
-err_create_workqueue:
- if (udc->qwork)
- destroy_workqueue(udc->qwork);
-err_destroy_dma:
- dma_pool_destroy(udc->dtd_pool);
-err_free_dma:
- dma_free_coherent(&pdev->dev, udc->ep_dqh_size,
- udc->ep_dqh, udc->ep_dqh_dma);
-err_disable_clock:
- mv_udc_disable_internal(udc);
-
- return retval;
-}
-
-#ifdef CONFIG_PM
-static int mv_udc_suspend(struct device *dev)
-{
- struct mv_udc *udc;
-
- udc = dev_get_drvdata(dev);
-
- /* if OTG is enabled, the following will be done in OTG driver*/
- if (udc->transceiver)
- return 0;
-
- if (udc->pdata->vbus && udc->pdata->vbus->poll)
- if (udc->pdata->vbus->poll() == VBUS_HIGH) {
- dev_info(&udc->dev->dev, "USB cable is connected!\n");
- return -EAGAIN;
- }
-
- /*
- * only cable is unplugged, udc can suspend.
- * So do not care about clock_gating == 1.
- */
- if (!udc->clock_gating) {
- udc_stop(udc);
-
- spin_lock_irq(&udc->lock);
- /* stop all usb activities */
- stop_activity(udc, udc->driver);
- spin_unlock_irq(&udc->lock);
-
- mv_udc_disable_internal(udc);
- }
-
- return 0;
-}
-
-static int mv_udc_resume(struct device *dev)
-{
- struct mv_udc *udc;
- int retval;
-
- udc = dev_get_drvdata(dev);
-
- /* if OTG is enabled, the following will be done in OTG driver*/
- if (udc->transceiver)
- return 0;
-
- if (!udc->clock_gating) {
- retval = mv_udc_enable_internal(udc);
- if (retval)
- return retval;
-
- if (udc->driver && udc->softconnect) {
- udc_reset(udc);
- ep0_reset(udc);
- udc_start(udc);
- }
- }
-
- return 0;
-}
-
-static const struct dev_pm_ops mv_udc_pm_ops = {
- .suspend = mv_udc_suspend,
- .resume = mv_udc_resume,
-};
-#endif
-
-static void mv_udc_shutdown(struct platform_device *pdev)
-{
- struct mv_udc *udc;
- u32 mode;
-
- udc = platform_get_drvdata(pdev);
- /* reset controller mode to IDLE */
- mv_udc_enable(udc);
- mode = readl(&udc->op_regs->usbmode);
- mode &= ~3;
- writel(mode, &udc->op_regs->usbmode);
- mv_udc_disable(udc);
-}
-
-static struct platform_driver udc_driver = {
- .probe = mv_udc_probe,
- .remove = mv_udc_remove,
- .shutdown = mv_udc_shutdown,
- .driver = {
- .name = "mv-udc",
-#ifdef CONFIG_PM
- .pm = &mv_udc_pm_ops,
-#endif
- },
-};
-
-module_platform_driver(udc_driver);
-MODULE_ALIAS("platform:mv-udc");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
deleted file mode 100644
index 7ecddbf5c90d..000000000000
--- a/drivers/usb/gadget/udc/net2272.c
+++ /dev/null
@@ -1,2723 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Driver for PLX NET2272 USB device controller
- *
- * Copyright (C) 2005-2006 PLX Technology, Inc.
- * Copyright (C) 2006-2011 Analog Devices, Inc.
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/prefetch.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/usb.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include <asm/byteorder.h>
-#include <linux/unaligned.h>
-
-#include "net2272.h"
-
-#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller"
-
-static const char driver_name[] = "net2272";
-static const char driver_vers[] = "2006 October 17/mainline";
-static const char driver_desc[] = DRIVER_DESC;
-
-static const char ep0name[] = "ep0";
-static const char * const ep_name[] = {
- ep0name,
- "ep-a", "ep-b", "ep-c",
-};
-
-#ifdef CONFIG_USB_NET2272_DMA
-/*
- * use_dma: the NET2272 can use an external DMA controller.
- * Note that since there is no generic DMA api, some functions,
- * notably request_dma, start_dma, and cancel_dma will need to be
- * modified for your platform's particular dma controller.
- *
- * If use_dma is disabled, pio will be used instead.
- */
-static bool use_dma = false;
-module_param(use_dma, bool, 0644);
-
-/*
- * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b)
- * The NET2272 can only use dma for a single endpoint at a time.
- * At some point this could be modified to allow either endpoint
- * to take control of dma as it becomes available.
- *
- * Note that DMA should not be used on OUT endpoints unless it can
- * be guaranteed that no short packets will arrive on an IN endpoint
- * while the DMA operation is pending. Otherwise the OUT DMA will
- * terminate prematurely (See NET2272 Errata 630-0213-0101)
- */
-static ushort dma_ep = 1;
-module_param(dma_ep, ushort, 0644);
-
-/*
- * dma_mode: net2272 dma mode setting (see LOCCTL1 definition):
- * mode 0 == Slow DREQ mode
- * mode 1 == Fast DREQ mode
- * mode 2 == Burst mode
- */
-static ushort dma_mode = 2;
-module_param(dma_mode, ushort, 0644);
-#else
-#define use_dma 0
-#define dma_ep 1
-#define dma_mode 2
-#endif
-
-/*
- * fifo_mode: net2272 buffer configuration:
- * mode 0 == ep-{a,b,c} 512db each
- * mode 1 == ep-a 1k, ep-{b,c} 512db
- * mode 2 == ep-a 1k, ep-b 1k, ep-c 512db
- * mode 3 == ep-a 1k, ep-b disabled, ep-c 512db
- */
-static ushort fifo_mode;
-module_param(fifo_mode, ushort, 0644);
-
-/*
- * enable_suspend: When enabled, the driver will respond to
- * USB suspend requests by powering down the NET2272. Otherwise,
- * USB suspend requests will be ignored. This is acceptable for
- * self-powered devices. For bus powered devices set this to 1.
- */
-static ushort enable_suspend;
-module_param(enable_suspend, ushort, 0644);
-
-static void assert_out_naking(struct net2272_ep *ep, const char *where)
-{
- u8 tmp;
-
-#ifndef DEBUG
- return;
-#endif
-
- tmp = net2272_ep_read(ep, EP_STAT0);
- if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
- dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n",
- ep->ep.name, where, tmp);
- net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
- }
-}
-#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
-
-static void stop_out_naking(struct net2272_ep *ep)
-{
- u8 tmp = net2272_ep_read(ep, EP_STAT0);
-
- if ((tmp & (1 << NAK_OUT_PACKETS)) != 0)
- net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
-}
-
-#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out")
-
-static char *type_string(u8 bmAttributes)
-{
- switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_BULK: return "bulk";
- case USB_ENDPOINT_XFER_ISOC: return "iso";
- case USB_ENDPOINT_XFER_INT: return "intr";
- default: return "control";
- }
-}
-
-static char *buf_state_string(unsigned state)
-{
- switch (state) {
- case BUFF_FREE: return "free";
- case BUFF_VALID: return "valid";
- case BUFF_LCL: return "local";
- case BUFF_USB: return "usb";
- default: return "unknown";
- }
-}
-
-static char *dma_mode_string(void)
-{
- if (!use_dma)
- return "PIO";
- switch (dma_mode) {
- case 0: return "SLOW DREQ";
- case 1: return "FAST DREQ";
- case 2: return "BURST";
- default: return "invalid";
- }
-}
-
-static void net2272_dequeue_all(struct net2272_ep *);
-static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *);
-static int net2272_fifo_status(struct usb_ep *);
-
-static const struct usb_ep_ops net2272_ep_ops;
-
-/*---------------------------------------------------------------------------*/
-
-static int
-net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
-{
- struct net2272 *dev;
- struct net2272_ep *ep;
- u32 max;
- u8 tmp;
- unsigned long flags;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || !desc || ep->desc || _ep->name == ep0name
- || desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
- dev = ep->dev;
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- max = usb_endpoint_maxp(desc);
-
- spin_lock_irqsave(&dev->lock, flags);
- _ep->maxpacket = max;
- ep->desc = desc;
-
- /* net2272_ep_reset() has already been called */
- ep->stopped = 0;
- ep->wedged = 0;
-
- /* set speed-dependent max packet */
- net2272_ep_write(ep, EP_MAXPKT0, max & 0xff);
- net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8);
-
- /* set type, direction, address; reset fifo counters */
- net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
- tmp = usb_endpoint_type(desc);
- if (usb_endpoint_xfer_bulk(desc)) {
- /* catch some particularly blatant driver bugs */
- if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) ||
- (dev->gadget.speed == USB_SPEED_FULL && max > 64)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ERANGE;
- }
- }
- ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0;
- tmp <<= ENDPOINT_TYPE;
- tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER);
- tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION;
- tmp |= (1 << ENDPOINT_ENABLE);
-
- /* for OUT transfers, block the rx fifo until a read is posted */
- ep->is_in = usb_endpoint_dir_in(desc);
- if (!ep->is_in)
- net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
-
- net2272_ep_write(ep, EP_CFG, tmp);
-
- /* enable irqs */
- tmp = (1 << ep->num) | net2272_read(dev, IRQENB0);
- net2272_write(dev, IRQENB0, tmp);
-
- tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
- | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
- | net2272_ep_read(ep, EP_IRQENB);
- net2272_ep_write(ep, EP_IRQENB, tmp);
-
- tmp = desc->bEndpointAddress;
- dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n",
- _ep->name, tmp & 0x0f, PIPEDIR(tmp),
- type_string(desc->bmAttributes), max,
- net2272_ep_read(ep, EP_CFG));
-
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
-}
-
-static void net2272_ep_reset(struct net2272_ep *ep)
-{
- u8 tmp;
-
- ep->desc = NULL;
- INIT_LIST_HEAD(&ep->queue);
-
- usb_ep_set_maxpacket_limit(&ep->ep, ~0);
- ep->ep.ops = &net2272_ep_ops;
-
- /* disable irqs, endpoint */
- net2272_ep_write(ep, EP_IRQENB, 0);
-
- /* init to our chosen defaults, notably so that we NAK OUT
- * packets until the driver queues a read.
- */
- tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS);
- net2272_ep_write(ep, EP_RSPSET, tmp);
-
- tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE);
- if (ep->num != 0)
- tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT);
-
- net2272_ep_write(ep, EP_RSPCLR, tmp);
-
- /* scrub most status bits, and flush any fifo state */
- net2272_ep_write(ep, EP_STAT0,
- (1 << DATA_IN_TOKEN_INTERRUPT)
- | (1 << DATA_OUT_TOKEN_INTERRUPT)
- | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
- | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
- | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT));
-
- net2272_ep_write(ep, EP_STAT1,
- (1 << TIMEOUT)
- | (1 << USB_OUT_ACK_SENT)
- | (1 << USB_OUT_NAK_SENT)
- | (1 << USB_IN_ACK_RCVD)
- | (1 << USB_IN_NAK_SENT)
- | (1 << USB_STALL_SENT)
- | (1 << LOCAL_OUT_ZLP)
- | (1 << BUFFER_FLUSH));
-
- /* fifo size is handled separately */
-}
-
-static int net2272_disable(struct usb_ep *_ep)
-{
- struct net2272_ep *ep;
- unsigned long flags;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || !ep->desc || _ep->name == ep0name)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->dev->lock, flags);
- net2272_dequeue_all(ep);
- net2272_ep_reset(ep);
-
- dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name);
-
- spin_unlock_irqrestore(&ep->dev->lock, flags);
- return 0;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static struct usb_request *
-net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
-{
- struct net2272_request *req;
-
- if (!_ep)
- return NULL;
-
- req = kzalloc(sizeof(*req), gfp_flags);
- if (!req)
- return NULL;
-
- INIT_LIST_HEAD(&req->queue);
-
- return &req->req;
-}
-
-static void
-net2272_free_request(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct net2272_request *req;
-
- if (!_ep || !_req)
- return;
-
- req = container_of(_req, struct net2272_request, req);
- WARN_ON(!list_empty(&req->queue));
- kfree(req);
-}
-
-static void
-net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status)
-{
- struct net2272 *dev;
- unsigned stopped = ep->stopped;
-
- if (ep->num == 0) {
- if (ep->dev->protocol_stall) {
- ep->stopped = 1;
- set_halt(ep);
- }
- allow_status(ep);
- }
-
- list_del_init(&req->queue);
-
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- dev = ep->dev;
- if (use_dma && ep->dma)
- usb_gadget_unmap_request(&dev->gadget, &req->req,
- ep->is_in);
-
- if (status && status != -ESHUTDOWN)
- dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n",
- ep->ep.name, &req->req, status,
- req->req.actual, req->req.length, req->req.buf);
-
- /* don't modify queue heads during completion callback */
- ep->stopped = 1;
- spin_unlock(&dev->lock);
- usb_gadget_giveback_request(&ep->ep, &req->req);
- spin_lock(&dev->lock);
- ep->stopped = stopped;
-}
-
-static int
-net2272_write_packet(struct net2272_ep *ep, u8 *buf,
- struct net2272_request *req, unsigned max)
-{
- u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA);
- u16 *bufp;
- unsigned length, count;
- u8 tmp;
-
- length = min(req->req.length - req->req.actual, max);
- req->req.actual += length;
-
- dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n",
- ep->ep.name, req, max, length,
- (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0));
-
- count = length;
- bufp = (u16 *)buf;
-
- while (likely(count >= 2)) {
- /* no byte-swap required; chip endian set during init */
- writew(*bufp++, ep_data);
- count -= 2;
- }
- buf = (u8 *)bufp;
-
- /* write final byte by placing the NET2272 into 8-bit mode */
- if (unlikely(count)) {
- tmp = net2272_read(ep->dev, LOCCTL);
- net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH));
- writeb(*buf, ep_data);
- net2272_write(ep->dev, LOCCTL, tmp);
- }
- return length;
-}
-
-/* returns: 0: still running, 1: completed, negative: errno */
-static int
-net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req)
-{
- u8 *buf;
- unsigned count, max;
- int status;
-
- dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n",
- ep->ep.name, req->req.actual, req->req.length);
-
- /*
- * Keep loading the endpoint until the final packet is loaded,
- * or the endpoint buffer is full.
- */
- top:
- /*
- * Clear interrupt status
- * - Packet Transmitted interrupt will become set again when the
- * host successfully takes another packet
- */
- net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT));
- while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) {
- buf = req->req.buf + req->req.actual;
- prefetch(buf);
-
- /* force pagesel */
- net2272_ep_read(ep, EP_STAT0);
-
- max = (net2272_ep_read(ep, EP_AVAIL1) << 8) |
- (net2272_ep_read(ep, EP_AVAIL0));
-
- if (max < ep->ep.maxpacket)
- max = (net2272_ep_read(ep, EP_AVAIL1) << 8)
- | (net2272_ep_read(ep, EP_AVAIL0));
-
- count = net2272_write_packet(ep, buf, req, max);
- /* see if we are done */
- if (req->req.length == req->req.actual) {
- /* validate short or zlp packet */
- if (count < ep->ep.maxpacket)
- set_fifo_bytecount(ep, 0);
- net2272_done(ep, req, 0);
-
- if (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct net2272_request,
- queue);
- status = net2272_kick_dma(ep, req);
-
- if (status < 0)
- if ((net2272_ep_read(ep, EP_STAT0)
- & (1 << BUFFER_EMPTY)))
- goto top;
- }
- return 1;
- }
- net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT));
- }
- return 0;
-}
-
-static void
-net2272_out_flush(struct net2272_ep *ep)
-{
- ASSERT_OUT_NAKING(ep);
-
- net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT)
- | (1 << DATA_PACKET_RECEIVED_INTERRUPT));
- net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
-}
-
-static int
-net2272_read_packet(struct net2272_ep *ep, u8 *buf,
- struct net2272_request *req, unsigned avail)
-{
- u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA);
- unsigned is_short;
- u16 *bufp;
-
- req->req.actual += avail;
-
- dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n",
- ep->ep.name, req, avail,
- (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0));
-
- is_short = (avail < ep->ep.maxpacket);
-
- if (unlikely(avail == 0)) {
- /* remove any zlp from the buffer */
- (void)readw(ep_data);
- return is_short;
- }
-
- /* Ensure we get the final byte */
- if (unlikely(avail % 2))
- avail++;
- bufp = (u16 *)buf;
-
- do {
- *bufp++ = readw(ep_data);
- avail -= 2;
- } while (avail);
-
- /*
- * To avoid false endpoint available race condition must read
- * ep stat0 twice in the case of a short transfer
- */
- if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))
- net2272_ep_read(ep, EP_STAT0);
-
- return is_short;
-}
-
-static int
-net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req)
-{
- u8 *buf;
- unsigned is_short;
- int count;
- int tmp;
- int cleanup = 0;
-
- dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n",
- ep->ep.name, req->req.actual, req->req.length);
-
- top:
- do {
- buf = req->req.buf + req->req.actual;
- prefetchw(buf);
-
- count = (net2272_ep_read(ep, EP_AVAIL1) << 8)
- | net2272_ep_read(ep, EP_AVAIL0);
-
- net2272_ep_write(ep, EP_STAT0,
- (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) |
- (1 << DATA_PACKET_RECEIVED_INTERRUPT));
-
- tmp = req->req.length - req->req.actual;
-
- if (count > tmp) {
- if ((tmp % ep->ep.maxpacket) != 0) {
- dev_err(ep->dev->dev,
- "%s out fifo %d bytes, expected %d\n",
- ep->ep.name, count, tmp);
- cleanup = 1;
- }
- count = (tmp > 0) ? tmp : 0;
- }
-
- is_short = net2272_read_packet(ep, buf, req, count);
-
- /* completion */
- if (unlikely(cleanup || is_short ||
- req->req.actual == req->req.length)) {
-
- if (cleanup) {
- net2272_out_flush(ep);
- net2272_done(ep, req, -EOVERFLOW);
- } else
- net2272_done(ep, req, 0);
-
- /* re-initialize endpoint transfer registers
- * otherwise they may result in erroneous pre-validation
- * for subsequent control reads
- */
- if (unlikely(ep->num == 0)) {
- net2272_ep_write(ep, EP_TRANSFER2, 0);
- net2272_ep_write(ep, EP_TRANSFER1, 0);
- net2272_ep_write(ep, EP_TRANSFER0, 0);
- }
-
- if (!list_empty(&ep->queue)) {
- int status;
-
- req = list_entry(ep->queue.next,
- struct net2272_request, queue);
- status = net2272_kick_dma(ep, req);
- if ((status < 0) &&
- !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY)))
- goto top;
- }
- return 1;
- }
- } while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY)));
-
- return 0;
-}
-
-static void
-net2272_pio_advance(struct net2272_ep *ep)
-{
- struct net2272_request *req;
-
- if (unlikely(list_empty(&ep->queue)))
- return;
-
- req = list_entry(ep->queue.next, struct net2272_request, queue);
- (ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req);
-}
-
-/* returns 0 on success, else negative errno */
-static int
-net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf,
- unsigned len, unsigned dir)
-{
- dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n",
- ep, buf, len, dir);
-
- /* The NET2272 only supports a single dma channel */
- if (dev->dma_busy)
- return -EBUSY;
- /*
- * EP_TRANSFER (used to determine the number of bytes received
- * in an OUT transfer) is 24 bits wide; don't ask for more than that.
- */
- if ((dir == 1) && (len > 0x1000000))
- return -EINVAL;
-
- dev->dma_busy = 1;
-
- /* initialize platform's dma */
-#ifdef CONFIG_USB_PCI
- /* NET2272 addr, buffer addr, length, etc. */
- switch (dev->dev_id) {
- case PCI_DEVICE_ID_RDK1:
- /* Setup PLX 9054 DMA mode */
- writel((1 << LOCAL_BUS_WIDTH) |
- (1 << TA_READY_INPUT_ENABLE) |
- (0 << LOCAL_BURST_ENABLE) |
- (1 << DONE_INTERRUPT_ENABLE) |
- (1 << LOCAL_ADDRESSING_MODE) |
- (1 << DEMAND_MODE) |
- (1 << DMA_EOT_ENABLE) |
- (1 << FAST_SLOW_TERMINATE_MODE_SELECT) |
- (1 << DMA_CHANNEL_INTERRUPT_SELECT),
- dev->rdk1.plx9054_base_addr + DMAMODE0);
-
- writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0);
- writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0);
- writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0);
- writel((dir << DIRECTION_OF_TRANSFER) |
- (1 << INTERRUPT_AFTER_TERMINAL_COUNT),
- dev->rdk1.plx9054_base_addr + DMADPR0);
- writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) |
- readl(dev->rdk1.plx9054_base_addr + INTCSR),
- dev->rdk1.plx9054_base_addr + INTCSR);
-
- break;
- }
-#endif
-
- net2272_write(dev, DMAREQ,
- (0 << DMA_BUFFER_VALID) |
- (1 << DMA_REQUEST_ENABLE) |
- (1 << DMA_CONTROL_DACK) |
- (dev->dma_eot_polarity << EOT_POLARITY) |
- (dev->dma_dack_polarity << DACK_POLARITY) |
- (dev->dma_dreq_polarity << DREQ_POLARITY) |
- ((ep >> 1) << DMA_ENDPOINT_SELECT));
-
- (void) net2272_read(dev, SCRATCH);
-
- return 0;
-}
-
-static void
-net2272_start_dma(struct net2272 *dev)
-{
- /* start platform's dma controller */
-#ifdef CONFIG_USB_PCI
- switch (dev->dev_id) {
- case PCI_DEVICE_ID_RDK1:
- writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START),
- dev->rdk1.plx9054_base_addr + DMACSR0);
- break;
- }
-#endif
-}
-
-/* returns 0 on success, else negative errno */
-static int
-net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req)
-{
- unsigned size;
- u8 tmp;
-
- if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma)
- return -EINVAL;
-
- /* don't use dma for odd-length transfers
- * otherwise, we'd need to deal with the last byte with pio
- */
- if (req->req.length & 1)
- return -EINVAL;
-
- dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n",
- ep->ep.name, req, (unsigned long long) req->req.dma);
-
- net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
-
- /* The NET2272 can only use DMA on one endpoint at a time */
- if (ep->dev->dma_busy)
- return -EBUSY;
-
- /* Make sure we only DMA an even number of bytes (we'll use
- * pio to complete the transfer)
- */
- size = req->req.length;
- size &= ~1;
-
- /* device-to-host transfer */
- if (ep->is_in) {
- /* initialize platform's dma controller */
- if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0))
- /* unable to obtain DMA channel; return error and use pio mode */
- return -EBUSY;
- req->req.actual += size;
-
- /* host-to-device transfer */
- } else {
- tmp = net2272_ep_read(ep, EP_STAT0);
-
- /* initialize platform's dma controller */
- if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1))
- /* unable to obtain DMA channel; return error and use pio mode */
- return -EBUSY;
-
- if (!(tmp & (1 << BUFFER_EMPTY)))
- ep->not_empty = 1;
- else
- ep->not_empty = 0;
-
-
- /* allow the endpoint's buffer to fill */
- net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
-
- /* this transfer completed and data's already in the fifo
- * return error so pio gets used.
- */
- if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
-
- /* deassert dreq */
- net2272_write(ep->dev, DMAREQ,
- (0 << DMA_BUFFER_VALID) |
- (0 << DMA_REQUEST_ENABLE) |
- (1 << DMA_CONTROL_DACK) |
- (ep->dev->dma_eot_polarity << EOT_POLARITY) |
- (ep->dev->dma_dack_polarity << DACK_POLARITY) |
- (ep->dev->dma_dreq_polarity << DREQ_POLARITY) |
- ((ep->num >> 1) << DMA_ENDPOINT_SELECT));
-
- return -EBUSY;
- }
- }
-
- /* Don't use per-packet interrupts: use dma interrupts only */
- net2272_ep_write(ep, EP_IRQENB, 0);
-
- net2272_start_dma(ep->dev);
-
- return 0;
-}
-
-static void net2272_cancel_dma(struct net2272 *dev)
-{
-#ifdef CONFIG_USB_PCI
- switch (dev->dev_id) {
- case PCI_DEVICE_ID_RDK1:
- writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0);
- writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0);
- while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) &
- (1 << CHANNEL_DONE)))
- continue; /* wait for dma to stabalize */
-
- /* dma abort generates an interrupt */
- writeb(1 << CHANNEL_CLEAR_INTERRUPT,
- dev->rdk1.plx9054_base_addr + DMACSR0);
- break;
- }
-#endif
-
- dev->dma_busy = 0;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static int
-net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
-{
- struct net2272_request *req;
- struct net2272_ep *ep;
- struct net2272 *dev;
- unsigned long flags;
- int status = -1;
- u8 s;
-
- req = container_of(_req, struct net2272_request, req);
- if (!_req || !_req->complete || !_req->buf
- || !list_empty(&req->queue))
- return -EINVAL;
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || (!ep->desc && ep->num != 0))
- return -EINVAL;
- dev = ep->dev;
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- /* set up dma mapping in case the caller didn't */
- if (use_dma && ep->dma) {
- status = usb_gadget_map_request(&dev->gadget, _req,
- ep->is_in);
- if (status)
- return status;
- }
-
- dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n",
- _ep->name, _req, _req->length, _req->buf,
- (unsigned long long) _req->dma, _req->zero ? "zero" : "!zero");
-
- spin_lock_irqsave(&dev->lock, flags);
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
-
- /* kickstart this i/o queue? */
- if (list_empty(&ep->queue) && !ep->stopped) {
- /* maybe there's no control data, just status ack */
- if (ep->num == 0 && _req->length == 0) {
- net2272_done(ep, req, 0);
- dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name);
- goto done;
- }
-
- /* Return zlp, don't let it block subsequent packets */
- s = net2272_ep_read(ep, EP_STAT0);
- if (s & (1 << BUFFER_EMPTY)) {
- /* Buffer is empty check for a blocking zlp, handle it */
- if ((s & (1 << NAK_OUT_PACKETS)) &&
- net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) {
- dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n");
- /*
- * Request is going to terminate with a short packet ...
- * hope the client is ready for it!
- */
- status = net2272_read_fifo(ep, req);
- /* clear short packet naking */
- net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS));
- goto done;
- }
- }
-
- /* try dma first */
- status = net2272_kick_dma(ep, req);
-
- if (status < 0) {
- /* dma failed (most likely in use by another endpoint)
- * fallback to pio
- */
- status = 0;
-
- if (ep->is_in)
- status = net2272_write_fifo(ep, req);
- else {
- s = net2272_ep_read(ep, EP_STAT0);
- if ((s & (1 << BUFFER_EMPTY)) == 0)
- status = net2272_read_fifo(ep, req);
- }
-
- if (unlikely(status != 0)) {
- if (status > 0)
- status = 0;
- req = NULL;
- }
- }
- }
- if (likely(req))
- list_add_tail(&req->queue, &ep->queue);
-
- if (likely(!list_empty(&ep->queue)))
- net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
- done:
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
-}
-
-/* dequeue ALL requests */
-static void
-net2272_dequeue_all(struct net2272_ep *ep)
-{
- struct net2272_request *req;
-
- /* called with spinlock held */
- ep->stopped = 1;
-
- while (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct net2272_request,
- queue);
- net2272_done(ep, req, -ESHUTDOWN);
- }
-}
-
-/* dequeue JUST ONE request */
-static int
-net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct net2272_ep *ep;
- struct net2272_request *req = NULL, *iter;
- unsigned long flags;
- int stopped;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || (!ep->desc && ep->num != 0) || !_req)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->dev->lock, flags);
- stopped = ep->stopped;
- ep->stopped = 1;
-
- /* make sure it's still queued on this endpoint */
- list_for_each_entry(iter, &ep->queue, queue) {
- if (&iter->req != _req)
- continue;
- req = iter;
- break;
- }
- if (!req) {
- ep->stopped = stopped;
- spin_unlock_irqrestore(&ep->dev->lock, flags);
- return -EINVAL;
- }
-
- /* queue head may be partially complete */
- if (ep->queue.next == &req->queue) {
- dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name);
- net2272_done(ep, req, -ECONNRESET);
- }
- ep->stopped = stopped;
-
- spin_unlock_irqrestore(&ep->dev->lock, flags);
- return 0;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static int
-net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
-{
- struct net2272_ep *ep;
- unsigned long flags;
- int ret = 0;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || (!ep->desc && ep->num != 0))
- return -EINVAL;
- if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
- if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc))
- return -EINVAL;
-
- spin_lock_irqsave(&ep->dev->lock, flags);
- if (!list_empty(&ep->queue))
- ret = -EAGAIN;
- else if (ep->is_in && value && net2272_fifo_status(_ep) != 0)
- ret = -EAGAIN;
- else {
- dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name,
- value ? "set" : "clear",
- wedged ? "wedge" : "halt");
- /* set/clear */
- if (value) {
- if (ep->num == 0)
- ep->dev->protocol_stall = 1;
- else
- set_halt(ep);
- if (wedged)
- ep->wedged = 1;
- } else {
- clear_halt(ep);
- ep->wedged = 0;
- }
- }
- spin_unlock_irqrestore(&ep->dev->lock, flags);
-
- return ret;
-}
-
-static int
-net2272_set_halt(struct usb_ep *_ep, int value)
-{
- return net2272_set_halt_and_wedge(_ep, value, 0);
-}
-
-static int
-net2272_set_wedge(struct usb_ep *_ep)
-{
- if (!_ep || _ep->name == ep0name)
- return -EINVAL;
- return net2272_set_halt_and_wedge(_ep, 1, 1);
-}
-
-static int
-net2272_fifo_status(struct usb_ep *_ep)
-{
- struct net2272_ep *ep;
- u16 avail;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || (!ep->desc && ep->num != 0))
- return -ENODEV;
- if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- avail = net2272_ep_read(ep, EP_AVAIL1) << 8;
- avail |= net2272_ep_read(ep, EP_AVAIL0);
- if (avail > ep->fifo_size)
- return -EOVERFLOW;
- if (ep->is_in)
- avail = ep->fifo_size - avail;
- return avail;
-}
-
-static void
-net2272_fifo_flush(struct usb_ep *_ep)
-{
- struct net2272_ep *ep;
-
- ep = container_of(_ep, struct net2272_ep, ep);
- if (!_ep || (!ep->desc && ep->num != 0))
- return;
- if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
- return;
-
- net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
-}
-
-static const struct usb_ep_ops net2272_ep_ops = {
- .enable = net2272_enable,
- .disable = net2272_disable,
-
- .alloc_request = net2272_alloc_request,
- .free_request = net2272_free_request,
-
- .queue = net2272_queue,
- .dequeue = net2272_dequeue,
-
- .set_halt = net2272_set_halt,
- .set_wedge = net2272_set_wedge,
- .fifo_status = net2272_fifo_status,
- .fifo_flush = net2272_fifo_flush,
-};
-
-/*---------------------------------------------------------------------------*/
-
-static int
-net2272_get_frame(struct usb_gadget *_gadget)
-{
- struct net2272 *dev;
- unsigned long flags;
- u16 ret;
-
- if (!_gadget)
- return -ENODEV;
- dev = container_of(_gadget, struct net2272, gadget);
- spin_lock_irqsave(&dev->lock, flags);
-
- ret = net2272_read(dev, FRAME1) << 8;
- ret |= net2272_read(dev, FRAME0);
-
- spin_unlock_irqrestore(&dev->lock, flags);
- return ret;
-}
-
-static int
-net2272_wakeup(struct usb_gadget *_gadget)
-{
- struct net2272 *dev;
- u8 tmp;
- unsigned long flags;
-
- if (!_gadget)
- return 0;
- dev = container_of(_gadget, struct net2272, gadget);
-
- spin_lock_irqsave(&dev->lock, flags);
- tmp = net2272_read(dev, USBCTL0);
- if (tmp & (1 << IO_WAKEUP_ENABLE))
- net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME));
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
-}
-
-static int
-net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
-{
- if (!_gadget)
- return -ENODEV;
-
- _gadget->is_selfpowered = (value != 0);
-
- return 0;
-}
-
-static int
-net2272_pullup(struct usb_gadget *_gadget, int is_on)
-{
- struct net2272 *dev;
- u8 tmp;
- unsigned long flags;
-
- if (!_gadget)
- return -ENODEV;
- dev = container_of(_gadget, struct net2272, gadget);
-
- spin_lock_irqsave(&dev->lock, flags);
- tmp = net2272_read(dev, USBCTL0);
- dev->softconnect = (is_on != 0);
- if (is_on)
- tmp |= (1 << USB_DETECT_ENABLE);
- else
- tmp &= ~(1 << USB_DETECT_ENABLE);
- net2272_write(dev, USBCTL0, tmp);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
-}
-
-static int net2272_start(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver);
-static int net2272_stop(struct usb_gadget *_gadget);
-static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable);
-
-static const struct usb_gadget_ops net2272_ops = {
- .get_frame = net2272_get_frame,
- .wakeup = net2272_wakeup,
- .set_selfpowered = net2272_set_selfpowered,
- .pullup = net2272_pullup,
- .udc_start = net2272_start,
- .udc_stop = net2272_stop,
- .udc_async_callbacks = net2272_async_callbacks,
-};
-
-/*---------------------------------------------------------------------------*/
-
-static ssize_t
-registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
-{
- struct net2272 *dev;
- char *next;
- unsigned size, t;
- unsigned long flags;
- u8 t1, t2;
- int i;
- const char *s;
-
- dev = dev_get_drvdata(_dev);
- next = buf;
- size = PAGE_SIZE;
- spin_lock_irqsave(&dev->lock, flags);
-
- /* Main Control Registers */
- t = scnprintf(next, size, "%s version %s,"
- "chiprev %02x, locctl %02x\n"
- "irqenb0 %02x irqenb1 %02x "
- "irqstat0 %02x irqstat1 %02x\n",
- driver_name, driver_vers, dev->chiprev,
- net2272_read(dev, LOCCTL),
- net2272_read(dev, IRQENB0),
- net2272_read(dev, IRQENB1),
- net2272_read(dev, IRQSTAT0),
- net2272_read(dev, IRQSTAT1));
- size -= t;
- next += t;
-
- /* DMA */
- t1 = net2272_read(dev, DMAREQ);
- t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n",
- t1, ep_name[(t1 & 0x01) + 1],
- t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "",
- t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "",
- t1 & (1 << DMA_REQUEST) ? "req " : "",
- t1 & (1 << DMA_BUFFER_VALID) ? "valid " : "");
- size -= t;
- next += t;
-
- /* USB Control Registers */
- t1 = net2272_read(dev, USBCTL1);
- if (t1 & (1 << VBUS_PIN)) {
- if (t1 & (1 << USB_HIGH_SPEED))
- s = "high speed";
- else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
- s = "powered";
- else
- s = "full speed";
- } else
- s = "not attached";
- t = scnprintf(next, size,
- "usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n",
- net2272_read(dev, USBCTL0), t1,
- net2272_read(dev, OURADDR), s);
- size -= t;
- next += t;
-
- /* Endpoint Registers */
- for (i = 0; i < 4; ++i) {
- struct net2272_ep *ep;
-
- ep = &dev->ep[i];
- if (i && !ep->desc)
- continue;
-
- t1 = net2272_ep_read(ep, EP_CFG);
- t2 = net2272_ep_read(ep, EP_RSPSET);
- t = scnprintf(next, size,
- "\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s"
- "irqenb %02x\n",
- ep->ep.name, t1, t2,
- (t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "",
- (t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "",
- (t2 & (1 << AUTOVALIDATE)) ? "auto " : "",
- (t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "",
- (t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "",
- (t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "",
- (t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ",
- (t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "",
- net2272_ep_read(ep, EP_IRQENB));
- size -= t;
- next += t;
-
- t = scnprintf(next, size,
- "\tstat0 %02x stat1 %02x avail %04x "
- "(ep%d%s-%s)%s\n",
- net2272_ep_read(ep, EP_STAT0),
- net2272_ep_read(ep, EP_STAT1),
- (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0),
- t1 & 0x0f,
- ep->is_in ? "in" : "out",
- type_string(t1 >> 5),
- ep->stopped ? "*" : "");
- size -= t;
- next += t;
-
- t = scnprintf(next, size,
- "\tep_transfer %06x\n",
- ((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) |
- ((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) |
- ((net2272_ep_read(ep, EP_TRANSFER0) & 0xff)));
- size -= t;
- next += t;
-
- t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03;
- t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03;
- t = scnprintf(next, size,
- "\tbuf-a %s buf-b %s\n",
- buf_state_string(t1),
- buf_state_string(t2));
- size -= t;
- next += t;
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return PAGE_SIZE - size;
-}
-static DEVICE_ATTR_RO(registers);
-
-/*---------------------------------------------------------------------------*/
-
-static void
-net2272_set_fifo_mode(struct net2272 *dev, int mode)
-{
- u8 tmp;
-
- tmp = net2272_read(dev, LOCCTL) & 0x3f;
- tmp |= (mode << 6);
- net2272_write(dev, LOCCTL, tmp);
-
- INIT_LIST_HEAD(&dev->gadget.ep_list);
-
- /* always ep-a, ep-c ... maybe not ep-b */
- list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list);
-
- switch (mode) {
- case 0:
- list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
- dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512;
- break;
- case 1:
- list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
- dev->ep[1].fifo_size = 1024;
- dev->ep[2].fifo_size = 512;
- break;
- case 2:
- list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
- dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024;
- break;
- case 3:
- dev->ep[1].fifo_size = 1024;
- break;
- }
-
- /* ep-c is always 2 512 byte buffers */
- list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list);
- dev->ep[3].fifo_size = 512;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void
-net2272_usb_reset(struct net2272 *dev)
-{
- dev->gadget.speed = USB_SPEED_UNKNOWN;
-
- net2272_cancel_dma(dev);
-
- net2272_write(dev, IRQENB0, 0);
- net2272_write(dev, IRQENB1, 0);
-
- /* clear irq state */
- net2272_write(dev, IRQSTAT0, 0xff);
- net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT));
-
- net2272_write(dev, DMAREQ,
- (0 << DMA_BUFFER_VALID) |
- (0 << DMA_REQUEST_ENABLE) |
- (1 << DMA_CONTROL_DACK) |
- (dev->dma_eot_polarity << EOT_POLARITY) |
- (dev->dma_dack_polarity << DACK_POLARITY) |
- (dev->dma_dreq_polarity << DREQ_POLARITY) |
- ((dma_ep >> 1) << DMA_ENDPOINT_SELECT));
-
- net2272_cancel_dma(dev);
- net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0);
-
- /* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping
- * note that the higher level gadget drivers are expected to convert data to little endian.
- * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here
- */
- net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH));
- net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE));
-}
-
-static void
-net2272_usb_reinit(struct net2272 *dev)
-{
- int i;
-
- /* basic endpoint init */
- for (i = 0; i < 4; ++i) {
- struct net2272_ep *ep = &dev->ep[i];
-
- ep->ep.name = ep_name[i];
- ep->dev = dev;
- ep->num = i;
- ep->not_empty = 0;
-
- if (use_dma && ep->num == dma_ep)
- ep->dma = 1;
-
- if (i > 0 && i <= 3)
- ep->fifo_size = 512;
- else
- ep->fifo_size = 64;
- net2272_ep_reset(ep);
-
- if (i == 0) {
- ep->ep.caps.type_control = true;
- } else {
- ep->ep.caps.type_iso = true;
- ep->ep.caps.type_bulk = true;
- ep->ep.caps.type_int = true;
- }
-
- ep->ep.caps.dir_in = true;
- ep->ep.caps.dir_out = true;
- }
- usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64);
-
- dev->gadget.ep0 = &dev->ep[0].ep;
- dev->ep[0].stopped = 0;
- INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
-}
-
-static void
-net2272_ep0_start(struct net2272 *dev)
-{
- struct net2272_ep *ep0 = &dev->ep[0];
-
- net2272_ep_write(ep0, EP_RSPSET,
- (1 << NAK_OUT_PACKETS_MODE) |
- (1 << ALT_NAK_OUT_PACKETS));
- net2272_ep_write(ep0, EP_RSPCLR,
- (1 << HIDE_STATUS_PHASE) |
- (1 << CONTROL_STATUS_PHASE_HANDSHAKE));
- net2272_write(dev, USBCTL0,
- (dev->softconnect << USB_DETECT_ENABLE) |
- (1 << USB_ROOT_PORT_WAKEUP_ENABLE) |
- (1 << IO_WAKEUP_ENABLE));
- net2272_write(dev, IRQENB0,
- (1 << SETUP_PACKET_INTERRUPT_ENABLE) |
- (1 << ENDPOINT_0_INTERRUPT_ENABLE) |
- (1 << DMA_DONE_INTERRUPT_ENABLE));
- net2272_write(dev, IRQENB1,
- (1 << VBUS_INTERRUPT_ENABLE) |
- (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) |
- (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE));
-}
-
-/* when a driver is successfully registered, it will receive
- * control requests including set_configuration(), which enables
- * non-control requests. then usb traffic follows until a
- * disconnect is reported. then a host may connect again, or
- * the driver might get unbound.
- */
-static int net2272_start(struct usb_gadget *_gadget,
- struct usb_gadget_driver *driver)
-{
- struct net2272 *dev;
- unsigned i;
-
- if (!driver || !driver->setup ||
- driver->max_speed != USB_SPEED_HIGH)
- return -EINVAL;
-
- dev = container_of(_gadget, struct net2272, gadget);
-
- for (i = 0; i < 4; ++i)
- dev->ep[i].irqs = 0;
- /* hook up the driver ... */
- dev->softconnect = 1;
- dev->driver = driver;
-
- /* ... then enable host detection and ep0; and we're ready
- * for set_configuration as well as eventual disconnect.
- */
- net2272_ep0_start(dev);
-
- return 0;
-}
-
-static void
-stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
-{
- int i;
-
- /* don't disconnect if it's not connected */
- if (dev->gadget.speed == USB_SPEED_UNKNOWN)
- driver = NULL;
-
- /* stop hardware; prevent new request submissions;
- * and kill any outstanding requests.
- */
- net2272_usb_reset(dev);
- for (i = 0; i < 4; ++i)
- net2272_dequeue_all(&dev->ep[i]);
-
- /* report disconnect; the driver is already quiesced */
- if (dev->async_callbacks && driver) {
- spin_unlock(&dev->lock);
- driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
- }
-
- net2272_usb_reinit(dev);
-}
-
-static int net2272_stop(struct usb_gadget *_gadget)
-{
- struct net2272 *dev;
- unsigned long flags;
-
- dev = container_of(_gadget, struct net2272, gadget);
-
- spin_lock_irqsave(&dev->lock, flags);
- stop_activity(dev, NULL);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev->driver = NULL;
-
- return 0;
-}
-
-static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable)
-{
- struct net2272 *dev = container_of(_gadget, struct net2272, gadget);
-
- spin_lock_irq(&dev->lock);
- dev->async_callbacks = enable;
- spin_unlock_irq(&dev->lock);
-}
-
-/*---------------------------------------------------------------------------*/
-/* handle ep-a/ep-b dma completions */
-static void
-net2272_handle_dma(struct net2272_ep *ep)
-{
- struct net2272_request *req;
- unsigned len;
- int status;
-
- if (!list_empty(&ep->queue))
- req = list_entry(ep->queue.next,
- struct net2272_request, queue);
- else
- req = NULL;
-
- dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req);
-
- /* Ensure DREQ is de-asserted */
- net2272_write(ep->dev, DMAREQ,
- (0 << DMA_BUFFER_VALID)
- | (0 << DMA_REQUEST_ENABLE)
- | (1 << DMA_CONTROL_DACK)
- | (ep->dev->dma_eot_polarity << EOT_POLARITY)
- | (ep->dev->dma_dack_polarity << DACK_POLARITY)
- | (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
- | (ep->dma << DMA_ENDPOINT_SELECT));
-
- ep->dev->dma_busy = 0;
-
- net2272_ep_write(ep, EP_IRQENB,
- (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
- | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
- | net2272_ep_read(ep, EP_IRQENB));
-
- /* device-to-host transfer completed */
- if (ep->is_in) {
- /* validate a short packet or zlp if necessary */
- if ((req->req.length % ep->ep.maxpacket != 0) ||
- req->req.zero)
- set_fifo_bytecount(ep, 0);
-
- net2272_done(ep, req, 0);
- if (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct net2272_request, queue);
- status = net2272_kick_dma(ep, req);
- if (status < 0)
- net2272_pio_advance(ep);
- }
-
- /* host-to-device transfer completed */
- } else {
- /* terminated with a short packet? */
- if (net2272_read(ep->dev, IRQSTAT0) &
- (1 << DMA_DONE_INTERRUPT)) {
- /* abort system dma */
- net2272_cancel_dma(ep->dev);
- }
-
- /* EP_TRANSFER will contain the number of bytes
- * actually received.
- * NOTE: There is no overflow detection on EP_TRANSFER:
- * We can't deal with transfers larger than 2^24 bytes!
- */
- len = (net2272_ep_read(ep, EP_TRANSFER2) << 16)
- | (net2272_ep_read(ep, EP_TRANSFER1) << 8)
- | (net2272_ep_read(ep, EP_TRANSFER0));
-
- if (ep->not_empty)
- len += 4;
-
- req->req.actual += len;
-
- /* get any remaining data */
- net2272_pio_advance(ep);
- }
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void
-net2272_handle_ep(struct net2272_ep *ep)
-{
- struct net2272_request *req;
- u8 stat0, stat1;
-
- if (!list_empty(&ep->queue))
- req = list_entry(ep->queue.next,
- struct net2272_request, queue);
- else
- req = NULL;
-
- /* ack all, and handle what we care about */
- stat0 = net2272_ep_read(ep, EP_STAT0);
- stat1 = net2272_ep_read(ep, EP_STAT1);
- ep->irqs++;
-
- dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
- ep->ep.name, stat0, stat1, req ? &req->req : NULL);
-
- net2272_ep_write(ep, EP_STAT0, stat0 &
- ~((1 << NAK_OUT_PACKETS)
- | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)));
- net2272_ep_write(ep, EP_STAT1, stat1);
-
- /* data packet(s) received (in the fifo, OUT)
- * direction must be validated, otherwise control read status phase
- * could be interpreted as a valid packet
- */
- if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT)))
- net2272_pio_advance(ep);
- /* data packet(s) transmitted (IN) */
- else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
- net2272_pio_advance(ep);
-}
-
-static struct net2272_ep *
-net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex)
-{
- struct net2272_ep *ep;
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
- return &dev->ep[0];
-
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- u8 bEndpointAddress;
-
- if (!ep->desc)
- continue;
- bEndpointAddress = ep->desc->bEndpointAddress;
- if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
- continue;
- if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))
- return ep;
- }
- return NULL;
-}
-
-/*
- * USB Test Packet:
- * JKJKJKJK * 9
- * JJKKJJKK * 8
- * JJJJKKKK * 8
- * JJJJJJJKKKKKKK * 8
- * JJJJJJJK * 8
- * {JKKKKKKK * 10}, JK
- */
-static const u8 net2272_test_packet[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
- 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
- 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
- 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E
-};
-
-static void
-net2272_set_test_mode(struct net2272 *dev, int mode)
-{
- int i;
-
- /* Disable all net2272 interrupts:
- * Nothing but a power cycle should stop the test.
- */
- net2272_write(dev, IRQENB0, 0x00);
- net2272_write(dev, IRQENB1, 0x00);
-
- /* Force tranceiver to high-speed */
- net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED);
-
- net2272_write(dev, PAGESEL, 0);
- net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT);
- net2272_write(dev, EP_RSPCLR,
- (1 << CONTROL_STATUS_PHASE_HANDSHAKE)
- | (1 << HIDE_STATUS_PHASE));
- net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION);
- net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH);
-
- /* wait for status phase to complete */
- while (!(net2272_read(dev, EP_STAT0) &
- (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)))
- ;
-
- /* Enable test mode */
- net2272_write(dev, USBTEST, mode);
-
- /* load test packet */
- if (mode == USB_TEST_PACKET) {
- /* switch to 8 bit mode */
- net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) &
- ~(1 << DATA_WIDTH));
-
- for (i = 0; i < sizeof(net2272_test_packet); ++i)
- net2272_write(dev, EP_DATA, net2272_test_packet[i]);
-
- /* Validate test packet */
- net2272_write(dev, EP_TRANSFER0, 0);
- }
-}
-
-static void
-net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
-{
- struct net2272_ep *ep;
- u8 num, scratch;
-
- /* starting a control request? */
- if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) {
- union {
- u8 raw[8];
- struct usb_ctrlrequest r;
- } u;
- int tmp = 0;
- struct net2272_request *req;
-
- if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
- if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED))
- dev->gadget.speed = USB_SPEED_HIGH;
- else
- dev->gadget.speed = USB_SPEED_FULL;
- dev_dbg(dev->dev, "%s\n",
- usb_speed_string(dev->gadget.speed));
- }
-
- ep = &dev->ep[0];
- ep->irqs++;
-
- /* make sure any leftover interrupt state is cleared */
- stat &= ~(1 << ENDPOINT_0_INTERRUPT);
- while (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct net2272_request, queue);
- net2272_done(ep, req,
- (req->req.actual == req->req.length) ? 0 : -EPROTO);
- }
- ep->stopped = 0;
- dev->protocol_stall = 0;
- net2272_ep_write(ep, EP_STAT0,
- (1 << DATA_IN_TOKEN_INTERRUPT)
- | (1 << DATA_OUT_TOKEN_INTERRUPT)
- | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
- | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
- | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT));
- net2272_ep_write(ep, EP_STAT1,
- (1 << TIMEOUT)
- | (1 << USB_OUT_ACK_SENT)
- | (1 << USB_OUT_NAK_SENT)
- | (1 << USB_IN_ACK_RCVD)
- | (1 << USB_IN_NAK_SENT)
- | (1 << USB_STALL_SENT)
- | (1 << LOCAL_OUT_ZLP));
-
- /*
- * Ensure Control Read pre-validation setting is beyond maximum size
- * - Control Writes can leave non-zero values in EP_TRANSFER. If
- * an EP0 transfer following the Control Write is a Control Read,
- * the NET2272 sees the non-zero EP_TRANSFER as an unexpected
- * pre-validation count.
- * - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures
- * the pre-validation count cannot cause an unexpected validatation
- */
- net2272_write(dev, PAGESEL, 0);
- net2272_write(dev, EP_TRANSFER2, 0xff);
- net2272_write(dev, EP_TRANSFER1, 0xff);
- net2272_write(dev, EP_TRANSFER0, 0xff);
-
- u.raw[0] = net2272_read(dev, SETUP0);
- u.raw[1] = net2272_read(dev, SETUP1);
- u.raw[2] = net2272_read(dev, SETUP2);
- u.raw[3] = net2272_read(dev, SETUP3);
- u.raw[4] = net2272_read(dev, SETUP4);
- u.raw[5] = net2272_read(dev, SETUP5);
- u.raw[6] = net2272_read(dev, SETUP6);
- u.raw[7] = net2272_read(dev, SETUP7);
- /*
- * If you have a big endian cpu make sure le16_to_cpus
- * performs the proper byte swapping here...
- */
- le16_to_cpus(&u.r.wValue);
- le16_to_cpus(&u.r.wIndex);
- le16_to_cpus(&u.r.wLength);
-
- /* ack the irq */
- net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT);
- stat ^= (1 << SETUP_PACKET_INTERRUPT);
-
- /* watch control traffic at the token level, and force
- * synchronization before letting the status phase happen.
- */
- ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
- if (ep->is_in) {
- scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
- | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE)
- | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE);
- stop_out_naking(ep);
- } else
- scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
- | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE)
- | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE);
- net2272_ep_write(ep, EP_IRQENB, scratch);
-
- if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
- goto delegate;
- switch (u.r.bRequest) {
- case USB_REQ_GET_STATUS: {
- struct net2272_ep *e;
- u16 status = 0;
-
- switch (u.r.bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_ENDPOINT:
- e = net2272_get_ep_by_addr(dev, u.r.wIndex);
- if (!e || u.r.wLength > 2)
- goto do_stall;
- if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT))
- status = cpu_to_le16(1);
- else
- status = cpu_to_le16(0);
-
- /* don't bother with a request object! */
- net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
- writew(status, net2272_reg_addr(dev, EP_DATA));
- set_fifo_bytecount(&dev->ep[0], 0);
- allow_status(ep);
- dev_vdbg(dev->dev, "%s stat %02x\n",
- ep->ep.name, status);
- goto next_endpoints;
- case USB_RECIP_DEVICE:
- if (u.r.wLength > 2)
- goto do_stall;
- if (dev->gadget.is_selfpowered)
- status = (1 << USB_DEVICE_SELF_POWERED);
-
- /* don't bother with a request object! */
- net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
- writew(status, net2272_reg_addr(dev, EP_DATA));
- set_fifo_bytecount(&dev->ep[0], 0);
- allow_status(ep);
- dev_vdbg(dev->dev, "device stat %02x\n", status);
- goto next_endpoints;
- case USB_RECIP_INTERFACE:
- if (u.r.wLength > 2)
- goto do_stall;
-
- /* don't bother with a request object! */
- net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
- writew(status, net2272_reg_addr(dev, EP_DATA));
- set_fifo_bytecount(&dev->ep[0], 0);
- allow_status(ep);
- dev_vdbg(dev->dev, "interface status %02x\n", status);
- goto next_endpoints;
- }
-
- break;
- }
- case USB_REQ_CLEAR_FEATURE: {
- struct net2272_ep *e;
-
- if (u.r.bRequestType != USB_RECIP_ENDPOINT)
- goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT ||
- u.r.wLength != 0)
- goto do_stall;
- e = net2272_get_ep_by_addr(dev, u.r.wIndex);
- if (!e)
- goto do_stall;
- if (e->wedged) {
- dev_vdbg(dev->dev, "%s wedged, halt not cleared\n",
- ep->ep.name);
- } else {
- dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name);
- clear_halt(e);
- }
- allow_status(ep);
- goto next_endpoints;
- }
- case USB_REQ_SET_FEATURE: {
- struct net2272_ep *e;
-
- if (u.r.bRequestType == USB_RECIP_DEVICE) {
- if (u.r.wIndex != NORMAL_OPERATION)
- net2272_set_test_mode(dev, (u.r.wIndex >> 8));
- allow_status(ep);
- dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex);
- goto next_endpoints;
- } else if (u.r.bRequestType != USB_RECIP_ENDPOINT)
- goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT ||
- u.r.wLength != 0)
- goto do_stall;
- e = net2272_get_ep_by_addr(dev, u.r.wIndex);
- if (!e)
- goto do_stall;
- set_halt(e);
- allow_status(ep);
- dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name);
- goto next_endpoints;
- }
- case USB_REQ_SET_ADDRESS: {
- net2272_write(dev, OURADDR, u.r.wValue & 0xff);
- allow_status(ep);
- break;
- }
- default:
- delegate:
- dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x "
- "ep_cfg %08x\n",
- u.r.bRequestType, u.r.bRequest,
- u.r.wValue, u.r.wIndex,
- net2272_ep_read(ep, EP_CFG));
- if (dev->async_callbacks) {
- spin_unlock(&dev->lock);
- tmp = dev->driver->setup(&dev->gadget, &u.r);
- spin_lock(&dev->lock);
- }
- }
-
- /* stall ep0 on error */
- if (tmp < 0) {
- do_stall:
- dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n",
- u.r.bRequestType, u.r.bRequest, tmp);
- dev->protocol_stall = 1;
- }
- /* endpoint dma irq? */
- } else if (stat & (1 << DMA_DONE_INTERRUPT)) {
- net2272_cancel_dma(dev);
- net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT);
- stat &= ~(1 << DMA_DONE_INTERRUPT);
- num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT))
- ? 2 : 1;
-
- ep = &dev->ep[num];
- net2272_handle_dma(ep);
- }
-
- next_endpoints:
- /* endpoint data irq? */
- scratch = stat & 0x0f;
- stat &= ~0x0f;
- for (num = 0; scratch; num++) {
- u8 t;
-
- /* does this endpoint's FIFO and queue need tending? */
- t = 1 << num;
- if ((scratch & t) == 0)
- continue;
- scratch ^= t;
-
- ep = &dev->ep[num];
- net2272_handle_ep(ep);
- }
-
- /* some interrupts we can just ignore */
- stat &= ~(1 << SOF_INTERRUPT);
-
- if (stat)
- dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat);
-}
-
-static void
-net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
-{
- u8 tmp, mask;
-
- /* after disconnect there's nothing else to do! */
- tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
- mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED);
-
- if (stat & tmp) {
- bool reset = false;
- bool disconnect = false;
-
- /*
- * Ignore disconnects and resets if the speed hasn't been set.
- * VBUS can bounce and there's always an initial reset.
- */
- net2272_write(dev, IRQSTAT1, tmp);
- if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
- if ((stat & (1 << VBUS_INTERRUPT)) &&
- (net2272_read(dev, USBCTL1) &
- (1 << VBUS_PIN)) == 0) {
- disconnect = true;
- dev_dbg(dev->dev, "disconnect %s\n",
- dev->driver->driver.name);
- } else if ((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
- (net2272_read(dev, USBCTL1) & mask)
- == 0) {
- reset = true;
- dev_dbg(dev->dev, "reset %s\n",
- dev->driver->driver.name);
- }
-
- if (disconnect || reset) {
- stop_activity(dev, dev->driver);
- net2272_ep0_start(dev);
- if (dev->async_callbacks) {
- spin_unlock(&dev->lock);
- if (reset)
- usb_gadget_udc_reset(&dev->gadget, dev->driver);
- else
- (dev->driver->disconnect)(&dev->gadget);
- spin_lock(&dev->lock);
- }
- return;
- }
- }
- stat &= ~tmp;
-
- if (!stat)
- return;
- }
-
- tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
- if (stat & tmp) {
- net2272_write(dev, IRQSTAT1, tmp);
- if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
- if (dev->async_callbacks && dev->driver->suspend)
- dev->driver->suspend(&dev->gadget);
- if (!enable_suspend) {
- stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
- dev_dbg(dev->dev, "Suspend disabled, ignoring\n");
- }
- } else {
- if (dev->async_callbacks && dev->driver->resume)
- dev->driver->resume(&dev->gadget);
- }
- stat &= ~tmp;
- }
-
- /* clear any other status/irqs */
- if (stat)
- net2272_write(dev, IRQSTAT1, stat);
-
- /* some status we can just ignore */
- stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
- | (1 << SUSPEND_REQUEST_INTERRUPT)
- | (1 << RESUME_INTERRUPT));
- if (!stat)
- return;
- else
- dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat);
-}
-
-static irqreturn_t net2272_irq(int irq, void *_dev)
-{
- struct net2272 *dev = _dev;
-#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2)
- u32 intcsr;
-#endif
-#if defined(PLX_PCI_RDK)
- u8 dmareq;
-#endif
- spin_lock(&dev->lock);
-#if defined(PLX_PCI_RDK)
- intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR);
-
- if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) {
- writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE),
- dev->rdk1.plx9054_base_addr + INTCSR);
- net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1));
- net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0));
- intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR);
- writel(intcsr | (1 << PCI_INTERRUPT_ENABLE),
- dev->rdk1.plx9054_base_addr + INTCSR);
- }
- if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) {
- writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)),
- dev->rdk1.plx9054_base_addr + DMACSR0);
-
- dmareq = net2272_read(dev, DMAREQ);
- if (dmareq & 0x01)
- net2272_handle_dma(&dev->ep[2]);
- else
- net2272_handle_dma(&dev->ep[1]);
- }
-#endif
-#if defined(PLX_PCI_RDK2)
- /* see if PCI int for us by checking irqstat */
- intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT);
- if (!(intcsr & (1 << NET2272_PCI_IRQ))) {
- spin_unlock(&dev->lock);
- return IRQ_NONE;
- }
- /* check dma interrupts */
-#endif
- /* Platform/device interrupt handler */
-#if !defined(PLX_PCI_RDK)
- net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1));
- net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0));
-#endif
- spin_unlock(&dev->lock);
-
- return IRQ_HANDLED;
-}
-
-static int net2272_present(struct net2272 *dev)
-{
- /*
- * Quick test to see if CPU can communicate properly with the NET2272.
- * Verifies connection using writes and reads to write/read and
- * read-only registers.
- *
- * This routine is strongly recommended especially during early bring-up
- * of new hardware, however for designs that do not apply Power On System
- * Tests (POST) it may discarded (or perhaps minimized).
- */
- unsigned int ii;
- u8 val, refval;
-
- /* Verify NET2272 write/read SCRATCH register can write and read */
- refval = net2272_read(dev, SCRATCH);
- for (ii = 0; ii < 0x100; ii += 7) {
- net2272_write(dev, SCRATCH, ii);
- val = net2272_read(dev, SCRATCH);
- if (val != ii) {
- dev_dbg(dev->dev,
- "%s: write/read SCRATCH register test failed: "
- "wrote:0x%2.2x, read:0x%2.2x\n",
- __func__, ii, val);
- return -EINVAL;
- }
- }
- /* To be nice, we write the original SCRATCH value back: */
- net2272_write(dev, SCRATCH, refval);
-
- /* Verify NET2272 CHIPREV register is read-only: */
- refval = net2272_read(dev, CHIPREV_2272);
- for (ii = 0; ii < 0x100; ii += 7) {
- net2272_write(dev, CHIPREV_2272, ii);
- val = net2272_read(dev, CHIPREV_2272);
- if (val != refval) {
- dev_dbg(dev->dev,
- "%s: write/read CHIPREV register test failed: "
- "wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n",
- __func__, ii, val, refval);
- return -EINVAL;
- }
- }
-
- /*
- * Verify NET2272's "NET2270 legacy revision" register
- * - NET2272 has two revision registers. The NET2270 legacy revision
- * register should read the same value, regardless of the NET2272
- * silicon revision. The legacy register applies to NET2270
- * firmware being applied to the NET2272.
- */
- val = net2272_read(dev, CHIPREV_LEGACY);
- if (val != NET2270_LEGACY_REV) {
- /*
- * Unexpected legacy revision value
- * - Perhaps the chip is a NET2270?
- */
- dev_dbg(dev->dev,
- "%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n"
- " - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n",
- __func__, NET2270_LEGACY_REV, val);
- return -EINVAL;
- }
-
- /*
- * Verify NET2272 silicon revision
- * - This revision register is appropriate for the silicon version
- * of the NET2272
- */
- val = net2272_read(dev, CHIPREV_2272);
- switch (val) {
- case CHIPREV_NET2272_R1:
- /*
- * NET2272 Rev 1 has DMA related errata:
- * - Newer silicon (Rev 1A or better) required
- */
- dev_dbg(dev->dev,
- "%s: Rev 1 detected: newer silicon recommended for DMA support\n",
- __func__);
- break;
- case CHIPREV_NET2272_R1A:
- break;
- default:
- /* NET2272 silicon version *may* not work with this firmware */
- dev_dbg(dev->dev,
- "%s: unexpected silicon revision register value: "
- " CHIPREV_2272: 0x%2.2x\n",
- __func__, val);
- /*
- * Return Success, even though the chip rev is not an expected value
- * - Older, pre-built firmware can attempt to operate on newer silicon
- * - Often, new silicon is perfectly compatible
- */
- }
-
- /* Success: NET2272 checks out OK */
- return 0;
-}
-
-static void
-net2272_gadget_release(struct device *_dev)
-{
- struct net2272 *dev = container_of(_dev, struct net2272, gadget.dev);
-
- kfree(dev);
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void
-net2272_remove(struct net2272 *dev)
-{
- if (dev->added)
- usb_del_gadget(&dev->gadget);
- free_irq(dev->irq, dev);
- iounmap(dev->base_addr);
- device_remove_file(dev->dev, &dev_attr_registers);
-
- dev_info(dev->dev, "unbind\n");
-}
-
-static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
-{
- struct net2272 *ret;
-
- if (!irq) {
- dev_dbg(dev, "No IRQ!\n");
- return ERR_PTR(-ENODEV);
- }
-
- /* alloc, and start init */
- ret = kzalloc(sizeof(*ret), GFP_KERNEL);
- if (!ret)
- return ERR_PTR(-ENOMEM);
-
- spin_lock_init(&ret->lock);
- ret->irq = irq;
- ret->dev = dev;
- ret->gadget.ops = &net2272_ops;
- ret->gadget.max_speed = USB_SPEED_HIGH;
-
- /* the "gadget" abstracts/virtualizes the controller */
- ret->gadget.name = driver_name;
- usb_initialize_gadget(dev, &ret->gadget, net2272_gadget_release);
-
- return ret;
-}
-
-static int
-net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
-{
- int ret;
-
- /* See if there... */
- if (net2272_present(dev)) {
- dev_warn(dev->dev, "2272 not found!\n");
- ret = -ENODEV;
- goto err;
- }
-
- net2272_usb_reset(dev);
- net2272_usb_reinit(dev);
-
- ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev);
- if (ret) {
- dev_err(dev->dev, "request interrupt %i failed\n", dev->irq);
- goto err;
- }
-
- dev->chiprev = net2272_read(dev, CHIPREV_2272);
-
- /* done */
- dev_info(dev->dev, "%s\n", driver_desc);
- dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n",
- dev->irq, dev->base_addr, dev->chiprev,
- dma_mode_string());
- dev_info(dev->dev, "version: %s\n", driver_vers);
-
- ret = device_create_file(dev->dev, &dev_attr_registers);
- if (ret)
- goto err_irq;
-
- ret = usb_add_gadget(&dev->gadget);
- if (ret)
- goto err_add_udc;
- dev->added = 1;
-
- return 0;
-
-err_add_udc:
- device_remove_file(dev->dev, &dev_attr_registers);
- err_irq:
- free_irq(dev->irq, dev);
- err:
- return ret;
-}
-
-#ifdef CONFIG_USB_PCI
-
-/*
- * wrap this driver around the specified device, but
- * don't respond over USB until a gadget driver binds to us
- */
-
-static int
-net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev)
-{
- unsigned long resource, len, tmp;
- void __iomem *mem_mapped_addr[4];
- int ret, i;
-
- /*
- * BAR 0 holds PLX 9054 config registers
- * BAR 1 is i/o memory; unused here
- * BAR 2 holds EPLD config registers
- * BAR 3 holds NET2272 registers
- */
-
- /* Find and map all address spaces */
- for (i = 0; i < 4; ++i) {
- if (i == 1)
- continue; /* BAR1 unused */
-
- resource = pci_resource_start(pdev, i);
- len = pci_resource_len(pdev, i);
-
- if (!request_mem_region(resource, len, driver_name)) {
- dev_dbg(dev->dev, "controller already in use\n");
- ret = -EBUSY;
- goto err;
- }
-
- mem_mapped_addr[i] = ioremap(resource, len);
- if (mem_mapped_addr[i] == NULL) {
- release_mem_region(resource, len);
- dev_dbg(dev->dev, "can't map memory\n");
- ret = -EFAULT;
- goto err;
- }
- }
-
- dev->rdk1.plx9054_base_addr = mem_mapped_addr[0];
- dev->rdk1.epld_base_addr = mem_mapped_addr[2];
- dev->base_addr = mem_mapped_addr[3];
-
- /* Set PLX 9054 bus width (16 bits) */
- tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1);
- writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT,
- dev->rdk1.plx9054_base_addr + LBRD1);
-
- /* Enable PLX 9054 Interrupts */
- writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) |
- (1 << PCI_INTERRUPT_ENABLE) |
- (1 << LOCAL_INTERRUPT_INPUT_ENABLE),
- dev->rdk1.plx9054_base_addr + INTCSR);
-
- writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)),
- dev->rdk1.plx9054_base_addr + DMACSR0);
-
- /* reset */
- writeb((1 << EPLD_DMA_ENABLE) |
- (1 << DMA_CTL_DACK) |
- (1 << DMA_TIMEOUT_ENABLE) |
- (1 << USER) |
- (0 << MPX_MODE) |
- (1 << BUSWIDTH) |
- (1 << NET2272_RESET),
- dev->base_addr + EPLD_IO_CONTROL_REGISTER);
-
- mb();
- writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) &
- ~(1 << NET2272_RESET),
- dev->base_addr + EPLD_IO_CONTROL_REGISTER);
- udelay(200);
-
- return 0;
-
- err:
- while (--i >= 0) {
- if (i == 1)
- continue; /* BAR1 unused */
- iounmap(mem_mapped_addr[i]);
- release_mem_region(pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
- }
-
- return ret;
-}
-
-static int
-net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev)
-{
- unsigned long resource, len;
- void __iomem *mem_mapped_addr[2];
- int ret, i;
-
- /*
- * BAR 0 holds FGPA config registers
- * BAR 1 holds NET2272 registers
- */
-
- /* Find and map all address spaces, bar2-3 unused in rdk 2 */
- for (i = 0; i < 2; ++i) {
- resource = pci_resource_start(pdev, i);
- len = pci_resource_len(pdev, i);
-
- if (!request_mem_region(resource, len, driver_name)) {
- dev_dbg(dev->dev, "controller already in use\n");
- ret = -EBUSY;
- goto err;
- }
-
- mem_mapped_addr[i] = ioremap(resource, len);
- if (mem_mapped_addr[i] == NULL) {
- release_mem_region(resource, len);
- dev_dbg(dev->dev, "can't map memory\n");
- ret = -EFAULT;
- goto err;
- }
- }
-
- dev->rdk2.fpga_base_addr = mem_mapped_addr[0];
- dev->base_addr = mem_mapped_addr[1];
-
- mb();
- /* Set 2272 bus width (16 bits) and reset */
- writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK);
- udelay(200);
- writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK);
- /* Print fpga version number */
- dev_info(dev->dev, "RDK2 FPGA version %08x\n",
- readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV));
- /* Enable FPGA Interrupts */
- writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB);
-
- return 0;
-
- err:
- while (--i >= 0) {
- iounmap(mem_mapped_addr[i]);
- release_mem_region(pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
- }
-
- return ret;
-}
-
-static int
-net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct net2272 *dev;
- int ret;
-
- dev = net2272_probe_init(&pdev->dev, pdev->irq);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
- dev->dev_id = pdev->device;
-
- if (pci_enable_device(pdev) < 0) {
- ret = -ENODEV;
- goto err_put;
- }
-
- pci_set_master(pdev);
-
- switch (pdev->device) {
- case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break;
- case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break;
- default: BUG();
- }
- if (ret)
- goto err_pci;
-
- ret = net2272_probe_fin(dev, 0);
- if (ret)
- goto err_pci;
-
- pci_set_drvdata(pdev, dev);
-
- return 0;
-
- err_pci:
- pci_disable_device(pdev);
- err_put:
- usb_put_gadget(&dev->gadget);
-
- return ret;
-}
-
-static void
-net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev)
-{
- int i;
-
- /* disable PLX 9054 interrupts */
- writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) &
- ~(1 << PCI_INTERRUPT_ENABLE),
- dev->rdk1.plx9054_base_addr + INTCSR);
-
- /* clean up resources allocated during probe() */
- iounmap(dev->rdk1.plx9054_base_addr);
- iounmap(dev->rdk1.epld_base_addr);
-
- for (i = 0; i < 4; ++i) {
- if (i == 1)
- continue; /* BAR1 unused */
- release_mem_region(pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
- }
-}
-
-static void
-net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev)
-{
- int i;
-
- /* disable fpga interrupts
- writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) &
- ~(1 << PCI_INTERRUPT_ENABLE),
- dev->rdk1.plx9054_base_addr + INTCSR);
- */
-
- /* clean up resources allocated during probe() */
- iounmap(dev->rdk2.fpga_base_addr);
-
- for (i = 0; i < 2; ++i)
- release_mem_region(pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
-}
-
-static void
-net2272_pci_remove(struct pci_dev *pdev)
-{
- struct net2272 *dev = pci_get_drvdata(pdev);
-
- net2272_remove(dev);
-
- switch (pdev->device) {
- case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break;
- case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break;
- default: BUG();
- }
-
- pci_disable_device(pdev);
-
- usb_put_gadget(&dev->gadget);
-}
-
-/* Table of matching PCI IDs */
-static struct pci_device_id pci_ids[] = {
- { /* RDK 1 card */
- .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe),
- .class_mask = 0,
- .vendor = PCI_VENDOR_ID_PLX,
- .device = PCI_DEVICE_ID_RDK1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { /* RDK 2 card */
- .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe),
- .class_mask = 0,
- .vendor = PCI_VENDOR_ID_PLX,
- .device = PCI_DEVICE_ID_RDK2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { }
-};
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-static struct pci_driver net2272_pci_driver = {
- .name = driver_name,
- .id_table = pci_ids,
-
- .probe = net2272_pci_probe,
- .remove = net2272_pci_remove,
-};
-
-static int net2272_pci_register(void)
-{
- return pci_register_driver(&net2272_pci_driver);
-}
-
-static void net2272_pci_unregister(void)
-{
- pci_unregister_driver(&net2272_pci_driver);
-}
-
-#else
-static inline int net2272_pci_register(void) { return 0; }
-static inline void net2272_pci_unregister(void) { }
-#endif
-
-/*---------------------------------------------------------------------------*/
-
-static int
-net2272_plat_probe(struct platform_device *pdev)
-{
- struct net2272 *dev;
- int ret;
- unsigned int irqflags;
- resource_size_t base, len;
- struct resource *iomem, *iomem_bus, *irq_res;
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0);
- if (!irq_res || !iomem) {
- dev_err(&pdev->dev, "must provide irq/base addr");
- return -EINVAL;
- }
-
- dev = net2272_probe_init(&pdev->dev, irq_res->start);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
-
- irqflags = 0;
- if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE)
- irqflags |= IRQF_TRIGGER_RISING;
- if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE)
- irqflags |= IRQF_TRIGGER_FALLING;
- if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL)
- irqflags |= IRQF_TRIGGER_HIGH;
- if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
- irqflags |= IRQF_TRIGGER_LOW;
-
- base = iomem->start;
- len = resource_size(iomem);
- if (iomem_bus)
- dev->base_shift = iomem_bus->start;
-
- if (!request_mem_region(base, len, driver_name)) {
- dev_dbg(dev->dev, "get request memory region!\n");
- ret = -EBUSY;
- goto err;
- }
- dev->base_addr = ioremap(base, len);
- if (!dev->base_addr) {
- dev_dbg(dev->dev, "can't map memory\n");
- ret = -EFAULT;
- goto err_req;
- }
-
- ret = net2272_probe_fin(dev, irqflags);
- if (ret)
- goto err_io;
-
- platform_set_drvdata(pdev, dev);
- dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n",
- (net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no ");
-
- return 0;
-
- err_io:
- iounmap(dev->base_addr);
- err_req:
- release_mem_region(base, len);
- err:
- usb_put_gadget(&dev->gadget);
-
- return ret;
-}
-
-static void
-net2272_plat_remove(struct platform_device *pdev)
-{
- struct net2272 *dev = platform_get_drvdata(pdev);
-
- net2272_remove(dev);
-
- release_mem_region(pdev->resource[0].start,
- resource_size(&pdev->resource[0]));
-
- usb_put_gadget(&dev->gadget);
-}
-
-static struct platform_driver net2272_plat_driver = {
- .probe = net2272_plat_probe,
- .remove = net2272_plat_remove,
- .driver = {
- .name = driver_name,
- },
- /* FIXME .suspend, .resume */
-};
-MODULE_ALIAS("platform:net2272");
-
-static int __init net2272_init(void)
-{
- int ret;
-
- ret = net2272_pci_register();
- if (ret)
- return ret;
- ret = platform_driver_register(&net2272_plat_driver);
- if (ret)
- goto err_pci;
- return ret;
-
-err_pci:
- net2272_pci_unregister();
- return ret;
-}
-module_init(net2272_init);
-
-static void __exit net2272_cleanup(void)
-{
- net2272_pci_unregister();
- platform_driver_unregister(&net2272_plat_driver);
-}
-module_exit(net2272_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("PLX Technology, Inc.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h
deleted file mode 100644
index a9994f737588..000000000000
--- a/drivers/usb/gadget/udc/net2272.h
+++ /dev/null
@@ -1,584 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * PLX NET2272 high/full speed USB device controller
- *
- * Copyright (C) 2005-2006 PLX Technology, Inc.
- * Copyright (C) 2006-2011 Analog Devices, Inc.
- */
-
-#ifndef __NET2272_H__
-#define __NET2272_H__
-
-/* Main Registers */
-#define REGADDRPTR 0x00
-#define REGDATA 0x01
-#define IRQSTAT0 0x02
-#define ENDPOINT_0_INTERRUPT 0
-#define ENDPOINT_A_INTERRUPT 1
-#define ENDPOINT_B_INTERRUPT 2
-#define ENDPOINT_C_INTERRUPT 3
-#define VIRTUALIZED_ENDPOINT_INTERRUPT 4
-#define SETUP_PACKET_INTERRUPT 5
-#define DMA_DONE_INTERRUPT 6
-#define SOF_INTERRUPT 7
-#define IRQSTAT1 0x03
-#define CONTROL_STATUS_INTERRUPT 1
-#define VBUS_INTERRUPT 2
-#define SUSPEND_REQUEST_INTERRUPT 3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT 4
-#define RESUME_INTERRUPT 5
-#define ROOT_PORT_RESET_INTERRUPT 6
-#define RESET_STATUS 7
-#define PAGESEL 0x04
-#define DMAREQ 0x1c
-#define DMA_ENDPOINT_SELECT 0
-#define DREQ_POLARITY 1
-#define DACK_POLARITY 2
-#define EOT_POLARITY 3
-#define DMA_CONTROL_DACK 4
-#define DMA_REQUEST_ENABLE 5
-#define DMA_REQUEST 6
-#define DMA_BUFFER_VALID 7
-#define SCRATCH 0x1d
-#define IRQENB0 0x20
-#define ENDPOINT_0_INTERRUPT_ENABLE 0
-#define ENDPOINT_A_INTERRUPT_ENABLE 1
-#define ENDPOINT_B_INTERRUPT_ENABLE 2
-#define ENDPOINT_C_INTERRUPT_ENABLE 3
-#define VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE 4
-#define SETUP_PACKET_INTERRUPT_ENABLE 5
-#define DMA_DONE_INTERRUPT_ENABLE 6
-#define SOF_INTERRUPT_ENABLE 7
-#define IRQENB1 0x21
-#define VBUS_INTERRUPT_ENABLE 2
-#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
-#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 4
-#define RESUME_INTERRUPT_ENABLE 5
-#define ROOT_PORT_RESET_INTERRUPT_ENABLE 6
-#define LOCCTL 0x22
-#define DATA_WIDTH 0
-#define LOCAL_CLOCK_OUTPUT 1
-#define LOCAL_CLOCK_OUTPUT_OFF 0
-#define LOCAL_CLOCK_OUTPUT_3_75MHZ 1
-#define LOCAL_CLOCK_OUTPUT_7_5MHZ 2
-#define LOCAL_CLOCK_OUTPUT_15MHZ 3
-#define LOCAL_CLOCK_OUTPUT_30MHZ 4
-#define LOCAL_CLOCK_OUTPUT_60MHZ 5
-#define DMA_SPLIT_BUS_MODE 4
-#define BYTE_SWAP 5
-#define BUFFER_CONFIGURATION 6
-#define BUFFER_CONFIGURATION_EPA512_EPB512 0
-#define BUFFER_CONFIGURATION_EPA1024_EPB512 1
-#define BUFFER_CONFIGURATION_EPA1024_EPB1024 2
-#define BUFFER_CONFIGURATION_EPA1024DB 3
-#define CHIPREV_LEGACY 0x23
-#define NET2270_LEGACY_REV 0x40
-#define LOCCTL1 0x24
-#define DMA_MODE 0
-#define SLOW_DREQ 0
-#define FAST_DREQ 1
-#define BURST_MODE 2
-#define DMA_DACK_ENABLE 2
-#define CHIPREV_2272 0x25
-#define CHIPREV_NET2272_R1 0x10
-#define CHIPREV_NET2272_R1A 0x11
-/* USB Registers */
-#define USBCTL0 0x18
-#define IO_WAKEUP_ENABLE 1
-#define USB_DETECT_ENABLE 3
-#define USB_ROOT_PORT_WAKEUP_ENABLE 5
-#define USBCTL1 0x19
-#define VBUS_PIN 0
-#define USB_FULL_SPEED 1
-#define USB_HIGH_SPEED 2
-#define GENERATE_RESUME 3
-#define VIRTUAL_ENDPOINT_ENABLE 4
-#define FRAME0 0x1a
-#define FRAME1 0x1b
-#define OURADDR 0x30
-#define FORCE_IMMEDIATE 7
-#define USBDIAG 0x31
-#define FORCE_TRANSMIT_CRC_ERROR 0
-#define PREVENT_TRANSMIT_BIT_STUFF 1
-#define FORCE_RECEIVE_ERROR 2
-#define FAST_TIMES 4
-#define USBTEST 0x32
-#define TEST_MODE_SELECT 0
-#define NORMAL_OPERATION 0
-#define XCVRDIAG 0x33
-#define FORCE_FULL_SPEED 2
-#define FORCE_HIGH_SPEED 3
-#define OPMODE 4
-#define NORMAL_OPERATION 0
-#define NON_DRIVING 1
-#define DISABLE_BITSTUFF_AND_NRZI_ENCODE 2
-#define LINESTATE 6
-#define SE0_STATE 0
-#define J_STATE 1
-#define K_STATE 2
-#define SE1_STATE 3
-#define VIRTOUT0 0x34
-#define VIRTOUT1 0x35
-#define VIRTIN0 0x36
-#define VIRTIN1 0x37
-#define SETUP0 0x40
-#define SETUP1 0x41
-#define SETUP2 0x42
-#define SETUP3 0x43
-#define SETUP4 0x44
-#define SETUP5 0x45
-#define SETUP6 0x46
-#define SETUP7 0x47
-/* Endpoint Registers (Paged via PAGESEL) */
-#define EP_DATA 0x05
-#define EP_STAT0 0x06
-#define DATA_IN_TOKEN_INTERRUPT 0
-#define DATA_OUT_TOKEN_INTERRUPT 1
-#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
-#define DATA_PACKET_RECEIVED_INTERRUPT 3
-#define SHORT_PACKET_TRANSFERRED_INTERRUPT 4
-#define NAK_OUT_PACKETS 5
-#define BUFFER_EMPTY 6
-#define BUFFER_FULL 7
-#define EP_STAT1 0x07
-#define TIMEOUT 0
-#define USB_OUT_ACK_SENT 1
-#define USB_OUT_NAK_SENT 2
-#define USB_IN_ACK_RCVD 3
-#define USB_IN_NAK_SENT 4
-#define USB_STALL_SENT 5
-#define LOCAL_OUT_ZLP 6
-#define BUFFER_FLUSH 7
-#define EP_TRANSFER0 0x08
-#define EP_TRANSFER1 0x09
-#define EP_TRANSFER2 0x0a
-#define EP_IRQENB 0x0b
-#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0
-#define DATA_OUT_TOKEN_INTERRUPT_ENABLE 1
-#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2
-#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3
-#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 4
-#define EP_AVAIL0 0x0c
-#define EP_AVAIL1 0x0d
-#define EP_RSPCLR 0x0e
-#define EP_RSPSET 0x0f
-#define ENDPOINT_HALT 0
-#define ENDPOINT_TOGGLE 1
-#define NAK_OUT_PACKETS_MODE 2
-#define CONTROL_STATUS_PHASE_HANDSHAKE 3
-#define INTERRUPT_MODE 4
-#define AUTOVALIDATE 5
-#define HIDE_STATUS_PHASE 6
-#define ALT_NAK_OUT_PACKETS 7
-#define EP_MAXPKT0 0x28
-#define EP_MAXPKT1 0x29
-#define ADDITIONAL_TRANSACTION_OPPORTUNITIES 3
-#define NONE_ADDITIONAL_TRANSACTION 0
-#define ONE_ADDITIONAL_TRANSACTION 1
-#define TWO_ADDITIONAL_TRANSACTION 2
-#define EP_CFG 0x2a
-#define ENDPOINT_NUMBER 0
-#define ENDPOINT_DIRECTION 4
-#define ENDPOINT_TYPE 5
-#define ENDPOINT_ENABLE 7
-#define EP_HBW 0x2b
-#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 0
-#define DATA0_PID 0
-#define DATA1_PID 1
-#define DATA2_PID 2
-#define MDATA_PID 3
-#define EP_BUFF_STATES 0x2c
-#define BUFFER_A_STATE 0
-#define BUFFER_B_STATE 2
-#define BUFF_FREE 0
-#define BUFF_VALID 1
-#define BUFF_LCL 2
-#define BUFF_USB 3
-
-/*---------------------------------------------------------------------------*/
-
-#define PCI_DEVICE_ID_RDK1 0x9054
-
-/* PCI-RDK EPLD Registers */
-#define RDK_EPLD_IO_REGISTER1 0x00000000
-#define RDK_EPLD_USB_RESET 0
-#define RDK_EPLD_USB_POWERDOWN 1
-#define RDK_EPLD_USB_WAKEUP 2
-#define RDK_EPLD_USB_EOT 3
-#define RDK_EPLD_DPPULL 4
-#define RDK_EPLD_IO_REGISTER2 0x00000004
-#define RDK_EPLD_BUSWIDTH 0
-#define RDK_EPLD_USER 2
-#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3
-#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4
-#define RDK_EPLD_STATUS_REGISTER 0x00000008
-#define RDK_EPLD_USB_LRESET 0
-#define RDK_EPLD_REVISION_REGISTER 0x0000000c
-
-/* PCI-RDK PLX 9054 Registers */
-#define INTCSR 0x68
-#define PCI_INTERRUPT_ENABLE 8
-#define LOCAL_INTERRUPT_INPUT_ENABLE 11
-#define LOCAL_INPUT_INTERRUPT_ACTIVE 15
-#define LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE 18
-#define LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE 19
-#define DMA_CHANNEL_0_INTERRUPT_ACTIVE 21
-#define DMA_CHANNEL_1_INTERRUPT_ACTIVE 22
-#define CNTRL 0x6C
-#define RELOAD_CONFIGURATION_REGISTERS 29
-#define PCI_ADAPTER_SOFTWARE_RESET 30
-#define DMAMODE0 0x80
-#define LOCAL_BUS_WIDTH 0
-#define INTERNAL_WAIT_STATES 2
-#define TA_READY_INPUT_ENABLE 6
-#define LOCAL_BURST_ENABLE 8
-#define SCATTER_GATHER_MODE 9
-#define DONE_INTERRUPT_ENABLE 10
-#define LOCAL_ADDRESSING_MODE 11
-#define DEMAND_MODE 12
-#define DMA_EOT_ENABLE 14
-#define FAST_SLOW_TERMINATE_MODE_SELECT 15
-#define DMA_CHANNEL_INTERRUPT_SELECT 17
-#define DMAPADR0 0x84
-#define DMALADR0 0x88
-#define DMASIZ0 0x8c
-#define DMADPR0 0x90
-#define DESCRIPTOR_LOCATION 0
-#define END_OF_CHAIN 1
-#define INTERRUPT_AFTER_TERMINAL_COUNT 2
-#define DIRECTION_OF_TRANSFER 3
-#define DMACSR0 0xa8
-#define CHANNEL_ENABLE 0
-#define CHANNEL_START 1
-#define CHANNEL_ABORT 2
-#define CHANNEL_CLEAR_INTERRUPT 3
-#define CHANNEL_DONE 4
-#define DMATHR 0xb0
-#define LBRD1 0xf8
-#define MEMORY_SPACE_LOCAL_BUS_WIDTH 0
-#define W8_BIT 0
-#define W16_BIT 1
-
-/* Special OR'ing of INTCSR bits */
-#define LOCAL_INTERRUPT_TEST \
- ((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \
- (1 << LOCAL_INTERRUPT_INPUT_ENABLE))
-
-#define DMA_CHANNEL_0_TEST \
- ((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \
- (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE))
-
-#define DMA_CHANNEL_1_TEST \
- ((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \
- (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE))
-
-/* EPLD Registers */
-#define RDK_EPLD_IO_REGISTER1 0x00000000
-#define RDK_EPLD_USB_RESET 0
-#define RDK_EPLD_USB_POWERDOWN 1
-#define RDK_EPLD_USB_WAKEUP 2
-#define RDK_EPLD_USB_EOT 3
-#define RDK_EPLD_DPPULL 4
-#define RDK_EPLD_IO_REGISTER2 0x00000004
-#define RDK_EPLD_BUSWIDTH 0
-#define RDK_EPLD_USER 2
-#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3
-#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4
-#define RDK_EPLD_STATUS_REGISTER 0x00000008
-#define RDK_EPLD_USB_LRESET 0
-#define RDK_EPLD_REVISION_REGISTER 0x0000000c
-
-#define EPLD_IO_CONTROL_REGISTER 0x400
-#define NET2272_RESET 0
-#define BUSWIDTH 1
-#define MPX_MODE 3
-#define USER 4
-#define DMA_TIMEOUT_ENABLE 5
-#define DMA_CTL_DACK 6
-#define EPLD_DMA_ENABLE 7
-#define EPLD_DMA_CONTROL_REGISTER 0x800
-#define SPLIT_DMA_MODE 0
-#define SPLIT_DMA_DIRECTION 1
-#define SPLIT_DMA_ENABLE 2
-#define SPLIT_DMA_INTERRUPT_ENABLE 3
-#define SPLIT_DMA_INTERRUPT 4
-#define EPLD_DMA_MODE 5
-#define EPLD_DMA_CONTROLLER_ENABLE 7
-#define SPLIT_DMA_ADDRESS_LOW 0xc00
-#define SPLIT_DMA_ADDRESS_HIGH 0x1000
-#define SPLIT_DMA_BYTE_COUNT_LOW 0x1400
-#define SPLIT_DMA_BYTE_COUNT_HIGH 0x1800
-#define EPLD_REVISION_REGISTER 0x1c00
-#define SPLIT_DMA_RAM 0x4000
-#define DMA_RAM_SIZE 0x1000
-
-/*---------------------------------------------------------------------------*/
-
-#define PCI_DEVICE_ID_RDK2 0x3272
-
-/* PCI-RDK version 2 registers */
-
-/* Main Control Registers */
-
-#define RDK2_IRQENB 0x00
-#define RDK2_IRQSTAT 0x04
-#define PB7 23
-#define PB6 22
-#define PB5 21
-#define PB4 20
-#define PB3 19
-#define PB2 18
-#define PB1 17
-#define PB0 16
-#define GP3 23
-#define GP2 23
-#define GP1 23
-#define GP0 23
-#define DMA_RETRY_ABORT 6
-#define DMA_PAUSE_DONE 5
-#define DMA_ABORT_DONE 4
-#define DMA_OUT_FIFO_TRANSFER_DONE 3
-#define DMA_LOCAL_DONE 2
-#define DMA_PCI_DONE 1
-#define NET2272_PCI_IRQ 0
-
-#define RDK2_LOCCTLRDK 0x08
-#define CHIP_RESET 3
-#define SPLIT_DMA 2
-#define MULTIPLEX_MODE 1
-#define BUS_WIDTH 0
-
-#define RDK2_GPIOCTL 0x10
-#define GP3_OUT_ENABLE 7
-#define GP2_OUT_ENABLE 6
-#define GP1_OUT_ENABLE 5
-#define GP0_OUT_ENABLE 4
-#define GP3_DATA 3
-#define GP2_DATA 2
-#define GP1_DATA 1
-#define GP0_DATA 0
-
-#define RDK2_LEDSW 0x14
-#define LED3 27
-#define LED2 26
-#define LED1 25
-#define LED0 24
-#define PBUTTON 16
-#define DIPSW 0
-
-#define RDK2_DIAG 0x18
-#define RDK2_FAST_TIMES 2
-#define FORCE_PCI_SERR 1
-#define FORCE_PCI_INT 0
-#define RDK2_FPGAREV 0x1C
-
-/* Dma Control registers */
-#define RDK2_DMACTL 0x80
-#define ADDR_HOLD 24
-#define RETRY_COUNT 16 /* 23:16 */
-#define FIFO_THRESHOLD 11 /* 15:11 */
-#define MEM_WRITE_INVALIDATE 10
-#define READ_MULTIPLE 9
-#define READ_LINE 8
-#define RDK2_DMA_MODE 6 /* 7:6 */
-#define CONTROL_DACK 5
-#define EOT_ENABLE 4
-#define EOT_POLARITY 3
-#define DACK_POLARITY 2
-#define DREQ_POLARITY 1
-#define DMA_ENABLE 0
-
-#define RDK2_DMASTAT 0x84
-#define GATHER_COUNT 12 /* 14:12 */
-#define FIFO_COUNT 6 /* 11:6 */
-#define FIFO_FLUSH 5
-#define FIFO_TRANSFER 4
-#define PAUSE_DONE 3
-#define ABORT_DONE 2
-#define DMA_ABORT 1
-#define DMA_START 0
-
-#define RDK2_DMAPCICOUNT 0x88
-#define DMA_DIRECTION 31
-#define DMA_PCI_BYTE_COUNT 0 /* 0:23 */
-
-#define RDK2_DMALOCCOUNT 0x8C /* 0:23 dma local byte count */
-
-#define RDK2_DMAADDR 0x90 /* 2:31 PCI bus starting address */
-
-/*---------------------------------------------------------------------------*/
-
-#define REG_INDEXED_THRESHOLD (1 << 5)
-
-/* DRIVER DATA STRUCTURES and UTILITIES */
-struct net2272_ep {
- struct usb_ep ep;
- struct net2272 *dev;
- unsigned long irqs;
-
- /* analogous to a host-side qh */
- struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
- unsigned num:8,
- fifo_size:12,
- stopped:1,
- wedged:1,
- is_in:1,
- is_iso:1,
- dma:1,
- not_empty:1;
-};
-
-struct net2272 {
- /* each device provides one gadget, several endpoints */
- struct usb_gadget gadget;
- struct device *dev;
- unsigned short dev_id;
-
- spinlock_t lock;
- struct net2272_ep ep[4];
- struct usb_gadget_driver *driver;
- unsigned protocol_stall:1,
- softconnect:1,
- wakeup:1,
- added:1,
- async_callbacks:1,
- dma_eot_polarity:1,
- dma_dack_polarity:1,
- dma_dreq_polarity:1,
- dma_busy:1;
- u16 chiprev;
- u8 pagesel;
-
- unsigned int irq;
- unsigned short fifo_mode;
-
- unsigned int base_shift;
- u16 __iomem *base_addr;
- union {
-#ifdef CONFIG_USB_PCI
- struct {
- void __iomem *plx9054_base_addr;
- void __iomem *epld_base_addr;
- } rdk1;
- struct {
- /* Bar0, Bar1 is base_addr both mem-mapped */
- void __iomem *fpga_base_addr;
- } rdk2;
-#endif
- };
-};
-
-static void __iomem *
-net2272_reg_addr(struct net2272 *dev, unsigned int reg)
-{
- return dev->base_addr + (reg << dev->base_shift);
-}
-
-static void
-net2272_write(struct net2272 *dev, unsigned int reg, u8 value)
-{
- if (reg >= REG_INDEXED_THRESHOLD) {
- /*
- * Indexed register; use REGADDRPTR/REGDATA
- * - Save and restore REGADDRPTR. This prevents REGADDRPTR from
- * changes between other code sections, but it is time consuming.
- * - Performance tips: either do not save and restore REGADDRPTR (if it
- * is safe) or do save/restore operations only in critical sections.
- u8 tmp = readb(dev->base_addr + REGADDRPTR);
- */
- writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
- writeb(value, net2272_reg_addr(dev, REGDATA));
- /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
- } else
- writeb(value, net2272_reg_addr(dev, reg));
-}
-
-static u8
-net2272_read(struct net2272 *dev, unsigned int reg)
-{
- u8 ret;
-
- if (reg >= REG_INDEXED_THRESHOLD) {
- /*
- * Indexed register; use REGADDRPTR/REGDATA
- * - Save and restore REGADDRPTR. This prevents REGADDRPTR from
- * changes between other code sections, but it is time consuming.
- * - Performance tips: either do not save and restore REGADDRPTR (if it
- * is safe) or do save/restore operations only in critical sections.
- u8 tmp = readb(dev->base_addr + REGADDRPTR);
- */
- writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
- ret = readb(net2272_reg_addr(dev, REGDATA));
- /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
- } else
- ret = readb(net2272_reg_addr(dev, reg));
-
- return ret;
-}
-
-static void
-net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value)
-{
- struct net2272 *dev = ep->dev;
-
- if (dev->pagesel != ep->num) {
- net2272_write(dev, PAGESEL, ep->num);
- dev->pagesel = ep->num;
- }
- net2272_write(dev, reg, value);
-}
-
-static u8
-net2272_ep_read(struct net2272_ep *ep, unsigned int reg)
-{
- struct net2272 *dev = ep->dev;
-
- if (dev->pagesel != ep->num) {
- net2272_write(dev, PAGESEL, ep->num);
- dev->pagesel = ep->num;
- }
- return net2272_read(dev, reg);
-}
-
-static void allow_status(struct net2272_ep *ep)
-{
- /* ep0 only */
- net2272_ep_write(ep, EP_RSPCLR,
- (1 << CONTROL_STATUS_PHASE_HANDSHAKE) |
- (1 << ALT_NAK_OUT_PACKETS) |
- (1 << NAK_OUT_PACKETS_MODE));
- ep->stopped = 1;
-}
-
-static void set_halt(struct net2272_ep *ep)
-{
- /* ep0 and bulk/intr endpoints */
- net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE);
- net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT);
-}
-
-static void clear_halt(struct net2272_ep *ep)
-{
- /* ep0 and bulk/intr endpoints */
- net2272_ep_write(ep, EP_RSPCLR,
- (1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE));
-}
-
-/* count (<= 4) bytes in the next fifo write will be valid */
-static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count)
-{
- /* net2272_ep_write will truncate to u8 for us */
- net2272_ep_write(ep, EP_TRANSFER2, count >> 16);
- net2272_ep_write(ep, EP_TRANSFER1, count >> 8);
- net2272_ep_write(ep, EP_TRANSFER0, count);
-}
-
-struct net2272_request {
- struct usb_request req;
- struct list_head queue;
- unsigned mapped:1,
- valid:1;
-};
-
-#endif
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 89b304cf6d03..3e4d56457597 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -2397,8 +2397,7 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false);
renesas_usb3_stop_controller(usb3);
- if (usb3->phy)
- phy_exit(usb3->phy);
+ phy_exit(usb3->phy);
pm_runtime_put(usb3_to_dev(usb3));
@@ -2984,8 +2983,7 @@ static int renesas_usb3_suspend(struct device *dev)
return 0;
renesas_usb3_stop_controller(usb3);
- if (usb3->phy)
- phy_exit(usb3->phy);
+ phy_exit(usb3->phy);
pm_runtime_put(dev);
return 0;
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index ae2aeb271897..fa94cc065274 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -2178,8 +2178,6 @@ fail:
/**
* xudc_remove - Releases the resources allocated during the initialization.
* @pdev: pointer to the platform device structure.
- *
- * Return: 0 always
*/
static void xudc_remove(struct platform_device *pdev)
{
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index d011d6c753ed..109100cc77a3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -104,6 +104,15 @@ config USB_XHCI_RZV2M
Say 'Y' to enable the support for the xHCI host controller
found in Renesas RZ/V2M SoC.
+config USB_XHCI_SIDEBAND
+ bool "xHCI support for sideband"
+ help
+ Say 'Y' to enable the support for the xHCI sideband capability.
+ Provide a mechanism for a sideband datapath for payload associated
+ with audio class endpoints. This allows for an audio DSP to use
+ xHCI USB endpoints directly, allowing CPU to sleep while playing
+ audio.
+
config USB_XHCI_TEGRA
tristate "xHCI support for NVIDIA Tegra SoCs"
depends on PHY_TEGRA_XUSB
@@ -225,7 +234,7 @@ config USB_EHCI_HCD_OMAP
tristate "EHCI support for OMAP3 and later chips"
depends on ARCH_OMAP || COMPILE_TEST
depends on NOP_USB_XCEIV
- default y
+ default ARCH_OMAP
help
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index be4e5245c52f..4df946c05ba0 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -32,6 +32,10 @@ endif
xhci-rcar-hcd-y += xhci-rcar.o
xhci-rcar-hcd-$(CONFIG_USB_XHCI_RZV2M) += xhci-rzv2m.o
+ifneq ($(CONFIG_USB_XHCI_SIDEBAND),)
+ xhci-hcd-y += xhci-sideband.o
+endif
+
obj-$(CONFIG_USB_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 26f13278d4d6..6ed2fa5418a4 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -410,15 +410,13 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
return retval;
}
-struct ehci_fsl {
- struct ehci_hcd ehci;
-
-#ifdef CONFIG_PM
+struct ehci_fsl_priv {
/* Saved USB PHY settings, need to restore after deep sleep. */
u32 usb_ctrl;
-#endif
};
+#define hcd_to_ehci_fsl_priv(h) ((struct ehci_fsl_priv *) hcd_to_ehci(h)->priv)
+
#ifdef CONFIG_PM
#ifdef CONFIG_PPC_MPC512x
@@ -566,17 +564,10 @@ static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev)
}
#endif /* CONFIG_PPC_MPC512x */
-static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- return container_of(ehci, struct ehci_fsl, ehci);
-}
-
static int ehci_fsl_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_fsl_priv *priv = hcd_to_ehci_fsl_priv(hcd);
void __iomem *non_ehci = hcd->regs;
if (of_device_is_compatible(dev->parent->of_node,
@@ -589,14 +580,14 @@ static int ehci_fsl_drv_suspend(struct device *dev)
if (!fsl_deep_sleep())
return 0;
- ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
+ priv->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL);
return 0;
}
static int ehci_fsl_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_fsl_priv *priv = hcd_to_ehci_fsl_priv(hcd);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
@@ -612,7 +603,7 @@ static int ehci_fsl_drv_resume(struct device *dev)
usb_root_hub_lost_power(hcd->self.root_hub);
/* Restore USB PHY settings and enable the controller. */
- iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL);
+ iowrite32be(priv->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL);
ehci_reset(ehci);
ehci_fsl_reinit(ehci);
@@ -671,7 +662,7 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)
#endif /* CONFIG_USB_OTG */
static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = {
- .extra_priv_size = sizeof(struct ehci_fsl),
+ .extra_priv_size = sizeof(struct ehci_fsl_priv),
.reset = ehci_fsl_setup,
};
diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h
index f6b9a00a0ab9..4b8ff4815644 100644
--- a/drivers/usb/host/xhci-caps.h
+++ b/drivers/usb/host/xhci-caps.h
@@ -62,8 +62,8 @@
#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
-/* db_off bitmask - bits 0:1 reserved */
-#define DBOFF_MASK (~0x3)
+/* db_off bitmask - bits 31:2 Doorbell Array Offset */
+#define DBOFF_MASK (0xfffffffc)
/* run_regs_off bitmask - bits 0:4 reserved */
#define RTSOFF_MASK (~0x1f)
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 1f5ef174abea..c6d44977193f 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -631,6 +631,112 @@ static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
}
}
+static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed,
+ struct seq_file *s)
+{
+ unsigned int num_ports;
+ unsigned int i;
+ int ret;
+ struct xhci_container_ctx *ctx;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ struct device *dev = hcd->self.controller;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ return ret;
+
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+ ctx = xhci_alloc_port_bw_ctx(xhci, 0);
+ if (!ctx) {
+ pm_runtime_put_sync(dev);
+ return -ENOMEM;
+ }
+
+ /* get roothub port bandwidth */
+ ret = xhci_get_port_bandwidth(xhci, ctx, dev_speed);
+ if (ret)
+ goto err_out;
+
+ /* print all roothub ports available bandwidth
+ * refer to xhci rev1_2 protocol 6.2.6 , byte 0 is reserved
+ */
+ for (i = 1; i < num_ports+1; i++)
+ seq_printf(s, "port[%d] available bw: %d%%.\n", i,
+ ctx->bytes[i]);
+err_out:
+ pm_runtime_put_sync(dev);
+ xhci_free_port_bw_ctx(xhci, ctx);
+ return ret;
+}
+
+static int xhci_ss_bw_show(struct seq_file *s, void *unused)
+{
+ int ret;
+ struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
+
+ ret = xhci_port_bw_show(xhci, USB_SPEED_SUPER, s);
+ return ret;
+}
+
+static int xhci_hs_bw_show(struct seq_file *s, void *unused)
+{
+ int ret;
+ struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
+
+ ret = xhci_port_bw_show(xhci, USB_SPEED_HIGH, s);
+ return ret;
+}
+
+static int xhci_fs_bw_show(struct seq_file *s, void *unused)
+{
+ int ret;
+ struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
+
+ ret = xhci_port_bw_show(xhci, USB_SPEED_FULL, s);
+ return ret;
+}
+
+static struct xhci_file_map bw_context_files[] = {
+ {"SS_BW", xhci_ss_bw_show, },
+ {"HS_BW", xhci_hs_bw_show, },
+ {"FS_BW", xhci_fs_bw_show, },
+};
+
+static int bw_context_open(struct inode *inode, struct file *file)
+{
+ int i;
+ struct xhci_file_map *f_map;
+ const char *file_name = file_dentry(file)->d_iname;
+
+ for (i = 0; i < ARRAY_SIZE(bw_context_files); i++) {
+ f_map = &bw_context_files[i];
+
+ if (strcmp(f_map->name, file_name) == 0)
+ break;
+ }
+
+ return single_open(file, f_map->show, inode->i_private);
+}
+
+static const struct file_operations bw_fops = {
+ .open = bw_context_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void xhci_debugfs_create_bandwidth(struct xhci_hcd *xhci,
+ struct dentry *parent)
+{
+ parent = debugfs_create_dir("port_bandwidth", parent);
+
+ xhci_debugfs_create_files(xhci, bw_context_files,
+ ARRAY_SIZE(bw_context_files),
+ xhci,
+ parent, &bw_fops);
+}
+
void xhci_debugfs_init(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
@@ -681,6 +787,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root);
xhci_debugfs_create_ports(xhci, xhci->debugfs_root);
+
+ xhci_debugfs_create_bandwidth(xhci, xhci->debugfs_root);
}
void xhci_debugfs_exit(struct xhci_hcd *xhci)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 486347776cb2..92bb84f8132a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1907,7 +1907,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)
* prevent port event interrupts from interfering
* with usb2 port resume process
*/
- xhci_disable_interrupter(xhci->interrupters[0]);
+ xhci_disable_interrupter(xhci, xhci->interrupters[0]);
disabled_irq = true;
}
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index d698095fc88d..bd745a0f2f78 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -484,6 +484,35 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci,
kfree(ctx);
}
+struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci,
+ gfp_t flags)
+{
+ struct xhci_container_ctx *ctx;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+
+ ctx = kzalloc_node(sizeof(*ctx), flags, dev_to_node(dev));
+ if (!ctx)
+ return NULL;
+
+ ctx->size = GET_PORT_BW_ARRAY_SIZE;
+
+ ctx->bytes = dma_pool_zalloc(xhci->port_bw_pool, flags, &ctx->dma);
+ if (!ctx->bytes) {
+ kfree(ctx);
+ return NULL;
+ }
+ return ctx;
+}
+
+void xhci_free_port_bw_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx)
+{
+ if (!ctx)
+ return;
+ dma_pool_free(xhci->port_bw_pool, ctx->bytes, ctx->dma);
+ kfree(ctx);
+}
+
struct xhci_input_control_ctx *xhci_get_input_control_ctx(
struct xhci_container_ctx *ctx)
{
@@ -1802,10 +1831,10 @@ xhci_remove_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
*/
if (ir->ir_set) {
tmp = readl(&ir->ir_set->erst_size);
- tmp &= ERST_SIZE_MASK;
+ tmp &= ~ERST_SIZE_MASK;
writel(tmp, &ir->ir_set->erst_size);
- xhci_write_64(xhci, ERST_EHB, &ir->ir_set->erst_dequeue);
+ xhci_update_erst_dequeue(xhci, ir, true);
}
}
@@ -1848,6 +1877,11 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup
return;
}
+ /*
+ * Cleanup secondary interrupter to ensure there are no pending events.
+ * This also updates event ring dequeue pointer back to the start.
+ */
+ xhci_skip_sec_intr_events(xhci, ir->event_ring, ir);
intr_num = ir->intr_num;
xhci_remove_interrupter(xhci, ir);
@@ -1907,6 +1941,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Freed small stream array pool");
+ dma_pool_destroy(xhci->port_bw_pool);
+ xhci->port_bw_pool = NULL;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Freed xhci port bw array pool");
+
dma_pool_destroy(xhci->medium_streams_pool);
xhci->medium_streams_pool = NULL;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -2282,37 +2321,25 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags)
return ir;
}
-static int
-xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
- unsigned int intr_num)
+void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num)
{
+ struct xhci_interrupter *ir;
u64 erst_base;
u32 erst_size;
- if (intr_num >= xhci->max_interrupters) {
- xhci_warn(xhci, "Can't add interrupter %d, max interrupters %d\n",
- intr_num, xhci->max_interrupters);
- return -EINVAL;
- }
-
- if (xhci->interrupters[intr_num]) {
- xhci_warn(xhci, "Interrupter %d\n already set up", intr_num);
- return -EINVAL;
- }
-
- xhci->interrupters[intr_num] = ir;
+ ir = xhci->interrupters[intr_num];
ir->intr_num = intr_num;
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
/* set ERST count with the number of entries in the segment table */
erst_size = readl(&ir->ir_set->erst_size);
- erst_size &= ERST_SIZE_MASK;
+ erst_size &= ~ERST_SIZE_MASK;
erst_size |= ir->event_ring->num_segs;
writel(erst_size, &ir->ir_set->erst_size);
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
- erst_base &= ERST_BASE_RSVDP;
- erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
+ erst_base &= ~ERST_BASE_ADDRESS_MASK;
+ erst_base |= ir->erst.erst_dma_addr & ERST_BASE_ADDRESS_MASK;
if (xhci->quirks & XHCI_WRITE_64_HI_LO)
hi_lo_writeq(erst_base, &ir->ir_set->erst_base);
else
@@ -2320,20 +2347,19 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
/* Set the event ring dequeue address of this interrupter */
xhci_set_hc_event_deq(xhci, ir);
-
- return 0;
}
struct xhci_interrupter *
xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
- u32 imod_interval)
+ u32 imod_interval, unsigned int intr_num)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_interrupter *ir;
unsigned int i;
int err = -ENOSPC;
- if (!xhci->interrupters || xhci->max_interrupters <= 1)
+ if (!xhci->interrupters || xhci->max_interrupters <= 1 ||
+ intr_num >= xhci->max_interrupters)
return NULL;
ir = xhci_alloc_interrupter(xhci, segs, GFP_KERNEL);
@@ -2341,15 +2367,23 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
return NULL;
spin_lock_irq(&xhci->lock);
-
- /* Find available secondary interrupter, interrupter 0 is reserved for primary */
- for (i = 1; i < xhci->max_interrupters; i++) {
- if (xhci->interrupters[i] == NULL) {
- err = xhci_add_interrupter(xhci, ir, i);
- break;
+ if (!intr_num) {
+ /* Find available secondary interrupter, interrupter 0 is reserved for primary */
+ for (i = 1; i < xhci->max_interrupters; i++) {
+ if (!xhci->interrupters[i]) {
+ xhci->interrupters[i] = ir;
+ xhci_add_interrupter(xhci, i);
+ err = 0;
+ break;
+ }
+ }
+ } else {
+ if (!xhci->interrupters[intr_num]) {
+ xhci->interrupters[intr_num] = ir;
+ xhci_add_interrupter(xhci, intr_num);
+ err = 0;
}
}
-
spin_unlock_irq(&xhci->lock);
if (err) {
@@ -2359,78 +2393,32 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
return NULL;
}
- err = xhci_set_interrupter_moderation(ir, imod_interval);
- if (err)
- xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n",
- i, imod_interval);
+ xhci_set_interrupter_moderation(ir, imod_interval);
xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
- i, xhci->max_interrupters);
+ ir->intr_num, xhci->max_interrupters);
return ir;
}
EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
-static void xhci_hcd_page_size(struct xhci_hcd *xhci)
-{
- u32 page_size;
-
- page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK;
- if (!is_power_of_2(page_size)) {
- xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size);
- /* Fallback to 4K page size, since that's common */
- page_size = 1;
- }
-
- xhci->page_size = page_size << 12;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK",
- xhci->page_size >> 10);
-}
-
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
- struct xhci_interrupter *ir;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
dma_addr_t dma;
- unsigned int val, val2;
- u64 val_64;
- u32 temp;
- int i;
-
- INIT_LIST_HEAD(&xhci->cmd_list);
-
- /* init command timeout work */
- INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
- init_completion(&xhci->cmd_ring_stop_completion);
-
- xhci_hcd_page_size(xhci);
-
- /*
- * Program the Number of Device Slots Enabled field in the CONFIG
- * register with the max value of slots the HC can handle.
- */
- val = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1));
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// xHC can handle at most %d device slots.", val);
- val2 = readl(&xhci->op_regs->config_reg);
- val |= (val2 & ~HCS_SLOTS_MASK);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Setting Max device slots reg = 0x%x.", val);
- writel(val, &xhci->op_regs->config_reg);
/*
* xHCI section 5.4.6 - Device Context array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
- xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
- flags);
+ xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, flags);
if (!xhci->dcbaa)
goto fail;
+
xhci->dcbaa->dma = dma;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Device context base array address = 0x%pad (DMA), %p (virt)",
- &xhci->dcbaa->dma, xhci->dcbaa);
- xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
+ "Device context base array address = 0x%pad (DMA), %p (virt)",
+ &xhci->dcbaa->dma, xhci->dcbaa);
/*
* Initialize the ring segment pool. The ring must be a contiguous
@@ -2446,92 +2434,77 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
else
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size);
+ if (!xhci->segment_pool)
+ goto fail;
/* See Table 46 and Note on Figure 55 */
- xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
- 2112, 64, xhci->page_size);
- if (!xhci->segment_pool || !xhci->device_pool)
+ xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, 2112, 64,
+ xhci->page_size);
+ if (!xhci->device_pool)
goto fail;
- /* Linear stream context arrays don't have any boundary restrictions,
+ /*
+ * Linear stream context arrays don't have any boundary restrictions,
* and only need to be 16-byte aligned.
*/
- xhci->small_streams_pool =
- dma_pool_create("xHCI 256 byte stream ctx arrays",
- dev, SMALL_STREAM_ARRAY_SIZE, 16, 0);
- xhci->medium_streams_pool =
- dma_pool_create("xHCI 1KB stream ctx arrays",
- dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0);
- /* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE
- * will be allocated with dma_alloc_coherent()
+ xhci->small_streams_pool = dma_pool_create("xHCI 256 byte stream ctx arrays",
+ dev, SMALL_STREAM_ARRAY_SIZE, 16, 0);
+ if (!xhci->small_streams_pool)
+ goto fail;
+
+ /*
+ * Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE will be
+ * allocated with dma_alloc_coherent().
*/
- if (!xhci->small_streams_pool || !xhci->medium_streams_pool)
+ xhci->medium_streams_pool = dma_pool_create("xHCI 1KB stream ctx arrays",
+ dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0);
+ if (!xhci->medium_streams_pool)
+ goto fail;
+
+ /*
+ * refer to xhci rev1_2 protocol 5.3.3 max ports is 255.
+ * refer to xhci rev1_2 protocol 6.4.3.14 port bandwidth buffer need
+ * to be 16-byte aligned.
+ */
+ xhci->port_bw_pool = dma_pool_create("xHCI 256 port bw ctx arrays",
+ dev, GET_PORT_BW_ARRAY_SIZE, 16, 0);
+ if (!xhci->port_bw_pool)
goto fail;
/* Set up the command ring to have one segments for now. */
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, 0, flags);
if (!xhci->cmd_ring)
goto fail;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Allocated command ring at %p", xhci->cmd_ring);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad",
- &xhci->cmd_ring->first_seg->dma);
- /* Set the address in the Command Ring Control register */
- val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
- val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
- (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
- xhci->cmd_ring->cycle_state;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Setting command ring address to 0x%016llx", val_64);
- xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad",
+ &xhci->cmd_ring->first_seg->dma);
- /* Reserve one command ring TRB for disabling LPM.
+ /*
+ * Reserve one command ring TRB for disabling LPM.
* Since the USB core grabs the shared usb_bus bandwidth mutex before
* disabling LPM, we only need to reserve one TRB for all devices.
*/
xhci->cmd_ring_reserved_trbs++;
- val = readl(&xhci->cap_regs->db_off);
- val &= DBOFF_MASK;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Doorbell array is located at offset 0x%x from cap regs base addr",
- val);
- xhci->dba = (void __iomem *) xhci->cap_regs + val;
-
/* Allocate and set up primary interrupter 0 with an event ring. */
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Allocating primary event ring");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating primary event ring");
xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
flags, dev_to_node(dev));
-
- ir = xhci_alloc_interrupter(xhci, 0, flags);
- if (!ir)
+ if (!xhci->interrupters)
goto fail;
- if (xhci_add_interrupter(xhci, ir, 0))
+ xhci->interrupters[0] = xhci_alloc_interrupter(xhci, 0, flags);
+ if (!xhci->interrupters[0])
goto fail;
- ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
-
- for (i = 0; i < MAX_HC_SLOTS; i++)
- xhci->devs[i] = NULL;
-
if (scratchpad_alloc(xhci, flags))
goto fail;
+
if (xhci_setup_port_arrays(xhci, flags))
goto fail;
- /* Enable USB 3.0 device notifications for function remote wake, which
- * is necessary for allowing USB 3.0 devices to do remote wakeup from
- * U3 (device suspend).
- */
- temp = readl(&xhci->op_regs->dev_notification);
- temp &= ~DEV_NOTE_MASK;
- temp |= DEV_NOTE_FWAKE;
- writel(temp, &xhci->op_regs->dev_notification);
-
return 0;
fail:
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 3155e3a842da..6dab142e7278 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -267,6 +267,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
device_property_read_u32(tmpdev, "imod-interval-ns",
&xhci->imod_interval);
+ device_property_read_u16(tmpdev, "num-hc-interrupters",
+ &xhci->max_interrupters);
}
/*
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 423bf3649570..e038ad3375dc 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1898,6 +1898,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
case TRB_NEC_GET_FW:
xhci_handle_cmd_nec_get_fw(xhci, event);
break;
+ case TRB_GET_BW:
+ break;
default:
/* Skip over unknown commands on the event ring */
xhci_info(xhci, "INFO unknown command type %d\n", cmd_type);
@@ -2977,9 +2979,6 @@ debug_finding_td:
(unsigned long long)xhci_trb_virt_to_dma(td->start_seg, td->start_trb),
(unsigned long long)xhci_trb_virt_to_dma(td->end_seg, td->end_trb));
- xhci_for_each_ring_seg(ep_ring->first_seg, ep_seg)
- xhci_warn(xhci, "Ring seg %u dma %pad\n", ep_seg->num, &ep_seg->dma);
-
return -ESHUTDOWN;
err_out:
@@ -3050,9 +3049,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter
* - When all events have finished
* - To avoid "Event Ring Full Error" condition
*/
-static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
- struct xhci_interrupter *ir,
- bool clear_ehb)
+void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+ struct xhci_interrupter *ir,
+ bool clear_ehb)
{
u64 temp_64;
dma_addr_t deq;
@@ -3083,11 +3082,14 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
{
if (!ir->ip_autoclear) {
- u32 irq_pending;
+ u32 iman;
+
+ iman = readl(&ir->ir_set->iman);
+ iman |= IMAN_IP;
+ writel(iman, &ir->ir_set->iman);
- irq_pending = readl(&ir->ir_set->irq_pending);
- irq_pending |= IMAN_IP;
- writel(irq_pending, &ir->ir_set->irq_pending);
+ /* Read operation to guarantee the write has been flushed from posted buffers */
+ readl(&ir->ir_set->iman);
}
}
@@ -3095,10 +3097,11 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
* Handle all OS-owned events on an interrupter event ring. It may drop
* and reaquire xhci->lock between event processing.
*/
-static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+ bool skip_events)
{
int event_loop = 0;
- int err;
+ int err = 0;
u64 temp;
xhci_clear_interrupt_pending(ir);
@@ -3121,7 +3124,8 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
/* Process all OS owned event TRBs on this event ring */
while (unhandled_event_trb(ir->event_ring)) {
- err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
+ if (!skip_events)
+ err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
/*
* If half a segment of events have been handled in one go then
@@ -3149,6 +3153,37 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
}
/*
+ * Move the event ring dequeue pointer to skip events kept in the secondary
+ * event ring. This is used to ensure that pending events in the ring are
+ * acknowledged, so the xHCI HCD can properly enter suspend/resume. The
+ * secondary ring is typically maintained by an external component.
+ */
+void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
+ struct xhci_ring *ring, struct xhci_interrupter *ir)
+{
+ union xhci_trb *current_trb;
+ u64 erdp_reg;
+ dma_addr_t deq;
+
+ /* disable irq, ack pending interrupt and ack all pending events */
+ xhci_disable_interrupter(xhci, ir);
+
+ /* last acked event trb is in erdp reg */
+ erdp_reg = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+ deq = (dma_addr_t)(erdp_reg & ERST_PTR_MASK);
+ if (!deq) {
+ xhci_err(xhci, "event ring handling not required\n");
+ return;
+ }
+
+ current_trb = ir->event_ring->dequeue;
+ /* read cycle state of the last acked trb to find out CCS */
+ ring->cycle_state = le32_to_cpu(current_trb->event_cmd.flags) & TRB_CYCLE;
+
+ xhci_handle_events(xhci, ir, true);
+}
+
+/*
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
* indicators of an event TRB error, but we check the status *first* to be safe.
@@ -3192,7 +3227,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
writel(status, &xhci->op_regs->status);
/* This is the handler of the primary interrupter */
- xhci_handle_events(xhci, xhci->interrupters[0]);
+ xhci_handle_events(xhci, xhci->interrupters[0], false);
out:
spin_unlock(&xhci->lock);
@@ -4414,6 +4449,17 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
command_must_succeed);
}
+/* Queue a get root hub port bandwidth command TRB */
+int xhci_queue_get_port_bw(struct xhci_hcd *xhci,
+ struct xhci_command *cmd, dma_addr_t in_ctx_ptr,
+ u8 dev_speed, bool command_must_succeed)
+{
+ return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr),
+ upper_32_bits(in_ctx_ptr), 0,
+ TRB_TYPE(TRB_GET_BW) | DEV_SPEED_FOR_TRB(dev_speed),
+ command_must_succeed);
+}
+
/* Queue an evaluate context command TRB */
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed)
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
new file mode 100644
index 000000000000..d49f9886dd84
--- /dev/null
+++ b/drivers/usb/host/xhci-sideband.c
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * xHCI host controller sideband support
+ *
+ * Copyright (c) 2023-2025, Intel Corporation.
+ *
+ * Author: Mathias Nyman
+ */
+
+#include <linux/usb/xhci-sideband.h>
+#include <linux/dma-direct.h>
+
+#include "xhci.h"
+
+/* sideband internal helpers */
+static struct sg_table *
+xhci_ring_to_sgtable(struct xhci_sideband *sb, struct xhci_ring *ring)
+{
+ struct xhci_segment *seg;
+ struct sg_table *sgt;
+ unsigned int n_pages;
+ struct page **pages;
+ struct device *dev;
+ size_t sz;
+ int i;
+
+ dev = xhci_to_hcd(sb->xhci)->self.sysdev;
+ sz = ring->num_segs * TRB_SEGMENT_SIZE;
+ n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
+ pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ return NULL;
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt) {
+ kvfree(pages);
+ return NULL;
+ }
+
+ seg = ring->first_seg;
+ if (!seg)
+ goto err;
+ /*
+ * Rings can potentially have multiple segments, create an array that
+ * carries page references to allocated segments. Utilize the
+ * sg_alloc_table_from_pages() to create the sg table, and to ensure
+ * that page links are created.
+ */
+ for (i = 0; i < ring->num_segs; i++) {
+ dma_get_sgtable(dev, sgt, seg->trbs, seg->dma,
+ TRB_SEGMENT_SIZE);
+ pages[i] = sg_page(sgt->sgl);
+ sg_free_table(sgt);
+ seg = seg->next;
+ }
+
+ if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL))
+ goto err;
+
+ /*
+ * Save first segment dma address to sg dma_address field for the sideband
+ * client to have access to the IOVA of the ring.
+ */
+ sg_dma_address(sgt->sgl) = ring->first_seg->dma;
+
+ return sgt;
+
+err:
+ kvfree(pages);
+ kfree(sgt);
+
+ return NULL;
+}
+
+static void
+__xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *ep)
+{
+ /*
+ * Issue a stop endpoint command when an endpoint is removed.
+ * The stop ep cmd handler will handle the ring cleanup.
+ */
+ xhci_stop_endpoint_sync(sb->xhci, ep, 0, GFP_KERNEL);
+
+ ep->sideband = NULL;
+ sb->eps[ep->ep_index] = NULL;
+}
+
+/* sideband api functions */
+
+/**
+ * xhci_sideband_notify_ep_ring_free - notify client of xfer ring free
+ * @sb: sideband instance for this usb device
+ * @ep_index: usb endpoint index
+ *
+ * Notifies the xHCI sideband client driver of a xHCI transfer ring free
+ * routine. This will allow for the client to ensure that all transfers
+ * are completed.
+ *
+ * The callback should be synchronous, as the ring free happens after.
+ */
+void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb,
+ unsigned int ep_index)
+{
+ struct xhci_sideband_event evt;
+
+ evt.type = XHCI_SIDEBAND_XFER_RING_FREE;
+ evt.evt_data = &ep_index;
+
+ if (sb->notify_client)
+ sb->notify_client(sb->intf, &evt);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_notify_ep_ring_free);
+
+/**
+ * xhci_sideband_add_endpoint - add endpoint to sideband access list
+ * @sb: sideband instance for this usb device
+ * @host_ep: usb host endpoint
+ *
+ * Adds an endpoint to the list of sideband accessed endpoints for this usb
+ * device.
+ * After an endpoint is added the sideband client can get the endpoint transfer
+ * ring buffer by calling xhci_sideband_endpoint_buffer()
+ *
+ * Return: 0 on success, negative error otherwise.
+ */
+int
+xhci_sideband_add_endpoint(struct xhci_sideband *sb,
+ struct usb_host_endpoint *host_ep)
+{
+ struct xhci_virt_ep *ep;
+ unsigned int ep_index;
+
+ mutex_lock(&sb->mutex);
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = &sb->vdev->eps[ep_index];
+
+ if (ep->ep_state & EP_HAS_STREAMS) {
+ mutex_unlock(&sb->mutex);
+ return -EINVAL;
+ }
+
+ /*
+ * Note, we don't know the DMA mask of the audio DSP device, if its
+ * smaller than for xhci it won't be able to access the endpoint ring
+ * buffer. This could be solved by not allowing the audio class driver
+ * to add the endpoint the normal way, but instead offload it immediately,
+ * and let this function add the endpoint and allocate the ring buffer
+ * with the smallest common DMA mask
+ */
+ if (sb->eps[ep_index] || ep->sideband) {
+ mutex_unlock(&sb->mutex);
+ return -EBUSY;
+ }
+
+ ep->sideband = sb;
+ sb->eps[ep_index] = ep;
+ mutex_unlock(&sb->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_add_endpoint);
+
+/**
+ * xhci_sideband_remove_endpoint - remove endpoint from sideband access list
+ * @sb: sideband instance for this usb device
+ * @host_ep: usb host endpoint
+ *
+ * Removes an endpoint from the list of sideband accessed endpoints for this usb
+ * device.
+ * sideband client should no longer touch the endpoint transfer buffer after
+ * calling this.
+ *
+ * Return: 0 on success, negative error otherwise.
+ */
+int
+xhci_sideband_remove_endpoint(struct xhci_sideband *sb,
+ struct usb_host_endpoint *host_ep)
+{
+ struct xhci_virt_ep *ep;
+ unsigned int ep_index;
+
+ mutex_lock(&sb->mutex);
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = sb->eps[ep_index];
+
+ if (!ep || !ep->sideband || ep->sideband != sb) {
+ mutex_unlock(&sb->mutex);
+ return -ENODEV;
+ }
+
+ __xhci_sideband_remove_endpoint(sb, ep);
+ xhci_initialize_ring_info(ep->ring);
+ mutex_unlock(&sb->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_remove_endpoint);
+
+int
+xhci_sideband_stop_endpoint(struct xhci_sideband *sb,
+ struct usb_host_endpoint *host_ep)
+{
+ struct xhci_virt_ep *ep;
+ unsigned int ep_index;
+
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = sb->eps[ep_index];
+
+ if (!ep || !ep->sideband || ep->sideband != sb)
+ return -EINVAL;
+
+ return xhci_stop_endpoint_sync(sb->xhci, ep, 0, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_stop_endpoint);
+
+/**
+ * xhci_sideband_get_endpoint_buffer - gets the endpoint transfer buffer address
+ * @sb: sideband instance for this usb device
+ * @host_ep: usb host endpoint
+ *
+ * Returns the address of the endpoint buffer where xHC controller reads queued
+ * transfer TRBs from. This is the starting address of the ringbuffer where the
+ * sideband client should write TRBs to.
+ *
+ * Caller needs to free the returned sg_table
+ *
+ * Return: struct sg_table * if successful. NULL otherwise.
+ */
+struct sg_table *
+xhci_sideband_get_endpoint_buffer(struct xhci_sideband *sb,
+ struct usb_host_endpoint *host_ep)
+{
+ struct xhci_virt_ep *ep;
+ unsigned int ep_index;
+
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+ ep = sb->eps[ep_index];
+
+ if (!ep || !ep->ring || !ep->sideband || ep->sideband != sb)
+ return NULL;
+
+ return xhci_ring_to_sgtable(sb, ep->ring);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_get_endpoint_buffer);
+
+/**
+ * xhci_sideband_get_event_buffer - return the event buffer for this device
+ * @sb: sideband instance for this usb device
+ *
+ * If a secondary xhci interupter is set up for this usb device then this
+ * function returns the address of the event buffer where xHC writes
+ * the transfer completion events.
+ *
+ * Caller needs to free the returned sg_table
+ *
+ * Return: struct sg_table * if successful. NULL otherwise.
+ */
+struct sg_table *
+xhci_sideband_get_event_buffer(struct xhci_sideband *sb)
+{
+ if (!sb || !sb->ir)
+ return NULL;
+
+ return xhci_ring_to_sgtable(sb, sb->ir->event_ring);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer);
+
+/**
+ * xhci_sideband_create_interrupter - creates a new interrupter for this sideband
+ * @sb: sideband instance for this usb device
+ * @num_seg: number of event ring segments to allocate
+ * @ip_autoclear: IP autoclearing support such as MSI implemented
+ *
+ * Sets up a xhci interrupter that can be used for this sideband accessed usb
+ * device. Transfer events for this device can be routed to this interrupters
+ * event ring by setting the 'Interrupter Target' field correctly when queueing
+ * the transfer TRBs.
+ * Once this interrupter is created the interrupter target ID can be obtained
+ * by calling xhci_sideband_interrupter_id()
+ *
+ * Returns 0 on success, negative error otherwise
+ */
+int
+xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
+ bool ip_autoclear, u32 imod_interval, int intr_num)
+{
+ int ret = 0;
+
+ if (!sb || !sb->xhci)
+ return -ENODEV;
+
+ mutex_lock(&sb->mutex);
+ if (sb->ir) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ sb->ir = xhci_create_secondary_interrupter(xhci_to_hcd(sb->xhci),
+ num_seg, imod_interval,
+ intr_num);
+ if (!sb->ir) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ sb->ir->ip_autoclear = ip_autoclear;
+
+out:
+ mutex_unlock(&sb->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter);
+
+/**
+ * xhci_sideband_remove_interrupter - remove the interrupter from a sideband
+ * @sb: sideband instance for this usb device
+ *
+ * Removes a registered interrupt for a sideband. This would allow for other
+ * sideband users to utilize this interrupter.
+ */
+void
+xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
+{
+ if (!sb || !sb->ir)
+ return;
+
+ mutex_lock(&sb->mutex);
+ xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir);
+
+ sb->ir = NULL;
+ mutex_unlock(&sb->mutex);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_remove_interrupter);
+
+/**
+ * xhci_sideband_interrupter_id - return the interrupter target id
+ * @sb: sideband instance for this usb device
+ *
+ * If a secondary xhci interrupter is set up for this usb device then this
+ * function returns the ID used by the interrupter. The sideband client
+ * needs to write this ID to the 'Interrupter Target' field of the transfer TRBs
+ * it queues on the endpoints transfer ring to ensure transfer completion event
+ * are written by xHC to the correct interrupter event ring.
+ *
+ * Returns interrupter id on success, negative error othgerwise
+ */
+int
+xhci_sideband_interrupter_id(struct xhci_sideband *sb)
+{
+ if (!sb || !sb->ir)
+ return -ENODEV;
+
+ return sb->ir->intr_num;
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_interrupter_id);
+
+/**
+ * xhci_sideband_register - register a sideband for a usb device
+ * @intf: usb interface associated with the sideband device
+ *
+ * Allows for clients to utilize XHCI interrupters and fetch transfer and event
+ * ring parameters for executing data transfers.
+ *
+ * Return: pointer to a new xhci_sideband instance if successful. NULL otherwise.
+ */
+struct xhci_sideband *
+xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type,
+ int (*notify_client)(struct usb_interface *intf,
+ struct xhci_sideband_event *evt))
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_virt_device *vdev;
+ struct xhci_sideband *sb;
+
+ /*
+ * Make sure the usb device is connected to a xhci controller. Fail
+ * registration if the type is anything other than XHCI_SIDEBAND_VENDOR,
+ * as this is the only type that is currently supported by xhci-sideband.
+ */
+ if (!udev->slot_id || type != XHCI_SIDEBAND_VENDOR)
+ return NULL;
+
+ sb = kzalloc_node(sizeof(*sb), GFP_KERNEL, dev_to_node(hcd->self.sysdev));
+ if (!sb)
+ return NULL;
+
+ mutex_init(&sb->mutex);
+
+ /* check this device isn't already controlled via sideband */
+ spin_lock_irq(&xhci->lock);
+
+ vdev = xhci->devs[udev->slot_id];
+
+ if (!vdev || vdev->sideband) {
+ xhci_warn(xhci, "XHCI sideband for slot %d already in use\n",
+ udev->slot_id);
+ spin_unlock_irq(&xhci->lock);
+ kfree(sb);
+ return NULL;
+ }
+
+ sb->xhci = xhci;
+ sb->vdev = vdev;
+ sb->intf = intf;
+ sb->type = type;
+ sb->notify_client = notify_client;
+ vdev->sideband = sb;
+
+ spin_unlock_irq(&xhci->lock);
+
+ return sb;
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_register);
+
+/**
+ * xhci_sideband_unregister - unregister sideband access to a usb device
+ * @sb: sideband instance to be unregistered
+ *
+ * Unregisters sideband access to a usb device and frees the sideband
+ * instance.
+ * After this the endpoint and interrupter event buffers should no longer
+ * be accessed via sideband. The xhci driver can now take over handling
+ * the buffers.
+ */
+void
+xhci_sideband_unregister(struct xhci_sideband *sb)
+{
+ struct xhci_hcd *xhci;
+ int i;
+
+ if (!sb)
+ return;
+
+ xhci = sb->xhci;
+
+ mutex_lock(&sb->mutex);
+ for (i = 0; i < EP_CTX_PER_DEV; i++)
+ if (sb->eps[i])
+ __xhci_sideband_remove_endpoint(sb, sb->eps[i]);
+ mutex_unlock(&sb->mutex);
+
+ xhci_sideband_remove_interrupter(sb);
+
+ spin_lock_irq(&xhci->lock);
+ sb->xhci = NULL;
+ sb->vdev->sideband = NULL;
+ spin_unlock_irq(&xhci->lock);
+
+ kfree(sb);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_unregister);
+MODULE_DESCRIPTION("xHCI sideband driver for secondary interrupter management");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 90eb491267b5..803047bec3e7 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -20,6 +20,7 @@
#include <linux/string_choices.h>
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/xhci-sideband.h>
#include "xhci.h"
#include "xhci-trace.h"
@@ -329,21 +330,29 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir)
if (!ir || !ir->ir_set)
return -EINVAL;
- iman = readl(&ir->ir_set->irq_pending);
- writel(ER_IRQ_ENABLE(iman), &ir->ir_set->irq_pending);
+ iman = readl(&ir->ir_set->iman);
+ iman |= IMAN_IE;
+ writel(iman, &ir->ir_set->iman);
+ /* Read operation to guarantee the write has been flushed from posted buffers */
+ readl(&ir->ir_set->iman);
return 0;
}
-int xhci_disable_interrupter(struct xhci_interrupter *ir)
+int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
{
u32 iman;
if (!ir || !ir->ir_set)
return -EINVAL;
- iman = readl(&ir->ir_set->irq_pending);
- writel(ER_IRQ_DISABLE(iman), &ir->ir_set->irq_pending);
+ iman = readl(&ir->ir_set->iman);
+ iman &= ~IMAN_IE;
+ writel(iman, &ir->ir_set->iman);
+
+ iman = readl(&ir->ir_set->iman);
+ if (iman & IMAN_IP)
+ xhci_dbg(xhci, "%s: Interrupt pending\n", __func__);
return 0;
}
@@ -354,13 +363,16 @@ int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
{
u32 imod;
- if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250)
+ if (!ir || !ir->ir_set)
return -EINVAL;
- imod = readl(&ir->ir_set->irq_control);
- imod &= ~ER_IRQ_INTERVAL_MASK;
- imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
- writel(imod, &ir->ir_set->irq_control);
+ /* IMODI value in IMOD register is in 250ns increments */
+ imod_interval = umin(imod_interval / 250, IMODI_MASK);
+
+ imod = readl(&ir->ir_set->imod);
+ imod &= ~IMODI_MASK;
+ imod |= imod_interval;
+ writel(imod, &ir->ir_set->imod);
return 0;
}
@@ -460,6 +472,82 @@ static int xhci_all_ports_seen_u0(struct xhci_hcd *xhci)
return (xhci->port_status_u0 == ((1 << xhci->usb3_rhub.num_ports) - 1));
}
+static void xhci_hcd_page_size(struct xhci_hcd *xhci)
+{
+ u32 page_size;
+
+ page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK;
+ if (!is_power_of_2(page_size)) {
+ xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size);
+ /* Fallback to 4K page size, since that's common */
+ page_size = 1;
+ }
+
+ xhci->page_size = page_size << 12;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK",
+ xhci->page_size >> 10);
+}
+
+static void xhci_enable_max_dev_slots(struct xhci_hcd *xhci)
+{
+ u32 config_reg;
+ u32 max_slots;
+
+ max_slots = HCS_MAX_SLOTS(xhci->hcs_params1);
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHC can handle at most %d device slots",
+ max_slots);
+
+ config_reg = readl(&xhci->op_regs->config_reg);
+ config_reg &= ~HCS_SLOTS_MASK;
+ config_reg |= max_slots;
+
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Setting Max device slots reg = 0x%x",
+ config_reg);
+ writel(config_reg, &xhci->op_regs->config_reg);
+}
+
+static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
+{
+ dma_addr_t deq_dma;
+ u64 crcr;
+
+ deq_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, xhci->cmd_ring->dequeue);
+ deq_dma &= CMD_RING_PTR_MASK;
+
+ crcr = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
+ crcr &= ~CMD_RING_PTR_MASK;
+ crcr |= deq_dma;
+
+ crcr &= ~CMD_RING_CYCLE;
+ crcr |= xhci->cmd_ring->cycle_state;
+
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Setting command ring address to 0x%llx", crcr);
+ xhci_write_64(xhci, crcr, &xhci->op_regs->cmd_ring);
+}
+
+static void xhci_set_doorbell_ptr(struct xhci_hcd *xhci)
+{
+ u32 offset;
+
+ offset = readl(&xhci->cap_regs->db_off) & DBOFF_MASK;
+ xhci->dba = (void __iomem *)xhci->cap_regs + offset;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Doorbell array is located at offset 0x%x from cap regs base addr", offset);
+}
+
+/*
+ * Enable USB 3.0 device notifications for function remote wake, which is necessary
+ * for allowing USB 3.0 devices to do remote wakeup from U3 (device suspend).
+ */
+static void xhci_set_dev_notifications(struct xhci_hcd *xhci)
+{
+ u32 dev_notf;
+
+ dev_notf = readl(&xhci->op_regs->dev_notification);
+ dev_notf &= ~DEV_NOTE_MASK;
+ dev_notf |= DEV_NOTE_FWAKE;
+ writel(dev_notf, &xhci->op_regs->dev_notification);
+}
/*
* Initialize memory for HCD and xHC (one-time init).
@@ -473,11 +561,37 @@ static int xhci_init(struct usb_hcd *hcd)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int retval;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Starting %s", __func__);
spin_lock_init(&xhci->lock);
+ INIT_LIST_HEAD(&xhci->cmd_list);
+ INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
+ init_completion(&xhci->cmd_ring_stop_completion);
+ xhci_hcd_page_size(xhci);
+ memset(xhci->devs, 0, MAX_HC_SLOTS * sizeof(*xhci->devs));
+
retval = xhci_mem_init(xhci, GFP_KERNEL);
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init");
+ if (retval)
+ return retval;
+
+ /* Set the Number of Device Slots Enabled to the maximum supported value */
+ xhci_enable_max_dev_slots(xhci);
+
+ /* Set the address in the Command Ring Control register */
+ xhci_set_cmd_ring_deq(xhci);
+
+ /* Set Device Context Base Address Array pointer */
+ xhci_write_64(xhci, xhci->dcbaa->dma, &xhci->op_regs->dcbaa_ptr);
+
+ /* Set Doorbell array pointer */
+ xhci_set_doorbell_ptr(xhci);
+
+ /* Set USB 3.0 device notifications for function remote wake */
+ xhci_set_dev_notifications(xhci);
+
+ /* Initialize the Primary interrupter */
+ xhci_add_interrupter(xhci, 0);
+ xhci->interrupters[0]->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
/* Initializing Compliance Mode Recovery Data If Needed */
if (xhci_compliance_mode_recovery_timer_quirk_check()) {
@@ -485,7 +599,8 @@ static int xhci_init(struct usb_hcd *hcd)
compliance_mode_recovery_timer_init(xhci);
}
- return retval;
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished %s", __func__);
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -640,7 +755,7 @@ void xhci_stop(struct usb_hcd *hcd)
"// Disabling event ring interrupts");
temp = readl(&xhci->op_regs->status);
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
- xhci_disable_interrupter(ir);
+ xhci_disable_interrupter(xhci, ir);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
xhci_mem_cleanup(xhci);
@@ -719,8 +834,8 @@ static void xhci_save_registers(struct xhci_hcd *xhci)
ir->s3_erst_size = readl(&ir->ir_set->erst_size);
ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
- ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
- ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+ ir->s3_iman = readl(&ir->ir_set->iman);
+ ir->s3_imod = readl(&ir->ir_set->imod);
}
}
@@ -743,28 +858,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
writel(ir->s3_erst_size, &ir->ir_set->erst_size);
xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
- writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
- writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+ writel(ir->s3_iman, &ir->ir_set->iman);
+ writel(ir->s3_imod, &ir->ir_set->imod);
}
}
-static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
-{
- u64 val_64;
-
- /* step 2: initialize command ring buffer */
- val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
- val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
- (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
- xhci->cmd_ring->dequeue) &
- (u64) ~CMD_RING_RSVD_BITS) |
- xhci->cmd_ring->cycle_state;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "// Setting command ring address to 0x%llx",
- (long unsigned long) val_64);
- xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
-}
-
/*
* The whole command ring must be cleared to zero when we suspend the host.
*
@@ -1092,7 +1190,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = readl(&xhci->op_regs->status);
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
- xhci_disable_interrupter(xhci->interrupters[0]);
+ xhci_disable_interrupter(xhci, xhci->interrupters[0]);
xhci_dbg(xhci, "cleaning up memory\n");
xhci_mem_cleanup(xhci);
@@ -1359,6 +1457,7 @@ static void xhci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
* xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
* HCDs. Find the index for an endpoint given its descriptor. Use the return
* value to right shift 1 for the bitmask.
+ * @desc: USB endpoint descriptor to determine index for
*
* Index = (epnum * 2) + direction - 1,
* where direction = 0 for OUT, 1 for IN.
@@ -3089,6 +3188,42 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(xhci_reset_bandwidth);
+/* Get the available bandwidth of the ports under the xhci roothub */
+int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+ u8 dev_speed)
+{
+ struct xhci_command *cmd;
+ unsigned long flags;
+ int ret;
+
+ if (!ctx || !xhci)
+ return -EINVAL;
+
+ cmd = xhci_alloc_command(xhci, true, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->in_ctx = ctx;
+
+ /* get xhci port bandwidth, refer to xhci rev1_2 protocol 4.6.15 */
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ ret = xhci_queue_get_port_bw(xhci, cmd, ctx->dma, dev_speed, 0);
+ if (ret) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto err_out;
+ }
+ xhci_ring_cmd_db(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ wait_for_completion(cmd->completion);
+err_out:
+ kfree(cmd->completion);
+ kfree(cmd);
+
+ return ret;
+}
+
static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
@@ -3911,6 +4046,8 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
if (ep->ring) {
+ if (ep->sideband)
+ xhci_sideband_notify_ep_ring_free(ep->sideband, i);
xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
xhci_free_endpoint_ring(xhci, virt_dev, i);
}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 242ab9fbc8ae..49887a303e43 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -152,10 +152,6 @@ struct xhci_op_regs {
#define XHCI_RESET_LONG_USEC (10 * 1000 * 1000)
#define XHCI_RESET_SHORT_USEC (250 * 1000)
-/* IMAN - Interrupt Management Register */
-#define IMAN_IE (1 << 1)
-#define IMAN_IP (1 << 0)
-
/* USBSTS - USB status - status bitmasks */
/* HC not running - set to 1 when run/stop bit is cleared. */
#define STS_HALT XHCI_STS_HALT
@@ -184,23 +180,22 @@ struct xhci_op_regs {
* notification type that matches a bit set in this bit field.
*/
#define DEV_NOTE_MASK (0xffff)
-#define ENABLE_DEV_NOTE(x) (1 << (x))
/* Most of the device notification types should only be used for debug.
* SW does need to pay attention to function wake notifications.
*/
-#define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1)
+#define DEV_NOTE_FWAKE (1 << 1)
/* CRCR - Command Ring Control Register - cmd_ring bitmasks */
-/* bit 0 is the command ring cycle state */
+/* bit 0 - Cycle bit indicates the ownership of the command ring */
+#define CMD_RING_CYCLE (1 << 0)
/* stop ring operation after completion of the currently executing command */
#define CMD_RING_PAUSE (1 << 1)
/* stop ring immediately - abort the currently executing command */
#define CMD_RING_ABORT (1 << 2)
/* true: command ring is running */
#define CMD_RING_RUNNING (1 << 3)
-/* bits 4:5 reserved and should be preserved */
-/* Command Ring pointer - bit mask for the lower 32 bits. */
-#define CMD_RING_RSVD_BITS (0x3f)
+/* bits 63:6 - Command Ring pointer */
+#define CMD_RING_PTR_MASK GENMASK_ULL(63, 6)
/* CONFIG - Configure Register - config_reg bitmasks */
/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
@@ -215,14 +210,13 @@ struct xhci_op_regs {
#define XHCI_PAGE_SIZE_MASK 0xffff
/**
- * struct xhci_intr_reg - Interrupt Register Set
- * @irq_pending: IMAN - Interrupt Management Register. Used to enable
+ * struct xhci_intr_reg - Interrupt Register Set, v1.2 section 5.5.2.
+ * @iman: IMAN - Interrupt Management Register. Used to enable
* interrupts and check for pending interrupts.
- * @irq_control: IMOD - Interrupt Moderation Register.
- * Used to throttle interrupts.
- * @erst_size: Number of segments in the Event Ring Segment Table (ERST).
- * @erst_base: ERST base address.
- * @erst_dequeue: Event ring dequeue pointer.
+ * @imod: IMOD - Interrupt Moderation Register. Used to throttle interrupts.
+ * @erst_size: ERSTSZ - Number of segments in the Event Ring Segment Table (ERST).
+ * @erst_base: ERSTBA - Event ring segment table base address.
+ * @erst_dequeue: ERDP - Event ring dequeue pointer.
*
* Each interrupter (defined by a MSI-X vector) has an event ring and an Event
* Ring Segment Table (ERST) associated with it. The event ring is comprised of
@@ -232,48 +226,51 @@ struct xhci_op_regs {
* updates the dequeue pointer.
*/
struct xhci_intr_reg {
- __le32 irq_pending;
- __le32 irq_control;
+ __le32 iman;
+ __le32 imod;
__le32 erst_size;
__le32 rsvd;
__le64 erst_base;
__le64 erst_dequeue;
};
-/* irq_pending bitmasks */
-#define ER_IRQ_PENDING(p) ((p) & 0x1)
-/* bits 2:31 need to be preserved */
-/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */
-#define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe)
-#define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2)
-#define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2))
-
-/* irq_control bitmasks */
-/* Minimum interval between interrupts (in 250ns intervals). The interval
- * between interrupts will be longer if there are no events on the event ring.
- * Default is 4000 (1 ms).
+/* iman bitmasks */
+/* bit 0 - Interrupt Pending (IP), whether there is an interrupt pending. Write-1-to-clear. */
+#define IMAN_IP (1 << 0)
+/* bit 1 - Interrupt Enable (IE), whether the interrupter is capable of generating an interrupt */
+#define IMAN_IE (1 << 1)
+
+/* imod bitmasks */
+/*
+ * bits 15:0 - Interrupt Moderation Interval, the minimum interval between interrupts
+ * (in 250ns intervals). The interval between interrupts will be longer if there are no
+ * events on the event ring. Default is 4000 (1 ms).
*/
-#define ER_IRQ_INTERVAL_MASK (0xffff)
-/* Counter used to count down the time to the next interrupt - HW use only */
-#define ER_IRQ_COUNTER_MASK (0xffff << 16)
+#define IMODI_MASK (0xffff)
+/* bits 31:16 - Interrupt Moderation Counter, used to count down the time to the next interrupt */
+#define IMODC_MASK (0xffff << 16)
/* erst_size bitmasks */
-/* Preserve bits 16:31 of erst_size */
-#define ERST_SIZE_MASK (0xffff << 16)
+/* bits 15:0 - Event Ring Segment Table Size, number of ERST entries */
+#define ERST_SIZE_MASK (0xffff)
/* erst_base bitmasks */
-#define ERST_BASE_RSVDP (GENMASK_ULL(5, 0))
+/* bits 63:6 - Event Ring Segment Table Base Address Register */
+#define ERST_BASE_ADDRESS_MASK GENMASK_ULL(63, 6)
/* erst_dequeue bitmasks */
-/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
- * where the current dequeue pointer lies. This is an optional HW hint.
+/*
+ * bits 2:0 - Dequeue ERST Segment Index (DESI), is the segment number (or alias) where the
+ * current dequeue pointer lies. This is an optional HW hint.
*/
#define ERST_DESI_MASK (0x7)
-/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by
+/*
+ * bit 3 - Event Handler Busy (EHB), whether the event ring is scheduled to be serviced by
* a work queue (or delayed service routine)?
*/
#define ERST_EHB (1 << 3)
-#define ERST_PTR_MASK (GENMASK_ULL(63, 4))
+/* bits 63:4 - Event Ring Dequeue Pointer */
+#define ERST_PTR_MASK GENMASK_ULL(63, 4)
/**
* struct xhci_run_regs
@@ -589,6 +586,7 @@ struct xhci_stream_info {
#define SMALL_STREAM_ARRAY_SIZE 256
#define MEDIUM_STREAM_ARRAY_SIZE 1024
+#define GET_PORT_BW_ARRAY_SIZE 256
/* Some Intel xHCI host controllers need software to keep track of the bus
* bandwidth. Keep track of endpoint info here. Each root port is allocated
@@ -700,6 +698,8 @@ struct xhci_virt_ep {
int next_frame_id;
/* Use new Isoch TRB layout needed for extended TBC support */
bool use_extended_tbc;
+ /* set if this endpoint is controlled via sideband access*/
+ struct xhci_sideband *sideband;
};
enum xhci_overhead_type {
@@ -762,6 +762,8 @@ struct xhci_virt_device {
u16 current_mel;
/* Used for the debugfs interfaces. */
void *debugfs_private;
+ /* set if this endpoint is controlled via sideband access*/
+ struct xhci_sideband *sideband;
};
/*
@@ -1002,6 +1004,9 @@ enum xhci_setup_dev {
/* bits 16:23 are the virtual function ID */
/* bits 24:31 are the slot ID */
+/* bits 19:16 are the dev speed */
+#define DEV_SPEED_FOR_TRB(p) ((p) << 16)
+
/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23)
#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
@@ -1447,8 +1452,8 @@ struct xhci_interrupter {
bool ip_autoclear;
u32 isoc_bei_interval;
/* For interrupter registers save and restore over suspend/resume */
- u32 s3_irq_pending;
- u32 s3_irq_control;
+ u32 s3_iman;
+ u32 s3_imod;
u32 s3_erst_size;
u64 s3_erst_base;
u64 s3_erst_dequeue;
@@ -1554,6 +1559,7 @@ struct xhci_hcd {
struct dma_pool *device_pool;
struct dma_pool *segment_pool;
struct dma_pool *small_streams_pool;
+ struct dma_pool *port_bw_pool;
struct dma_pool *medium_streams_pool;
/* Host controller watchdog timer structures */
@@ -1846,11 +1852,18 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
int type, gfp_t flags);
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx);
+struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci,
+ gfp_t flags);
+void xhci_free_port_bw_ctx(struct xhci_hcd *xhci,
+ struct xhci_container_ctx *ctx);
struct xhci_interrupter *
xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
- u32 imod_interval);
+ u32 imod_interval, unsigned int intr_num);
void xhci_remove_secondary_interrupter(struct usb_hcd
*hcd, struct xhci_interrupter *ir);
+void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
+ struct xhci_ring *ring,
+ struct xhci_interrupter *ir);
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
@@ -1891,7 +1904,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
u32 imod_interval);
int xhci_enable_interrupter(struct xhci_interrupter *ir);
-int xhci_disable_interrupter(struct xhci_interrupter *ir);
+int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir);
/* xHCI ring, segment, TRB, and TD functions */
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
@@ -1916,6 +1929,11 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id,
bool command_must_succeed);
+int xhci_queue_get_port_bw(struct xhci_hcd *xhci,
+ struct xhci_command *cmd, dma_addr_t in_ctx_ptr,
+ u8 dev_speed, bool command_must_succeed);
+int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+ u8 dev_speed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,
@@ -1936,6 +1954,10 @@ unsigned int count_trbs(u64 addr, u64 len);
int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
int suspend, gfp_t gfp_flags);
void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);
+void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
+ struct xhci_interrupter *ir,
+ bool clear_ehb);
+void xhci_add_interrupter(struct xhci_hcd *xhci, unsigned int intr_num);
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c
index f5372dfa241a..5b481876af1b 100644
--- a/drivers/usb/misc/onboard_usb_dev.c
+++ b/drivers/usb/misc/onboard_usb_dev.c
@@ -36,9 +36,10 @@
#define USB5744_CMD_CREG_ACCESS 0x99
#define USB5744_CMD_CREG_ACCESS_LSB 0x37
#define USB5744_CREG_MEM_ADDR 0x00
+#define USB5744_CREG_MEM_RD_ADDR 0x04
#define USB5744_CREG_WRITE 0x00
-#define USB5744_CREG_RUNTIMEFLAGS2 0x41
-#define USB5744_CREG_RUNTIMEFLAGS2_LSB 0x1D
+#define USB5744_CREG_READ 0x01
+#define USB5744_CREG_RUNTIMEFLAGS2 0x411D
#define USB5744_CREG_BYPASS_UDC_SUSPEND BIT(3)
static void onboard_dev_attach_usb_driver(struct work_struct *work);
@@ -309,11 +310,88 @@ static void onboard_dev_attach_usb_driver(struct work_struct *work)
pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));
}
+#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744)
+static int onboard_dev_5744_i2c_read_byte(struct i2c_client *client, u16 addr, u8 *data)
+{
+ struct i2c_msg msg[2];
+ u8 rd_buf[3];
+ int ret;
+
+ u8 wr_buf[7] = {0, USB5744_CREG_MEM_ADDR, 4,
+ USB5744_CREG_READ, 1,
+ addr >> 8 & 0xff,
+ addr & 0xff};
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = sizeof(wr_buf);
+ msg[0].buf = wr_buf;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0)
+ return ret;
+
+ wr_buf[0] = USB5744_CMD_CREG_ACCESS;
+ wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
+ wr_buf[2] = 0;
+ msg[0].len = 3;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0)
+ return ret;
+
+ wr_buf[0] = 0;
+ wr_buf[1] = USB5744_CREG_MEM_RD_ADDR;
+ msg[0].len = 2;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = rd_buf;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ return ret;
+ *data = rd_buf[1];
+
+ return 0;
+}
+
+static int onboard_dev_5744_i2c_write_byte(struct i2c_client *client, u16 addr, u8 data)
+{
+ struct i2c_msg msg[2];
+ int ret;
+
+ u8 wr_buf[8] = {0, USB5744_CREG_MEM_ADDR, 5,
+ USB5744_CREG_WRITE, 1,
+ addr >> 8 & 0xff,
+ addr & 0xff,
+ data};
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = sizeof(wr_buf);
+ msg[0].buf = wr_buf;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0)
+ return ret;
+
+ msg[0].len = 3;
+ wr_buf[0] = USB5744_CMD_CREG_ACCESS;
+ wr_buf[1] = USB5744_CMD_CREG_ACCESS_LSB;
+ wr_buf[2] = 0;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int onboard_dev_5744_i2c_init(struct i2c_client *client)
{
-#if IS_ENABLED(CONFIG_USB_ONBOARD_DEV_USB5744)
struct device *dev = &client->dev;
int ret;
+ u8 reg;
/*
* Set BYPASS_UDC_SUSPEND bit to ensure MCU is always enabled
@@ -321,20 +399,16 @@ static int onboard_dev_5744_i2c_init(struct i2c_client *client)
* The command writes 5 bytes to memory and single data byte in
* configuration register.
*/
- char wr_buf[7] = {USB5744_CREG_MEM_ADDR, 5,
- USB5744_CREG_WRITE, 1,
- USB5744_CREG_RUNTIMEFLAGS2,
- USB5744_CREG_RUNTIMEFLAGS2_LSB,
- USB5744_CREG_BYPASS_UDC_SUSPEND};
-
- ret = i2c_smbus_write_block_data(client, 0, sizeof(wr_buf), wr_buf);
+ ret = onboard_dev_5744_i2c_read_byte(client,
+ USB5744_CREG_RUNTIMEFLAGS2, &reg);
if (ret)
- return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n");
+ return dev_err_probe(dev, ret, "CREG_RUNTIMEFLAGS2 read failed\n");
- ret = i2c_smbus_write_word_data(client, USB5744_CMD_CREG_ACCESS,
- USB5744_CMD_CREG_ACCESS_LSB);
+ reg |= USB5744_CREG_BYPASS_UDC_SUSPEND;
+ ret = onboard_dev_5744_i2c_write_byte(client,
+ USB5744_CREG_RUNTIMEFLAGS2, reg);
if (ret)
- return dev_err_probe(dev, ret, "Configuration Register Access Command failed\n");
+ return dev_err_probe(dev, ret, "BYPASS_UDC_SUSPEND bit configuration failed\n");
/* Send SMBus command to boot hub. */
ret = i2c_smbus_write_word_data(client, USB5744_CMD_ATTACH,
@@ -343,10 +417,13 @@ static int onboard_dev_5744_i2c_init(struct i2c_client *client)
return dev_err_probe(dev, ret, "USB Attach with SMBus command failed\n");
return ret;
+}
#else
+static int onboard_dev_5744_i2c_init(struct i2c_client *client)
+{
return -ENODEV;
-#endif
}
+#endif
static int onboard_dev_probe(struct platform_device *pdev)
{
@@ -490,6 +567,7 @@ static struct platform_driver onboard_dev_driver = {
#define VENDOR_ID_CYPRESS 0x04b4
#define VENDOR_ID_GENESYS 0x05e3
#define VENDOR_ID_MICROCHIP 0x0424
+#define VENDOR_ID_PARADE 0x1da0
#define VENDOR_ID_REALTEK 0x0bda
#define VENDOR_ID_TI 0x0451
#define VENDOR_ID_VIA 0x2109
@@ -586,14 +664,19 @@ static const struct usb_device_id onboard_dev_id_table[] = {
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 HUB */
+ { USB_DEVICE(VENDOR_ID_PARADE, 0x5511) }, /* PS5511 USB 3.2 */
+ { USB_DEVICE(VENDOR_ID_PARADE, 0x55a1) }, /* PS5511 USB 2.0 */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 HUB */
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 HUB */
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0179) }, /* RTL8188ETV 2.4GHz WiFi */
{ USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 HUB */
{ USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 HUB */
+ { USB_DEVICE(VENDOR_ID_TI, 0x8440) }, /* TI USB8044 3.0 HUB */
+ { USB_DEVICE(VENDOR_ID_TI, 0x8442) }, /* TI USB8044 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 HUB */
{ USB_DEVICE(VENDOR_ID_VIA, 0x2817) }, /* VIA VL817 2.0 HUB */
{ USB_DEVICE(VENDOR_ID_XMOS, 0x0013) }, /* XMOS XVF3500 Voice Processor */
diff --git a/drivers/usb/misc/onboard_usb_dev.h b/drivers/usb/misc/onboard_usb_dev.h
index 933797a7e084..e017b8e22f93 100644
--- a/drivers/usb/misc/onboard_usb_dev.h
+++ b/drivers/usb/misc/onboard_usb_dev.h
@@ -38,6 +38,13 @@ static const struct onboard_dev_pdata microchip_usb5744_data = {
.is_hub = true,
};
+static const struct onboard_dev_pdata parade_ps5511_data = {
+ .reset_us = 500,
+ .num_supplies = 2,
+ .supply_names = { "vddd11", "vdd33"},
+ .is_hub = true,
+};
+
static const struct onboard_dev_pdata realtek_rts5411_data = {
.reset_us = 0,
.num_supplies = 1,
@@ -45,6 +52,13 @@ static const struct onboard_dev_pdata realtek_rts5411_data = {
.is_hub = true,
};
+static const struct onboard_dev_pdata realtek_rtl8188etv_data = {
+ .reset_us = 0,
+ .num_supplies = 1,
+ .supply_names = { "vdd" },
+ .is_hub = false,
+};
+
static const struct onboard_dev_pdata ti_tusb8020b_data = {
.reset_us = 3000,
.num_supplies = 1,
@@ -111,6 +125,8 @@ static const struct of_device_id onboard_dev_match[] = {
{ .compatible = "usb451,8027", .data = &ti_tusb8020b_data, },
{ .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
{ .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
+ { .compatible = "usb451,8440", .data = &ti_tusb8041_data, },
+ { .compatible = "usb451,8442", .data = &ti_tusb8041_data, },
{ .compatible = "usb4b4,6504", .data = &cypress_hx3_data, },
{ .compatible = "usb4b4,6506", .data = &cypress_hx3_data, },
{ .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, },
@@ -118,10 +134,13 @@ static const struct of_device_id onboard_dev_match[] = {
{ .compatible = "usb5e3,610", .data = &genesys_gl852g_data, },
{ .compatible = "usb5e3,620", .data = &genesys_gl852g_data, },
{ .compatible = "usb5e3,626", .data = &genesys_gl852g_data, },
+ { .compatible = "usbbda,179", .data = &realtek_rtl8188etv_data, },
{ .compatible = "usbbda,411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,414", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5414", .data = &realtek_rts5411_data, },
+ { .compatible = "usb1da0,5511", .data = &parade_ps5511_data, },
+ { .compatible = "usb1da0,55a1", .data = &parade_ps5511_data, },
{ .compatible = "usb2109,817", .data = &vialab_vl817_data, },
{ .compatible = "usb2109,2817", .data = &vialab_vl817_data, },
{ .compatible = "usb20b1,0013", .data = &xmos_xvf3500_data, },
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 5f629d7cad64..b7acf3966cd7 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -126,18 +126,6 @@ config USB_ISP1301
To compile this driver as a module, choose M here: the
module will be called phy-isp1301.
-config USB_MV_OTG
- tristate "Marvell USB OTG support"
- depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
- depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
- select USB_PHY
- help
- Say Y here if you want to build Marvell USB OTG transceiver
- driver in kernel (including PXA and MMP series). This driver
- implements role switch between EHCI host driver and gadget driver.
-
- To compile this driver as a module, choose M here.
-
config USB_MXS_PHY
tristate "Freescale MXS USB PHY support"
depends on ARCH_MXC || ARCH_MXS
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index e5d619b4d8f6..ceae46c5341d 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o
obj-$(CONFIG_USB_TEGRA_PHY) += phy-tegra-usb.o
obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o
obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
-obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o
obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
deleted file mode 100644
index 638fba58420c..000000000000
--- a/drivers/usb/phy/phy-mv-usb.c
+++ /dev/null
@@ -1,881 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
- * Author: Chao Xie <chao.xie@marvell.com>
- * Neil Zhang <zhangwm@marvell.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/uaccess.h>
-#include <linux/device.h>
-#include <linux/proc_fs.h>
-#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/string_choices.h>
-
-#include <linux/usb.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/hcd.h>
-#include <linux/platform_data/mv_usb.h>
-
-#include "phy-mv-usb.h"
-
-#define DRIVER_DESC "Marvell USB OTG transceiver driver"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-static const char driver_name[] = "mv-otg";
-
-static char *state_string[] = {
- "undefined",
- "b_idle",
- "b_srp_init",
- "b_peripheral",
- "b_wait_acon",
- "b_host",
- "a_idle",
- "a_wait_vrise",
- "a_wait_bcon",
- "a_host",
- "a_suspend",
- "a_peripheral",
- "a_wait_vfall",
- "a_vbus_err"
-};
-
-static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
-{
- struct mv_otg *mvotg = container_of(otg->usb_phy, struct mv_otg, phy);
- if (mvotg->pdata->set_vbus == NULL)
- return -ENODEV;
-
- return mvotg->pdata->set_vbus(on);
-}
-
-static int mv_otg_set_host(struct usb_otg *otg,
- struct usb_bus *host)
-{
- otg->host = host;
-
- return 0;
-}
-
-static int mv_otg_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
-{
- otg->gadget = gadget;
-
- return 0;
-}
-
-static void mv_otg_run_state_machine(struct mv_otg *mvotg,
- unsigned long delay)
-{
- dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n");
- if (!mvotg->qwork)
- return;
-
- queue_delayed_work(mvotg->qwork, &mvotg->work, delay);
-}
-
-static void mv_otg_timer_await_bcon(struct timer_list *t)
-{
- struct mv_otg *mvotg = from_timer(mvotg, t,
- otg_ctrl.timer[A_WAIT_BCON_TIMER]);
-
- mvotg->otg_ctrl.a_wait_bcon_timeout = 1;
-
- dev_info(&mvotg->pdev->dev, "B Device No Response!\n");
-
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 0);
- spin_unlock(&mvotg->wq_lock);
- }
-}
-
-static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id)
-{
- struct timer_list *timer;
-
- if (id >= OTG_TIMER_NUM)
- return -EINVAL;
-
- timer = &mvotg->otg_ctrl.timer[id];
-
- if (timer_pending(timer))
- timer_delete(timer);
-
- return 0;
-}
-
-static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id,
- unsigned long interval)
-{
- struct timer_list *timer;
-
- if (id >= OTG_TIMER_NUM)
- return -EINVAL;
-
- timer = &mvotg->otg_ctrl.timer[id];
- if (timer_pending(timer)) {
- dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id);
- return -EBUSY;
- }
-
- timer->expires = jiffies + interval;
- add_timer(timer);
-
- return 0;
-}
-
-static int mv_otg_reset(struct mv_otg *mvotg)
-{
- u32 tmp;
- int ret;
-
- /* Stop the controller */
- tmp = readl(&mvotg->op_regs->usbcmd);
- tmp &= ~USBCMD_RUN_STOP;
- writel(tmp, &mvotg->op_regs->usbcmd);
-
- /* Reset the controller to get default values */
- writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd);
-
- ret = readl_poll_timeout_atomic(&mvotg->op_regs->usbcmd, tmp,
- (tmp & USBCMD_CTRL_RESET), 10, 10000);
- if (ret < 0) {
- dev_err(&mvotg->pdev->dev,
- "Wait for RESET completed TIMEOUT\n");
- return ret;
- }
-
- writel(0x0, &mvotg->op_regs->usbintr);
- tmp = readl(&mvotg->op_regs->usbsts);
- writel(tmp, &mvotg->op_regs->usbsts);
-
- return 0;
-}
-
-static void mv_otg_init_irq(struct mv_otg *mvotg)
-{
- u32 otgsc;
-
- mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID
- | OTGSC_INTR_A_VBUS_VALID;
- mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
- | OTGSC_INTSTS_A_VBUS_VALID;
-
- if (mvotg->pdata->vbus == NULL) {
- mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
- | OTGSC_INTR_B_SESSION_END;
- mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
- | OTGSC_INTSTS_B_SESSION_END;
- }
-
- if (mvotg->pdata->id == NULL) {
- mvotg->irq_en |= OTGSC_INTR_USB_ID;
- mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
- }
-
- otgsc = readl(&mvotg->op_regs->otgsc);
- otgsc |= mvotg->irq_en;
- writel(otgsc, &mvotg->op_regs->otgsc);
-}
-
-static void mv_otg_start_host(struct mv_otg *mvotg, int on)
-{
-#ifdef CONFIG_USB
- struct usb_otg *otg = mvotg->phy.otg;
- struct usb_hcd *hcd;
-
- if (!otg->host)
- return;
-
- dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop");
-
- hcd = bus_to_hcd(otg->host);
-
- if (on) {
- usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
- device_wakeup_enable(hcd->self.controller);
- } else {
- usb_remove_hcd(hcd);
- }
-#endif /* CONFIG_USB */
-}
-
-static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
-{
- struct usb_otg *otg = mvotg->phy.otg;
-
- if (!otg->gadget)
- return;
-
- dev_info(mvotg->phy.dev, "gadget %s\n", str_on_off(on));
-
- if (on)
- usb_gadget_vbus_connect(otg->gadget);
- else
- usb_gadget_vbus_disconnect(otg->gadget);
-}
-
-static void otg_clock_enable(struct mv_otg *mvotg)
-{
- clk_prepare_enable(mvotg->clk);
-}
-
-static void otg_clock_disable(struct mv_otg *mvotg)
-{
- clk_disable_unprepare(mvotg->clk);
-}
-
-static int mv_otg_enable_internal(struct mv_otg *mvotg)
-{
- int retval = 0;
-
- if (mvotg->active)
- return 0;
-
- dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
-
- otg_clock_enable(mvotg);
- if (mvotg->pdata->phy_init) {
- retval = mvotg->pdata->phy_init(mvotg->phy_regs);
- if (retval) {
- dev_err(&mvotg->pdev->dev,
- "init phy error %d\n", retval);
- otg_clock_disable(mvotg);
- return retval;
- }
- }
- mvotg->active = 1;
-
- return 0;
-
-}
-
-static int mv_otg_enable(struct mv_otg *mvotg)
-{
- if (mvotg->clock_gating)
- return mv_otg_enable_internal(mvotg);
-
- return 0;
-}
-
-static void mv_otg_disable_internal(struct mv_otg *mvotg)
-{
- if (mvotg->active) {
- dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
- if (mvotg->pdata->phy_deinit)
- mvotg->pdata->phy_deinit(mvotg->phy_regs);
- otg_clock_disable(mvotg);
- mvotg->active = 0;
- }
-}
-
-static void mv_otg_disable(struct mv_otg *mvotg)
-{
- if (mvotg->clock_gating)
- mv_otg_disable_internal(mvotg);
-}
-
-static void mv_otg_update_inputs(struct mv_otg *mvotg)
-{
- struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
- u32 otgsc;
-
- otgsc = readl(&mvotg->op_regs->otgsc);
-
- if (mvotg->pdata->vbus) {
- if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
- otg_ctrl->b_sess_vld = 1;
- otg_ctrl->b_sess_end = 0;
- } else {
- otg_ctrl->b_sess_vld = 0;
- otg_ctrl->b_sess_end = 1;
- }
- } else {
- otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID);
- otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
- }
-
- if (mvotg->pdata->id)
- otg_ctrl->id = !!mvotg->pdata->id->poll();
- else
- otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
-
- if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id)
- otg_ctrl->a_bus_req = 1;
-
- otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID);
- otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID);
-
- dev_dbg(&mvotg->pdev->dev, "%s: ", __func__);
- dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id);
- dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld);
- dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end);
- dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld);
- dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld);
-}
-
-static void mv_otg_update_state(struct mv_otg *mvotg)
-{
- struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
- int old_state = mvotg->phy.otg->state;
-
- switch (old_state) {
- case OTG_STATE_UNDEFINED:
- mvotg->phy.otg->state = OTG_STATE_B_IDLE;
- fallthrough;
- case OTG_STATE_B_IDLE:
- if (otg_ctrl->id == 0)
- mvotg->phy.otg->state = OTG_STATE_A_IDLE;
- else if (otg_ctrl->b_sess_vld)
- mvotg->phy.otg->state = OTG_STATE_B_PERIPHERAL;
- break;
- case OTG_STATE_B_PERIPHERAL:
- if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
- mvotg->phy.otg->state = OTG_STATE_B_IDLE;
- break;
- case OTG_STATE_A_IDLE:
- if (otg_ctrl->id)
- mvotg->phy.otg->state = OTG_STATE_B_IDLE;
- else if (!(otg_ctrl->a_bus_drop) &&
- (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
- mvotg->phy.otg->state = OTG_STATE_A_WAIT_VRISE;
- break;
- case OTG_STATE_A_WAIT_VRISE:
- if (otg_ctrl->a_vbus_vld)
- mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON;
- break;
- case OTG_STATE_A_WAIT_BCON:
- if (otg_ctrl->id || otg_ctrl->a_bus_drop
- || otg_ctrl->a_wait_bcon_timeout) {
- mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
- mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
- otg_ctrl->a_bus_req = 0;
- } else if (!otg_ctrl->a_vbus_vld) {
- mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
- mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR;
- } else if (otg_ctrl->b_conn) {
- mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
- mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- mvotg->phy.otg->state = OTG_STATE_A_HOST;
- }
- break;
- case OTG_STATE_A_HOST:
- if (otg_ctrl->id || !otg_ctrl->b_conn
- || otg_ctrl->a_bus_drop)
- mvotg->phy.otg->state = OTG_STATE_A_WAIT_BCON;
- else if (!otg_ctrl->a_vbus_vld)
- mvotg->phy.otg->state = OTG_STATE_A_VBUS_ERR;
- break;
- case OTG_STATE_A_WAIT_VFALL:
- if (otg_ctrl->id
- || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
- || otg_ctrl->a_bus_req)
- mvotg->phy.otg->state = OTG_STATE_A_IDLE;
- break;
- case OTG_STATE_A_VBUS_ERR:
- if (otg_ctrl->id || otg_ctrl->a_clr_err
- || otg_ctrl->a_bus_drop) {
- otg_ctrl->a_clr_err = 0;
- mvotg->phy.otg->state = OTG_STATE_A_WAIT_VFALL;
- }
- break;
- default:
- break;
- }
-}
-
-static void mv_otg_work(struct work_struct *work)
-{
- struct mv_otg *mvotg;
- struct usb_otg *otg;
- int old_state;
-
- mvotg = container_of(to_delayed_work(work), struct mv_otg, work);
-
-run:
- /* work queue is single thread, or we need spin_lock to protect */
- otg = mvotg->phy.otg;
- old_state = otg->state;
-
- if (!mvotg->active)
- return;
-
- mv_otg_update_inputs(mvotg);
- mv_otg_update_state(mvotg);
-
- if (old_state != mvotg->phy.otg->state) {
- dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
- state_string[old_state],
- state_string[mvotg->phy.otg->state]);
-
- switch (mvotg->phy.otg->state) {
- case OTG_STATE_B_IDLE:
- otg->default_a = 0;
- if (old_state == OTG_STATE_B_PERIPHERAL)
- mv_otg_start_periphrals(mvotg, 0);
- mv_otg_reset(mvotg);
- mv_otg_disable(mvotg);
- usb_phy_set_event(&mvotg->phy, USB_EVENT_NONE);
- break;
- case OTG_STATE_B_PERIPHERAL:
- mv_otg_enable(mvotg);
- mv_otg_start_periphrals(mvotg, 1);
- usb_phy_set_event(&mvotg->phy, USB_EVENT_ENUMERATED);
- break;
- case OTG_STATE_A_IDLE:
- otg->default_a = 1;
- mv_otg_enable(mvotg);
- if (old_state == OTG_STATE_A_WAIT_VFALL)
- mv_otg_start_host(mvotg, 0);
- mv_otg_reset(mvotg);
- break;
- case OTG_STATE_A_WAIT_VRISE:
- mv_otg_set_vbus(otg, 1);
- break;
- case OTG_STATE_A_WAIT_BCON:
- if (old_state != OTG_STATE_A_HOST)
- mv_otg_start_host(mvotg, 1);
- mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
- T_A_WAIT_BCON);
- /*
- * Now, we directly enter A_HOST. So set b_conn = 1
- * here. In fact, it need host driver to notify us.
- */
- mvotg->otg_ctrl.b_conn = 1;
- break;
- case OTG_STATE_A_HOST:
- break;
- case OTG_STATE_A_WAIT_VFALL:
- /*
- * Now, we has exited A_HOST. So set b_conn = 0
- * here. In fact, it need host driver to notify us.
- */
- mvotg->otg_ctrl.b_conn = 0;
- mv_otg_set_vbus(otg, 0);
- break;
- case OTG_STATE_A_VBUS_ERR:
- break;
- default:
- break;
- }
- goto run;
- }
-}
-
-static irqreturn_t mv_otg_irq(int irq, void *dev)
-{
- struct mv_otg *mvotg = dev;
- u32 otgsc;
-
- otgsc = readl(&mvotg->op_regs->otgsc);
- writel(otgsc, &mvotg->op_regs->otgsc);
-
- /*
- * if we have vbus, then the vbus detection for B-device
- * will be done by mv_otg_inputs_irq().
- */
- if (mvotg->pdata->vbus)
- if ((otgsc & OTGSC_STS_USB_ID) &&
- !(otgsc & OTGSC_INTSTS_USB_ID))
- return IRQ_NONE;
-
- if ((otgsc & mvotg->irq_status) == 0)
- return IRQ_NONE;
-
- mv_otg_run_state_machine(mvotg, 0);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
-{
- struct mv_otg *mvotg = dev;
-
- /* The clock may disabled at this time */
- if (!mvotg->active) {
- mv_otg_enable(mvotg);
- mv_otg_init_irq(mvotg);
- }
-
- mv_otg_run_state_machine(mvotg, 0);
-
- return IRQ_HANDLED;
-}
-
-static ssize_t
-a_bus_req_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct mv_otg *mvotg = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%d\n",
- mvotg->otg_ctrl.a_bus_req);
-}
-
-static ssize_t
-a_bus_req_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mv_otg *mvotg = dev_get_drvdata(dev);
-
- if (count > 2)
- return -1;
-
- /* We will use this interface to change to A device */
- if (mvotg->phy.otg->state != OTG_STATE_B_IDLE
- && mvotg->phy.otg->state != OTG_STATE_A_IDLE)
- return -1;
-
- /* The clock may disabled and we need to set irq for ID detected */
- mv_otg_enable(mvotg);
- mv_otg_init_irq(mvotg);
-
- if (buf[0] == '1') {
- mvotg->otg_ctrl.a_bus_req = 1;
- mvotg->otg_ctrl.a_bus_drop = 0;
- dev_dbg(&mvotg->pdev->dev,
- "User request: a_bus_req = 1\n");
-
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 0);
- spin_unlock(&mvotg->wq_lock);
- }
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(a_bus_req);
-
-static ssize_t
-a_clr_err_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mv_otg *mvotg = dev_get_drvdata(dev);
- if (!mvotg->phy.otg->default_a)
- return -1;
-
- if (count > 2)
- return -1;
-
- if (buf[0] == '1') {
- mvotg->otg_ctrl.a_clr_err = 1;
- dev_dbg(&mvotg->pdev->dev,
- "User request: a_clr_err = 1\n");
- }
-
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 0);
- spin_unlock(&mvotg->wq_lock);
- }
-
- return count;
-}
-
-static DEVICE_ATTR_WO(a_clr_err);
-
-static ssize_t
-a_bus_drop_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mv_otg *mvotg = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%d\n",
- mvotg->otg_ctrl.a_bus_drop);
-}
-
-static ssize_t
-a_bus_drop_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mv_otg *mvotg = dev_get_drvdata(dev);
- if (!mvotg->phy.otg->default_a)
- return -1;
-
- if (count > 2)
- return -1;
-
- if (buf[0] == '0') {
- mvotg->otg_ctrl.a_bus_drop = 0;
- dev_dbg(&mvotg->pdev->dev,
- "User request: a_bus_drop = 0\n");
- } else if (buf[0] == '1') {
- mvotg->otg_ctrl.a_bus_drop = 1;
- mvotg->otg_ctrl.a_bus_req = 0;
- dev_dbg(&mvotg->pdev->dev,
- "User request: a_bus_drop = 1\n");
- dev_dbg(&mvotg->pdev->dev,
- "User request: and a_bus_req = 0\n");
- }
-
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 0);
- spin_unlock(&mvotg->wq_lock);
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(a_bus_drop);
-
-static struct attribute *inputs_attrs[] = {
- &dev_attr_a_bus_req.attr,
- &dev_attr_a_clr_err.attr,
- &dev_attr_a_bus_drop.attr,
- NULL,
-};
-
-static const struct attribute_group inputs_attr_group = {
- .name = "inputs",
- .attrs = inputs_attrs,
-};
-
-static const struct attribute_group *mv_otg_groups[] = {
- &inputs_attr_group,
- NULL,
-};
-
-static void mv_otg_remove(struct platform_device *pdev)
-{
- struct mv_otg *mvotg = platform_get_drvdata(pdev);
-
- if (mvotg->qwork)
- destroy_workqueue(mvotg->qwork);
-
- mv_otg_disable(mvotg);
-
- usb_remove_phy(&mvotg->phy);
-}
-
-static int mv_otg_probe(struct platform_device *pdev)
-{
- struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct mv_otg *mvotg;
- struct usb_otg *otg;
- struct resource *r;
- int retval = 0, i;
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "failed to get platform data\n");
- return -ENODEV;
- }
-
- mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL);
- if (!mvotg)
- return -ENOMEM;
-
- otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
- if (!otg)
- return -ENOMEM;
-
- platform_set_drvdata(pdev, mvotg);
-
- mvotg->pdev = pdev;
- mvotg->pdata = pdata;
-
- mvotg->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(mvotg->clk))
- return PTR_ERR(mvotg->clk);
-
- mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
- if (!mvotg->qwork) {
- dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n");
- return -ENOMEM;
- }
-
- INIT_DELAYED_WORK(&mvotg->work, mv_otg_work);
-
- /* OTG common part */
- mvotg->pdev = pdev;
- mvotg->phy.dev = &pdev->dev;
- mvotg->phy.otg = otg;
- mvotg->phy.label = driver_name;
-
- otg->state = OTG_STATE_UNDEFINED;
- otg->usb_phy = &mvotg->phy;
- otg->set_host = mv_otg_set_host;
- otg->set_peripheral = mv_otg_set_peripheral;
- otg->set_vbus = mv_otg_set_vbus;
-
- for (i = 0; i < OTG_TIMER_NUM; i++)
- timer_setup(&mvotg->otg_ctrl.timer[i],
- mv_otg_timer_await_bcon, 0);
-
- r = platform_get_resource_byname(mvotg->pdev,
- IORESOURCE_MEM, "phyregs");
- if (r == NULL) {
- dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
- retval = -ENODEV;
- goto err_destroy_workqueue;
- }
-
- mvotg->phy_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (mvotg->phy_regs == NULL) {
- dev_err(&pdev->dev, "failed to map phy I/O memory\n");
- retval = -EFAULT;
- goto err_destroy_workqueue;
- }
-
- r = platform_get_resource_byname(mvotg->pdev,
- IORESOURCE_MEM, "capregs");
- if (r == NULL) {
- dev_err(&pdev->dev, "no I/O memory resource defined\n");
- retval = -ENODEV;
- goto err_destroy_workqueue;
- }
-
- mvotg->cap_regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (mvotg->cap_regs == NULL) {
- dev_err(&pdev->dev, "failed to map I/O memory\n");
- retval = -EFAULT;
- goto err_destroy_workqueue;
- }
-
- /* we will acces controller register, so enable the udc controller */
- retval = mv_otg_enable_internal(mvotg);
- if (retval) {
- dev_err(&pdev->dev, "mv otg enable error %d\n", retval);
- goto err_destroy_workqueue;
- }
-
- mvotg->op_regs =
- (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
- + (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
-
- if (pdata->id) {
- retval = devm_request_threaded_irq(&pdev->dev, pdata->id->irq,
- NULL, mv_otg_inputs_irq,
- IRQF_ONESHOT, "id", mvotg);
- if (retval) {
- dev_info(&pdev->dev,
- "Failed to request irq for ID\n");
- pdata->id = NULL;
- }
- }
-
- if (pdata->vbus) {
- mvotg->clock_gating = 1;
- retval = devm_request_threaded_irq(&pdev->dev, pdata->vbus->irq,
- NULL, mv_otg_inputs_irq,
- IRQF_ONESHOT, "vbus", mvotg);
- if (retval) {
- dev_info(&pdev->dev,
- "Failed to request irq for VBUS, "
- "disable clock gating\n");
- mvotg->clock_gating = 0;
- pdata->vbus = NULL;
- }
- }
-
- if (pdata->disable_otg_clock_gating)
- mvotg->clock_gating = 0;
-
- mv_otg_reset(mvotg);
- mv_otg_init_irq(mvotg);
-
- r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no IRQ resource defined\n");
- retval = -ENODEV;
- goto err_disable_clk;
- }
-
- mvotg->irq = r->start;
- if (devm_request_irq(&pdev->dev, mvotg->irq, mv_otg_irq, IRQF_SHARED,
- driver_name, mvotg)) {
- dev_err(&pdev->dev, "Request irq %d for OTG failed\n",
- mvotg->irq);
- mvotg->irq = 0;
- retval = -ENODEV;
- goto err_disable_clk;
- }
-
- retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2);
- if (retval < 0) {
- dev_err(&pdev->dev, "can't register transceiver, %d\n",
- retval);
- goto err_disable_clk;
- }
-
- spin_lock_init(&mvotg->wq_lock);
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 2 * HZ);
- spin_unlock(&mvotg->wq_lock);
- }
-
- dev_info(&pdev->dev,
- "successful probe OTG device %s clock gating.\n",
- mvotg->clock_gating ? "with" : "without");
-
- return 0;
-
-err_disable_clk:
- mv_otg_disable_internal(mvotg);
-err_destroy_workqueue:
- destroy_workqueue(mvotg->qwork);
-
- return retval;
-}
-
-#ifdef CONFIG_PM
-static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct mv_otg *mvotg = platform_get_drvdata(pdev);
-
- if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) {
- dev_info(&pdev->dev,
- "OTG state is not B_IDLE, it is %d!\n",
- mvotg->phy.otg->state);
- return -EAGAIN;
- }
-
- if (!mvotg->clock_gating)
- mv_otg_disable_internal(mvotg);
-
- return 0;
-}
-
-static int mv_otg_resume(struct platform_device *pdev)
-{
- struct mv_otg *mvotg = platform_get_drvdata(pdev);
- u32 otgsc;
-
- if (!mvotg->clock_gating) {
- mv_otg_enable_internal(mvotg);
-
- otgsc = readl(&mvotg->op_regs->otgsc);
- otgsc |= mvotg->irq_en;
- writel(otgsc, &mvotg->op_regs->otgsc);
-
- if (spin_trylock(&mvotg->wq_lock)) {
- mv_otg_run_state_machine(mvotg, 0);
- spin_unlock(&mvotg->wq_lock);
- }
- }
- return 0;
-}
-#endif
-
-static struct platform_driver mv_otg_driver = {
- .probe = mv_otg_probe,
- .remove = mv_otg_remove,
- .driver = {
- .name = driver_name,
- .dev_groups = mv_otg_groups,
- },
-#ifdef CONFIG_PM
- .suspend = mv_otg_suspend,
- .resume = mv_otg_resume,
-#endif
-};
-module_platform_driver(mv_otg_driver);
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 4b35ef216125..f52418fe3fd4 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -685,10 +685,29 @@ static int usbhs_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
spin_lock_init(usbhs_priv_to_lock(priv));
+ /*
+ * Acquire clocks and enable power management (PM) early in the
+ * probe process, as the driver accesses registers during
+ * initialization. Ensure the device is active before proceeding.
+ */
+ pm_runtime_enable(dev);
+
+ ret = usbhsc_clk_get(dev, priv);
+ if (ret)
+ goto probe_pm_disable;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto probe_clk_put;
+
+ ret = usbhsc_clk_prepare_enable(priv);
+ if (ret)
+ goto probe_pm_put;
+
/* call pipe and module init */
ret = usbhs_pipe_probe(priv);
if (ret < 0)
- return ret;
+ goto probe_clk_dis_unprepare;
ret = usbhs_fifo_probe(priv);
if (ret < 0)
@@ -698,19 +717,15 @@ static int usbhs_probe(struct platform_device *pdev)
if (ret < 0)
goto probe_end_fifo_exit;
- /* dev_set_drvdata should be called after usbhs_mod_init */
+ /* platform_set_drvdata() should be called after usbhs_mod_probe() */
platform_set_drvdata(pdev, priv);
ret = reset_control_deassert(priv->rsts);
if (ret)
goto probe_fail_rst;
- ret = usbhsc_clk_get(dev, priv);
- if (ret)
- goto probe_fail_clks;
-
/*
- * deviece reset here because
+ * device reset here because
* USB device might be used in boot loader.
*/
usbhs_sys_clock_ctrl(priv, 0);
@@ -721,7 +736,7 @@ static int usbhs_probe(struct platform_device *pdev)
if (ret) {
dev_warn(dev, "USB function not selected (GPIO)\n");
ret = -ENOTSUPP;
- goto probe_end_mod_exit;
+ goto probe_assert_rest;
}
}
@@ -735,14 +750,19 @@ static int usbhs_probe(struct platform_device *pdev)
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
dev_err(dev, "platform init failed.\n");
- goto probe_end_mod_exit;
+ goto probe_assert_rest;
}
/* reset phy for connection */
usbhs_platform_call(priv, phy_reset, pdev);
- /* power control */
- pm_runtime_enable(dev);
+ /*
+ * Disable the clocks that were enabled earlier in the probe path,
+ * and let the driver handle the clocks beyond this point.
+ */
+ usbhsc_clk_disable_unprepare(priv);
+ pm_runtime_put(dev);
+
if (!usbhs_get_dparam(priv, runtime_pwctrl)) {
usbhsc_power_ctrl(priv, 1);
usbhs_mod_autonomy_mode(priv);
@@ -759,9 +779,7 @@ static int usbhs_probe(struct platform_device *pdev)
return ret;
-probe_end_mod_exit:
- usbhsc_clk_put(priv);
-probe_fail_clks:
+probe_assert_rest:
reset_control_assert(priv->rsts);
probe_fail_rst:
usbhs_mod_remove(priv);
@@ -769,6 +787,14 @@ probe_end_fifo_exit:
usbhs_fifo_remove(priv);
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
+probe_clk_dis_unprepare:
+ usbhsc_clk_disable_unprepare(priv);
+probe_pm_put:
+ pm_runtime_put(dev);
+probe_clk_put:
+ usbhsc_clk_put(priv);
+probe_pm_disable:
+ pm_runtime_disable(dev);
dev_info(dev, "probe failed (%d)\n", ret);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 2fea1b1db4a2..9e2a18c0b218 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -17,7 +17,7 @@ static int usb_serial_device_match(struct device *dev,
const struct device_driver *drv)
{
const struct usb_serial_port *port = to_usb_serial_port(dev);
- struct usb_serial_driver *driver = to_usb_serial_driver(drv);
+ const struct usb_serial_driver *driver = to_usb_serial_driver(drv);
/*
* drivers are already assigned to ports in serial_probe so it's
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 010688dd9e49..22579d0d8ab8 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -458,6 +458,8 @@ static int pl2303_detect_type(struct usb_serial *serial)
case 0x605:
case 0x700: /* GR */
case 0x705:
+ case 0x905: /* GT-2AB */
+ case 0x1005: /* GC-Q20 */
return TYPE_HXN;
}
break;
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index a0c244bc77c0..d671189ecee2 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -729,11 +729,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
/* start read urb */
urb = port->read_urb;
- if (!urb) {
- dev_err(&port->dev, "%s - no read urb\n", __func__);
- status = -EINVAL;
- goto unlink_int_urb;
- }
tport->tp_read_urb_state = TI_READ_URB_RUNNING;
urb->context = tport;
status = usb_submit_urb(urb, GFP_KERNEL);
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index d460d71b4257..1477e31d7763 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -52,6 +52,13 @@ UNUSUAL_DEV(0x059f, 0x1061, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME),
+/* Reported-by: Zhihong Zhou <zhouzhihong@greatwall.com.cn> */
+UNUSUAL_DEV(0x0781, 0x55e8, 0x0000, 0x9999,
+ "SanDisk",
+ "",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_UAS),
+
/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999,
"Hiksemi",
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
index ac84a6d64c2f..b09b58d7311d 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -393,6 +393,10 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
break;
case CMDT_RSP_NAK:
switch (cmd) {
+ case DP_CMD_STATUS_UPDATE:
+ if (typec_altmode_exit(alt))
+ dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
+ break;
case DP_CMD_CONFIGURE:
dp->data.conf = 0;
ret = dp_altmode_configured(dp);
diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
index ae90688d23e4..a884cec9ab7e 100644
--- a/drivers/usb/typec/bus.c
+++ b/drivers/usb/typec/bus.c
@@ -449,7 +449,7 @@ ATTRIBUTE_GROUPS(typec);
static int typec_match(struct device *dev, const struct device_driver *driver)
{
- struct typec_altmode_driver *drv = to_altmode_driver(driver);
+ const struct typec_altmode_driver *drv = to_altmode_driver(driver);
struct typec_altmode *altmode = to_typec_altmode(dev);
const struct typec_device_id *id;
diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index 49926d6e72c7..182c902c42f6 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -214,7 +214,7 @@ int typec_switch_set(struct typec_switch *sw,
sw_dev = sw->sw_devs[i];
ret = sw_dev->set(sw_dev, orientation);
- if (ret)
+ if (ret && ret != -EOPNOTSUPP)
return ret;
}
@@ -378,7 +378,7 @@ int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
mux_dev = mux->mux_devs[i];
ret = mux_dev->set(mux_dev, state);
- if (ret)
+ if (ret && ret != -EOPNOTSUPP)
return ret;
}
diff --git a/drivers/usb/typec/mux/fsa4480.c b/drivers/usb/typec/mux/fsa4480.c
index f71dba8bf07c..c54e42c7e6a1 100644
--- a/drivers/usb/typec/mux/fsa4480.c
+++ b/drivers/usb/typec/mux/fsa4480.c
@@ -12,6 +12,7 @@
#include <linux/regmap.h>
#include <linux/usb/typec_dp.h>
#include <linux/usb/typec_mux.h>
+#include <linux/regulator/consumer.h>
#define FSA4480_DEVICE_ID 0x00
#define FSA4480_DEVICE_ID_VENDOR_ID GENMASK(7, 6)
@@ -273,6 +274,10 @@ static int fsa4480_probe(struct i2c_client *client)
if (IS_ERR(fsa->regmap))
return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
+ ret = devm_regulator_get_enable_optional(dev, "vcc");
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
ret = regmap_read(fsa->regmap, FSA4480_DEVICE_ID, &val);
if (ret)
return dev_err_probe(dev, -ENODEV, "FSA4480 not found\n");
diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c
index d42da5720a25..cdbb7c11d714 100644
--- a/drivers/usb/typec/port-mapper.c
+++ b/drivers/usb/typec/port-mapper.c
@@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/component.h>
+#include <linux/thunderbolt.h>
#include <linux/usb.h>
#include "class.h"
@@ -36,6 +37,11 @@ struct each_port_arg {
struct component_match *match;
};
+static int usb4_port_compare(struct device *dev, void *fwnode)
+{
+ return usb4_usb3_port_match(dev, fwnode);
+}
+
static int typec_port_compare(struct device *dev, void *fwnode)
{
return device_match_fwnode(dev, fwnode);
@@ -51,9 +57,22 @@ static int typec_port_match(struct device *dev, void *data)
if (con_adev == adev)
return 0;
- if (con_adev->pld_crc == adev->pld_crc)
+ if (con_adev->pld_crc == adev->pld_crc) {
+ struct fwnode_handle *adev_fwnode = acpi_fwnode_handle(adev);
+
component_match_add(&arg->port->dev, &arg->match, typec_port_compare,
- acpi_fwnode_handle(adev));
+ adev_fwnode);
+
+ /*
+ * If dev is USB 3.x port, it may have reference to the
+ * USB4 host interface in which case we can also link the
+ * Type-C port with the USB4 port.
+ */
+ if (fwnode_property_present(adev_fwnode, "usb4-host-interface"))
+ component_match_add(&arg->port->dev, &arg->match,
+ usb4_port_compare, adev_fwnode);
+ }
+
return 0;
}
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 19ab6647af70..a56e31b20c21 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -17,6 +17,7 @@
#include <linux/usb/tcpci.h>
#include <linux/usb/tcpm.h>
#include <linux/usb/typec.h>
+#include <linux/regulator/consumer.h>
#define PD_RETRY_COUNT_DEFAULT 3
#define PD_RETRY_COUNT_3_0_OR_HIGHER 2
@@ -905,6 +906,10 @@ static int tcpci_probe(struct i2c_client *client)
int err;
u16 val = 0;
+ err = devm_regulator_get_enable_optional(&client->dev, "vdd");
+ if (err && err != -ENODEV)
+ return dev_err_probe(&client->dev, err, "Failed to get regulator\n");
+
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index fd1b80593367..b5a5ed40faea 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -166,7 +166,8 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
return;
}
- if (count > sizeof(struct pd_message) || count + 1 > TCPC_RECEIVE_BUFFER_LEN) {
+ if (count > sizeof(struct pd_message) + 1 ||
+ count + 1 > TCPC_RECEIVE_BUFFER_LEN) {
dev_err(chip->dev, "Invalid TCPC_RX_BYTE_CNT %d\n", count);
return;
}
@@ -536,7 +537,10 @@ static int max_tcpci_probe(struct i2c_client *client)
return dev_err_probe(&client->dev, ret,
"IRQ initialization failed\n");
- device_init_wakeup(chip->dev, true);
+ ret = devm_device_init_wakeup(chip->dev);
+ if (ret)
+ return dev_err_probe(chip->dev, ret, "Failed to init wakeup\n");
+
return 0;
}
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 5ea884ef36af..1a1f9e1f8e4e 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -67,6 +67,7 @@
\
S(ACC_UNATTACHED), \
S(DEBUG_ACC_ATTACHED), \
+ S(DEBUG_ACC_DEBOUNCE), \
S(AUDIO_ACC_ATTACHED), \
S(AUDIO_ACC_DEBOUNCE), \
\
@@ -313,6 +314,10 @@ struct pd_data {
unsigned int operating_snk_mw;
};
+#define PD_CAP_REV10 0x1
+#define PD_CAP_REV20 0x2
+#define PD_CAP_REV30 0x3
+
struct pd_revision_info {
u8 rev_major;
u8 rev_minor;
@@ -596,6 +601,15 @@ struct pd_rx_event {
enum tcpm_transmit_type rx_sop_type;
};
+struct altmode_vdm_event {
+ struct kthread_work work;
+ struct tcpm_port *port;
+ u32 header;
+ u32 *data;
+ int cnt;
+ enum tcpm_transmit_type tx_sop_type;
+};
+
static const char * const pd_rev[] = {
[PD_REV10] = "rev1",
[PD_REV20] = "rev2",
@@ -621,7 +635,8 @@ static const char * const pd_rev[] = {
!tcpm_cc_is_source((port)->cc1)))
#define tcpm_port_is_debug(port) \
- (tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2))
+ ((tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2)) || \
+ (tcpm_cc_is_sink((port)->cc1) && tcpm_cc_is_sink((port)->cc2)))
#define tcpm_port_is_audio(port) \
(tcpm_cc_is_audio((port)->cc1) && tcpm_cc_is_audio((port)->cc2))
@@ -1151,7 +1166,7 @@ static int tcpm_set_attached_state(struct tcpm_port *port, bool attached)
port->data_role);
}
-static int tcpm_set_roles(struct tcpm_port *port, bool attached,
+static int tcpm_set_roles(struct tcpm_port *port, bool attached, int state,
enum typec_role role, enum typec_data_role data)
{
enum typec_orientation orientation;
@@ -1188,7 +1203,7 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
}
}
- ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation);
+ ret = tcpm_mux_set(port, state, usb_role, orientation);
if (ret < 0)
return ret;
@@ -1608,18 +1623,68 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
mod_vdm_delayed_work(port, 0);
}
-static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
- const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
+static void tcpm_queue_vdm_work(struct kthread_work *work)
{
- if (port->state != SRC_READY && port->state != SNK_READY &&
- port->state != SRC_VDM_IDENTITY_REQUEST)
- return;
+ struct altmode_vdm_event *event = container_of(work,
+ struct altmode_vdm_event,
+ work);
+ struct tcpm_port *port = event->port;
mutex_lock(&port->lock);
- tcpm_queue_vdm(port, header, data, cnt, tx_sop_type);
+ if (port->state != SRC_READY && port->state != SNK_READY &&
+ port->state != SRC_VDM_IDENTITY_REQUEST) {
+ tcpm_log_force(port, "dropping altmode_vdm_event");
+ goto port_unlock;
+ }
+
+ tcpm_queue_vdm(port, event->header, event->data, event->cnt, event->tx_sop_type);
+
+port_unlock:
+ kfree(event->data);
+ kfree(event);
mutex_unlock(&port->lock);
}
+static int tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
+ const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
+{
+ struct altmode_vdm_event *event;
+ u32 *data_cpy;
+ int ret = -ENOMEM;
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ goto err_event;
+
+ data_cpy = kcalloc(cnt, sizeof(u32), GFP_KERNEL);
+ if (!data_cpy)
+ goto err_data;
+
+ kthread_init_work(&event->work, tcpm_queue_vdm_work);
+ event->port = port;
+ event->header = header;
+ memcpy(data_cpy, data, sizeof(u32) * cnt);
+ event->data = data_cpy;
+ event->cnt = cnt;
+ event->tx_sop_type = tx_sop_type;
+
+ ret = kthread_queue_work(port->wq, &event->work);
+ if (!ret) {
+ ret = -EBUSY;
+ goto err_queue;
+ }
+
+ return 0;
+
+err_queue:
+ kfree(data_cpy);
+err_data:
+ kfree(event);
+err_event:
+ tcpm_log_force(port, "failed to queue altmode vdm, err:%d", ret);
+ return ret;
+}
+
static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt)
{
u32 vdo = p[VDO_INDEX_IDH];
@@ -2830,8 +2895,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
- tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
}
static int tcpm_altmode_exit(struct typec_altmode *altmode)
@@ -2847,8 +2911,7 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode)
header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
header |= VDO_OPOS(altmode->mode);
- tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP);
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP);
}
static int tcpm_altmode_vdm(struct typec_altmode *altmode,
@@ -2856,9 +2919,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode,
{
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
- tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP);
-
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP);
}
static const struct typec_altmode_ops tcpm_altmode_ops = {
@@ -2882,8 +2943,7 @@ static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_pl
header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
header |= VDO_OPOS(altmode->mode);
- tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
}
static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop)
@@ -2899,8 +2959,7 @@ static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plu
header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
header |= VDO_OPOS(altmode->mode);
- tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME);
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME);
}
static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
@@ -2908,9 +2967,7 @@ static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug
{
struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
- tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME);
-
- return 0;
+ return tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME);
}
static const struct typec_cable_ops tcpm_cable_ops = {
@@ -4353,7 +4410,8 @@ static int tcpm_src_attach(struct tcpm_port *port)
tcpm_enable_auto_vbus_discharge(port, true);
- ret = tcpm_set_roles(port, true, TYPEC_SOURCE, tcpm_data_role_for_source(port));
+ ret = tcpm_set_roles(port, true, TYPEC_STATE_USB,
+ TYPEC_SOURCE, tcpm_data_role_for_source(port));
if (ret < 0)
return ret;
@@ -4528,7 +4586,8 @@ static int tcpm_snk_attach(struct tcpm_port *port)
tcpm_enable_auto_vbus_discharge(port, true);
- ret = tcpm_set_roles(port, true, TYPEC_SINK, tcpm_data_role_for_sink(port));
+ ret = tcpm_set_roles(port, true, TYPEC_STATE_USB,
+ TYPEC_SINK, tcpm_data_role_for_sink(port));
if (ret < 0)
return ret;
@@ -4551,12 +4610,24 @@ static void tcpm_snk_detach(struct tcpm_port *port)
static int tcpm_acc_attach(struct tcpm_port *port)
{
int ret;
+ enum typec_role role;
+ enum typec_data_role data;
+ int state = TYPEC_STATE_USB;
if (port->attached)
return 0;
- ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
- tcpm_data_role_for_source(port));
+ role = tcpm_port_is_sink(port) ? TYPEC_SINK : TYPEC_SOURCE;
+ data = tcpm_port_is_sink(port) ? tcpm_data_role_for_sink(port)
+ : tcpm_data_role_for_source(port);
+
+ if (tcpm_port_is_audio(port))
+ state = TYPEC_MODE_AUDIO;
+
+ if (tcpm_port_is_debug(port))
+ state = TYPEC_MODE_DEBUG;
+
+ ret = tcpm_set_roles(port, true, state, role, data);
if (ret < 0)
return ret;
@@ -4665,6 +4736,25 @@ static void tcpm_set_initial_svdm_version(struct tcpm_port *port)
}
}
+static void tcpm_set_initial_negotiated_rev(struct tcpm_port *port)
+{
+ switch (port->pd_rev.rev_major) {
+ case PD_CAP_REV10:
+ port->negotiated_rev = PD_REV10;
+ break;
+ case PD_CAP_REV20:
+ port->negotiated_rev = PD_REV20;
+ break;
+ case PD_CAP_REV30:
+ port->negotiated_rev = PD_REV30;
+ break;
+ default:
+ port->negotiated_rev = PD_MAX_REV;
+ break;
+ }
+ port->negotiated_rev_prime = port->negotiated_rev;
+}
+
static void run_state_machine(struct tcpm_port *port)
{
int ret;
@@ -4782,8 +4872,7 @@ static void run_state_machine(struct tcpm_port *port)
typec_set_pwr_opmode(port->typec_port, opmode);
port->pwr_opmode = TYPEC_PWR_MODE_USB;
port->caps_count = 0;
- port->negotiated_rev = PD_MAX_REV;
- port->negotiated_rev_prime = PD_MAX_REV;
+ tcpm_set_initial_negotiated_rev(port);
port->message_id = 0;
port->message_id_prime = 0;
port->rx_msgid = -1;
@@ -4964,7 +5053,13 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, SRC_UNATTACHED, PD_T_DRP_SRC);
break;
case SNK_ATTACH_WAIT:
- if ((port->cc1 == TYPEC_CC_OPEN &&
+ if (tcpm_port_is_debug(port))
+ tcpm_set_state(port, DEBUG_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ else if (tcpm_port_is_audio(port))
+ tcpm_set_state(port, AUDIO_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ else if ((port->cc1 == TYPEC_CC_OPEN &&
port->cc2 != TYPEC_CC_OPEN) ||
(port->cc1 != TYPEC_CC_OPEN &&
port->cc2 == TYPEC_CC_OPEN))
@@ -4978,6 +5073,12 @@ static void run_state_machine(struct tcpm_port *port)
if (tcpm_port_is_disconnected(port))
tcpm_set_state(port, SNK_UNATTACHED,
PD_T_PD_DEBOUNCE);
+ else if (tcpm_port_is_debug(port))
+ tcpm_set_state(port, DEBUG_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ else if (tcpm_port_is_audio(port))
+ tcpm_set_state(port, AUDIO_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
else if (port->vbus_present)
tcpm_set_state(port,
tcpm_try_src(port) ? SRC_TRY
@@ -5048,8 +5149,7 @@ static void run_state_machine(struct tcpm_port *port)
port->cc2 : port->cc1);
typec_set_pwr_opmode(port->typec_port, opmode);
port->pwr_opmode = TYPEC_PWR_MODE_USB;
- port->negotiated_rev = PD_MAX_REV;
- port->negotiated_rev_prime = PD_MAX_REV;
+ tcpm_set_initial_negotiated_rev(port);
port->message_id = 0;
port->message_id_prime = 0;
port->rx_msgid = -1;
@@ -5276,7 +5376,10 @@ static void run_state_machine(struct tcpm_port *port)
/* Accessory states */
case ACC_UNATTACHED:
tcpm_acc_detach(port);
- tcpm_set_state(port, SRC_UNATTACHED, 0);
+ if (port->port_type == TYPEC_PORT_SRC)
+ tcpm_set_state(port, SRC_UNATTACHED, 0);
+ else
+ tcpm_set_state(port, SNK_UNATTACHED, 0);
break;
case DEBUG_ACC_ATTACHED:
case AUDIO_ACC_ATTACHED:
@@ -5284,6 +5387,7 @@ static void run_state_machine(struct tcpm_port *port)
if (ret < 0)
tcpm_set_state(port, ACC_UNATTACHED, 0);
break;
+ case DEBUG_ACC_DEBOUNCE:
case AUDIO_ACC_DEBOUNCE:
tcpm_set_state(port, ACC_UNATTACHED, port->timings.cc_debounce_time);
break;
@@ -5326,7 +5430,7 @@ static void run_state_machine(struct tcpm_port *port)
*/
tcpm_set_vconn(port, false);
tcpm_set_vbus(port, false);
- tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
+ tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SOURCE,
tcpm_data_role_for_source(port));
/*
* If tcpc fails to notify vbus off, TCPM will wait for PD_T_SAFE_0V +
@@ -5358,7 +5462,7 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_vconn(port, false);
if (port->pd_capable)
tcpm_set_charge(port, false);
- tcpm_set_roles(port, port->self_powered, TYPEC_SINK,
+ tcpm_set_roles(port, port->self_powered, TYPEC_STATE_USB, TYPEC_SINK,
tcpm_data_role_for_sink(port));
/*
* VBUS may or may not toggle, depending on the adapter.
@@ -5482,10 +5586,10 @@ static void run_state_machine(struct tcpm_port *port)
case DR_SWAP_CHANGE_DR:
tcpm_unregister_altmodes(port);
if (port->data_role == TYPEC_HOST)
- tcpm_set_roles(port, true, port->pwr_role,
+ tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role,
TYPEC_DEVICE);
else
- tcpm_set_roles(port, true, port->pwr_role,
+ tcpm_set_roles(port, true, TYPEC_STATE_USB, port->pwr_role,
TYPEC_HOST);
tcpm_ams_finish(port);
tcpm_set_state(port, ready_state(port), 0);
@@ -5875,7 +5979,8 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
}
break;
case SNK_UNATTACHED:
- if (tcpm_port_is_sink(port))
+ if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
+ tcpm_port_is_sink(port))
tcpm_set_state(port, SNK_ATTACH_WAIT, 0);
break;
case SNK_ATTACH_WAIT:
@@ -5938,7 +6043,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
case DEBUG_ACC_ATTACHED:
if (cc1 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_OPEN)
- tcpm_set_state(port, ACC_UNATTACHED, 0);
+ tcpm_set_state(port, DEBUG_ACC_DEBOUNCE, 0);
+ break;
+
+ case DEBUG_ACC_DEBOUNCE:
+ if (tcpm_port_is_debug(port))
+ tcpm_set_state(port, DEBUG_ACC_ATTACHED, 0);
break;
case SNK_TRY:
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index 7ee721a877c1..dcf141ada078 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -1431,7 +1431,7 @@ static int tps6598x_probe(struct i2c_client *client)
tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source");
if (tps->wakeup && client->irq) {
- device_init_wakeup(&client->dev, true);
+ devm_device_init_wakeup(&client->dev);
enable_irq_wake(client->irq);
}
diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h
index 9b23e9017452..cecb8d11d239 100644
--- a/drivers/usb/typec/tipd/tps6598x.h
+++ b/drivers/usb/typec/tipd/tps6598x.h
@@ -27,7 +27,7 @@
#define TPS_STATUS_OVERCURRENT BIT(16)
#define TPS_STATUS_GOTO_MIN_ACTIVE BIT(26)
#define TPS_STATUS_BIST BIT(27)
-#define TPS_STATUS_HIGH_VOLAGE_WARNING BIT(28)
+#define TPS_STATUS_HIGH_VOLTAGE_WARNING BIT(28)
#define TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING BIT(29)
#define TPS_STATUS_CONN_STATE_MASK GENMASK(3, 1)
diff --git a/drivers/usb/typec/tipd/trace.h b/drivers/usb/typec/tipd/trace.h
index 0669cca12ea1..bea383f2db9d 100644
--- a/drivers/usb/typec/tipd/trace.h
+++ b/drivers/usb/typec/tipd/trace.h
@@ -153,7 +153,7 @@
{ TPS_STATUS_OVERCURRENT, "OVERCURRENT" }, \
{ TPS_STATUS_GOTO_MIN_ACTIVE, "GOTO_MIN_ACTIVE" }, \
{ TPS_STATUS_BIST, "BIST" }, \
- { TPS_STATUS_HIGH_VOLAGE_WARNING, "HIGH_VOLAGE_WARNING" }, \
+ { TPS_STATUS_HIGH_VOLTAGE_WARNING, "HIGH_VOLTAGE_WARNING" }, \
{ TPS_STATUS_HIGH_LOW_VOLTAGE_WARNING, "HIGH_LOW_VOLTAGE_WARNING" })
#define show_tps25750_status_flags(flags) \
diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index 75559601fe8f..8bf8fefb4f07 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -91,4 +91,15 @@ config UCSI_LENOVO_YOGA_C630
To compile the driver as a module, choose M here: the module will be
called ucsi_yoga_c630.
+config UCSI_HUAWEI_GAOKUN
+ tristate "UCSI Interface Driver for Huawei Matebook E Go"
+ depends on EC_HUAWEI_GAOKUN
+ select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
+ help
+ This driver enables UCSI support on the Huawei Matebook E Go tablet,
+ which is a sc8280xp-based 2-in-1 tablet.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_huawei_gaokun.
+
endif
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index be98a879104d..dbc571763eff 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o
obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o
obj-$(CONFIG_CROS_EC_UCSI) += cros_ec_ucsi.o
obj-$(CONFIG_UCSI_LENOVO_YOGA_C630) += ucsi_yoga_c630.o
+obj-$(CONFIG_UCSI_HUAWEI_GAOKUN) += ucsi_huawei_gaokun.o
diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c
index eae2b18a2d8a..92ebf1a2defd 100644
--- a/drivers/usb/typec/ucsi/debugfs.c
+++ b/drivers/usb/typec/ucsi/debugfs.c
@@ -34,16 +34,20 @@ static int ucsi_cmd(void *data, u64 val)
case UCSI_CONNECTOR_RESET:
case UCSI_SET_SINK_PATH:
case UCSI_SET_NEW_CAM:
+ case UCSI_SET_USB:
ret = ucsi_send_command(ucsi, val, NULL, 0);
break;
case UCSI_GET_CAPABILITY:
case UCSI_GET_CONNECTOR_CAPABILITY:
case UCSI_GET_ALTERNATE_MODES:
+ case UCSI_GET_CAM_SUPPORTED:
case UCSI_GET_CURRENT_CAM:
case UCSI_GET_PDOS:
case UCSI_GET_CABLE_PROPERTY:
case UCSI_GET_CONNECTOR_STATUS:
case UCSI_GET_ERROR_STATUS:
+ case UCSI_GET_PD_MESSAGE:
+ case UCSI_GET_ATTENTION_VDO:
case UCSI_GET_CAM_CS:
case UCSI_GET_LPM_PPM_INFO:
ret = ucsi_send_command(ucsi, val,
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 9c5278a0c5d4..5a8f947fcece 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -125,9 +125,11 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_GET_CONNECTOR_STATUS 0x12
#define UCSI_GET_CONNECTOR_STATUS_SIZE 152
#define UCSI_GET_ERROR_STATUS 0x13
+#define UCSI_GET_ATTENTION_VDO 0x16
#define UCSI_GET_PD_MESSAGE 0x15
#define UCSI_GET_CAM_CS 0x18
#define UCSI_SET_SINK_PATH 0x1c
+#define UCSI_SET_USB 0x21
#define UCSI_GET_LPM_PPM_INFO 0x22
#define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16)
@@ -434,7 +436,7 @@ struct ucsi_debugfs_entry {
u64 low;
u64 high;
} response;
- u32 status;
+ int status;
struct dentry *dentry;
};
diff --git a/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c
new file mode 100644
index 000000000000..7b5222081bbb
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_huawei_gaokun.c
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ucsi-huawei-gaokun - A UCSI driver for HUAWEI Matebook E Go
+ *
+ * Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com>
+ */
+
+#include <drm/bridge/aux-bridge.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_data/huawei-gaokun-ec.h>
+#include <linux/string.h>
+#include <linux/usb/pd_vdo.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/workqueue_types.h>
+
+#include "ucsi.h"
+
+#define EC_EVENT_UCSI 0x21
+#define EC_EVENT_USB 0x22
+
+#define GAOKUN_CCX_MASK GENMASK(1, 0)
+#define GAOKUN_MUX_MASK GENMASK(3, 2)
+
+#define GAOKUN_DPAM_MASK GENMASK(3, 0)
+#define GAOKUN_HPD_STATE_MASK BIT(4)
+#define GAOKUN_HPD_IRQ_MASK BIT(5)
+
+#define GET_IDX(updt) (ffs(updt) - 1)
+
+#define CCX_TO_ORI(ccx) (++(ccx) % 3) /* convert ccx to enum typec_orientation */
+
+/* Configuration Channel Extension */
+enum gaokun_ucsi_ccx {
+ USBC_CCX_NORMAL,
+ USBC_CCX_REVERSE,
+ USBC_CCX_NONE,
+};
+
+enum gaokun_ucsi_mux {
+ USBC_MUX_NONE,
+ USBC_MUX_USB_2L,
+ USBC_MUX_DP_4L,
+ USBC_MUX_USB_DP,
+};
+
+/* based on pmic_glink_altmode_pin_assignment */
+enum gaokun_ucsi_dpam_pan { /* DP Alt Mode Pin Assignments */
+ USBC_DPAM_PAN_NONE,
+ USBC_DPAM_PAN_A, /* Not supported after USB Type-C Standard v1.0b */
+ USBC_DPAM_PAN_B, /* Not supported after USB Type-C Standard v1.0b */
+ USBC_DPAM_PAN_C, /* USBC_DPAM_PAN_C_REVERSE - 6 */
+ USBC_DPAM_PAN_D,
+ USBC_DPAM_PAN_E,
+ USBC_DPAM_PAN_F, /* Not supported after USB Type-C Standard v1.0b */
+ USBC_DPAM_PAN_A_REVERSE,/* Not supported after USB Type-C Standard v1.0b */
+ USBC_DPAM_PAN_B_REVERSE,/* Not supported after USB Type-C Standard v1.0b */
+ USBC_DPAM_PAN_C_REVERSE,
+ USBC_DPAM_PAN_D_REVERSE,
+ USBC_DPAM_PAN_E_REVERSE,
+ USBC_DPAM_PAN_F_REVERSE,/* Not supported after USB Type-C Standard v1.0b */
+};
+
+struct gaokun_ucsi_reg {
+ u8 num_ports;
+ u8 port_updt;
+ u8 port_data[4];
+ u8 checksum;
+ u8 reserved;
+} __packed;
+
+struct gaokun_ucsi_port {
+ struct completion usb_ack;
+ spinlock_t lock; /* serializing port resource access */
+
+ struct gaokun_ucsi *ucsi;
+ struct auxiliary_device *bridge;
+
+ int idx;
+ enum gaokun_ucsi_ccx ccx;
+ enum gaokun_ucsi_mux mux;
+ u8 mode;
+ u16 svid;
+ u8 hpd_state;
+ u8 hpd_irq;
+};
+
+struct gaokun_ucsi {
+ struct gaokun_ec *ec;
+ struct ucsi *ucsi;
+ struct gaokun_ucsi_port *ports;
+ struct device *dev;
+ struct delayed_work work;
+ struct notifier_block nb;
+ u16 version;
+ u8 num_ports;
+};
+
+/* -------------------------------------------------------------------------- */
+/* For UCSI */
+
+static int gaokun_ucsi_read_version(struct ucsi *ucsi, u16 *version)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi);
+
+ *version = uec->version;
+
+ return 0;
+}
+
+static int gaokun_ucsi_read_cci(struct ucsi *ucsi, u32 *cci)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi);
+ u8 buf[GAOKUN_UCSI_READ_SIZE];
+ int ret;
+
+ ret = gaokun_ec_ucsi_read(uec->ec, buf);
+ if (ret)
+ return ret;
+
+ memcpy(cci, buf, sizeof(*cci));
+
+ return 0;
+}
+
+static int gaokun_ucsi_read_message_in(struct ucsi *ucsi,
+ void *val, size_t val_len)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi);
+ u8 buf[GAOKUN_UCSI_READ_SIZE];
+ int ret;
+
+ ret = gaokun_ec_ucsi_read(uec->ec, buf);
+ if (ret)
+ return ret;
+
+ memcpy(val, buf + GAOKUN_UCSI_CCI_SIZE,
+ min(val_len, GAOKUN_UCSI_MSGI_SIZE));
+
+ return 0;
+}
+
+static int gaokun_ucsi_async_control(struct ucsi *ucsi, u64 command)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(ucsi);
+ u8 buf[GAOKUN_UCSI_WRITE_SIZE] = {};
+
+ memcpy(buf, &command, sizeof(command));
+
+ return gaokun_ec_ucsi_write(uec->ec, buf);
+}
+
+static void gaokun_ucsi_update_connector(struct ucsi_connector *con)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(con->ucsi);
+
+ if (con->num > uec->num_ports)
+ return;
+
+ con->typec_cap.orientation_aware = true;
+}
+
+static void gaokun_set_orientation(struct ucsi_connector *con,
+ struct gaokun_ucsi_port *port)
+{
+ enum gaokun_ucsi_ccx ccx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ ccx = port->ccx;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ typec_set_orientation(con->port, CCX_TO_ORI(ccx));
+}
+
+static void gaokun_ucsi_connector_status(struct ucsi_connector *con)
+{
+ struct gaokun_ucsi *uec = ucsi_get_drvdata(con->ucsi);
+ int idx;
+
+ idx = con->num - 1;
+ if (con->num > uec->num_ports) {
+ dev_warn(uec->dev, "set orientation out of range: con%d\n", idx);
+ return;
+ }
+
+ gaokun_set_orientation(con, &uec->ports[idx]);
+}
+
+const struct ucsi_operations gaokun_ucsi_ops = {
+ .read_version = gaokun_ucsi_read_version,
+ .read_cci = gaokun_ucsi_read_cci,
+ .read_message_in = gaokun_ucsi_read_message_in,
+ .sync_control = ucsi_sync_control_common,
+ .async_control = gaokun_ucsi_async_control,
+ .update_connector = gaokun_ucsi_update_connector,
+ .connector_status = gaokun_ucsi_connector_status,
+};
+
+/* -------------------------------------------------------------------------- */
+/* For Altmode */
+
+static void gaokun_ucsi_port_update(struct gaokun_ucsi_port *port,
+ const u8 *port_data)
+{
+ struct gaokun_ucsi *uec = port->ucsi;
+ int offset = port->idx * 2; /* every port has 2 Bytes data */
+ unsigned long flags;
+ u8 dcc, ddi;
+
+ dcc = port_data[offset];
+ ddi = port_data[offset + 1];
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->ccx = FIELD_GET(GAOKUN_CCX_MASK, dcc);
+ port->mux = FIELD_GET(GAOKUN_MUX_MASK, dcc);
+ port->mode = FIELD_GET(GAOKUN_DPAM_MASK, ddi);
+ port->hpd_state = FIELD_GET(GAOKUN_HPD_STATE_MASK, ddi);
+ port->hpd_irq = FIELD_GET(GAOKUN_HPD_IRQ_MASK, ddi);
+
+ /* Mode and SVID are unused; keeping them to make things clearer */
+ switch (port->mode) {
+ case USBC_DPAM_PAN_C:
+ case USBC_DPAM_PAN_C_REVERSE:
+ port->mode = DP_PIN_ASSIGN_C; /* correct it for usb later */
+ break;
+ case USBC_DPAM_PAN_D:
+ case USBC_DPAM_PAN_D_REVERSE:
+ port->mode = DP_PIN_ASSIGN_D;
+ break;
+ case USBC_DPAM_PAN_E:
+ case USBC_DPAM_PAN_E_REVERSE:
+ port->mode = DP_PIN_ASSIGN_E;
+ break;
+ case USBC_DPAM_PAN_NONE:
+ port->mode = TYPEC_STATE_SAFE;
+ break;
+ default:
+ dev_warn(uec->dev, "unknown mode %d\n", port->mode);
+ break;
+ }
+
+ switch (port->mux) {
+ case USBC_MUX_NONE:
+ port->svid = 0;
+ break;
+ case USBC_MUX_USB_2L:
+ port->svid = USB_SID_PD;
+ port->mode = TYPEC_STATE_USB; /* same as PAN_C, correct it */
+ break;
+ case USBC_MUX_DP_4L:
+ case USBC_MUX_USB_DP:
+ port->svid = USB_SID_DISPLAYPORT;
+ break;
+ default:
+ dev_warn(uec->dev, "unknown mux state %d\n", port->mux);
+ break;
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int gaokun_ucsi_refresh(struct gaokun_ucsi *uec)
+{
+ struct gaokun_ucsi_reg ureg;
+ int ret, idx;
+
+ ret = gaokun_ec_ucsi_get_reg(uec->ec, &ureg);
+ if (ret)
+ return GAOKUN_UCSI_NO_PORT_UPDATE;
+
+ uec->num_ports = ureg.num_ports;
+ idx = GET_IDX(ureg.port_updt);
+
+ if (idx < 0 || idx >= ureg.num_ports)
+ return GAOKUN_UCSI_NO_PORT_UPDATE;
+
+ gaokun_ucsi_port_update(&uec->ports[idx], ureg.port_data);
+ return idx;
+}
+
+static void gaokun_ucsi_handle_altmode(struct gaokun_ucsi_port *port)
+{
+ struct gaokun_ucsi *uec = port->ucsi;
+ int idx = port->idx;
+
+ if (idx >= uec->ucsi->cap.num_connectors) {
+ dev_warn(uec->dev, "altmode port out of range: %d\n", idx);
+ return;
+ }
+
+ /* UCSI callback .connector_status() have set orientation */
+ if (port->bridge)
+ drm_aux_hpd_bridge_notify(&port->bridge->dev,
+ port->hpd_state ?
+ connector_status_connected :
+ connector_status_disconnected);
+
+ gaokun_ec_ucsi_pan_ack(uec->ec, port->idx);
+}
+
+static void gaokun_ucsi_altmode_notify_ind(struct gaokun_ucsi *uec)
+{
+ int idx;
+
+ if (!uec->ucsi->connector) { /* slow to register */
+ dev_err_ratelimited(uec->dev, "ucsi connector is not initialized yet\n");
+ return;
+ }
+
+ idx = gaokun_ucsi_refresh(uec);
+ if (idx == GAOKUN_UCSI_NO_PORT_UPDATE)
+ gaokun_ec_ucsi_pan_ack(uec->ec, idx); /* ack directly if no update */
+ else
+ gaokun_ucsi_handle_altmode(&uec->ports[idx]);
+}
+
+/*
+ * When inserting, 2 UCSI events(connector change) are followed by USB events.
+ * If we received one USB event, that means USB events are not blocked, so we
+ * can complelte for all ports, and we should signal all events.
+ */
+static void gaokun_ucsi_complete_usb_ack(struct gaokun_ucsi *uec)
+{
+ struct gaokun_ucsi_port *port;
+ int idx = 0;
+
+ while (idx < uec->num_ports) {
+ port = &uec->ports[idx++];
+ if (!completion_done(&port->usb_ack))
+ complete_all(&port->usb_ack);
+ }
+}
+
+/*
+ * USB event is necessary for enabling altmode, the event should follow
+ * UCSI event, if not after timeout(this notify may be disabled somehow),
+ * then force to enable altmode.
+ */
+static void gaokun_ucsi_handle_no_usb_event(struct gaokun_ucsi *uec, int idx)
+{
+ struct gaokun_ucsi_port *port;
+
+ port = &uec->ports[idx];
+ if (!wait_for_completion_timeout(&port->usb_ack, 2 * HZ)) {
+ dev_warn(uec->dev, "No USB EVENT, triggered by UCSI EVENT");
+ gaokun_ucsi_altmode_notify_ind(uec);
+ }
+}
+
+static int gaokun_ucsi_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ u32 cci;
+ int ret;
+ struct gaokun_ucsi *uec = container_of(nb, struct gaokun_ucsi, nb);
+
+ switch (action) {
+ case EC_EVENT_USB:
+ gaokun_ucsi_complete_usb_ack(uec);
+ gaokun_ucsi_altmode_notify_ind(uec);
+ return NOTIFY_OK;
+
+ case EC_EVENT_UCSI:
+ ret = gaokun_ucsi_read_cci(uec->ucsi, &cci);
+ if (ret)
+ return NOTIFY_DONE;
+
+ ucsi_notify_common(uec->ucsi, cci);
+ if (UCSI_CCI_CONNECTOR(cci))
+ gaokun_ucsi_handle_no_usb_event(uec, UCSI_CCI_CONNECTOR(cci) - 1);
+
+ return NOTIFY_OK;
+
+ default:
+ return NOTIFY_DONE;
+ }
+}
+
+static int gaokun_ucsi_ports_init(struct gaokun_ucsi *uec)
+{
+ struct gaokun_ucsi_port *ucsi_port;
+ struct gaokun_ucsi_reg ureg = {};
+ struct device *dev = uec->dev;
+ struct fwnode_handle *fwnode;
+ int i, ret, num_ports;
+ u32 port;
+
+ gaokun_ec_ucsi_get_reg(uec->ec, &ureg);
+ num_ports = ureg.num_ports;
+ uec->ports = devm_kcalloc(dev, num_ports, sizeof(*uec->ports),
+ GFP_KERNEL);
+ if (!uec->ports)
+ return -ENOMEM;
+
+ for (i = 0; i < num_ports; ++i) {
+ ucsi_port = &uec->ports[i];
+ ucsi_port->ccx = USBC_CCX_NONE;
+ ucsi_port->idx = i;
+ ucsi_port->ucsi = uec;
+ init_completion(&ucsi_port->usb_ack);
+ spin_lock_init(&ucsi_port->lock);
+ }
+
+ device_for_each_child_node(dev, fwnode) {
+ ret = fwnode_property_read_u32(fwnode, "reg", &port);
+ if (ret < 0) {
+ dev_err(dev, "missing reg property of %pOFn\n", fwnode);
+ fwnode_handle_put(fwnode);
+ return ret;
+ }
+
+ if (port >= num_ports) {
+ dev_warn(dev, "invalid connector number %d, ignoring\n", port);
+ continue;
+ }
+
+ ucsi_port = &uec->ports[port];
+ ucsi_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));
+ if (IS_ERR(ucsi_port->bridge)) {
+ fwnode_handle_put(fwnode);
+ return PTR_ERR(ucsi_port->bridge);
+ }
+ }
+
+ for (i = 0; i < num_ports; i++) {
+ if (!uec->ports[i].bridge)
+ continue;
+
+ ret = devm_drm_dp_hpd_bridge_add(dev, uec->ports[i].bridge);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gaokun_ucsi_register_worker(struct work_struct *work)
+{
+ struct gaokun_ucsi *uec;
+ struct ucsi *ucsi;
+ int ret;
+
+ uec = container_of(work, struct gaokun_ucsi, work.work);
+ ucsi = uec->ucsi;
+
+ ret = gaokun_ec_register_notify(uec->ec, &uec->nb);
+ if (ret) {
+ dev_err_probe(ucsi->dev, ret, "notifier register failed\n");
+ return;
+ }
+
+ ret = ucsi_register(ucsi);
+ if (ret)
+ dev_err_probe(ucsi->dev, ret, "ucsi register failed\n");
+}
+
+static int gaokun_ucsi_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct gaokun_ec *ec = adev->dev.platform_data;
+ struct device *dev = &adev->dev;
+ struct gaokun_ucsi *uec;
+ int ret;
+
+ uec = devm_kzalloc(dev, sizeof(*uec), GFP_KERNEL);
+ if (!uec)
+ return -ENOMEM;
+
+ uec->ec = ec;
+ uec->dev = dev;
+ uec->version = UCSI_VERSION_1_0;
+ uec->nb.notifier_call = gaokun_ucsi_notify;
+
+ INIT_DELAYED_WORK(&uec->work, gaokun_ucsi_register_worker);
+
+ ret = gaokun_ucsi_ports_init(uec);
+ if (ret)
+ return ret;
+
+ uec->ucsi = ucsi_create(dev, &gaokun_ucsi_ops);
+ if (IS_ERR(uec->ucsi))
+ return PTR_ERR(uec->ucsi);
+
+ ucsi_set_drvdata(uec->ucsi, uec);
+ auxiliary_set_drvdata(adev, uec);
+
+ /* EC can't handle UCSI properly in the early stage */
+ schedule_delayed_work(&uec->work, 3 * HZ);
+
+ return 0;
+}
+
+static void gaokun_ucsi_remove(struct auxiliary_device *adev)
+{
+ struct gaokun_ucsi *uec = auxiliary_get_drvdata(adev);
+
+ gaokun_ec_unregister_notify(uec->ec, &uec->nb);
+ ucsi_unregister(uec->ucsi);
+ ucsi_destroy(uec->ucsi);
+}
+
+static const struct auxiliary_device_id gaokun_ucsi_id_table[] = {
+ { .name = GAOKUN_MOD_NAME "." GAOKUN_DEV_UCSI, },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, gaokun_ucsi_id_table);
+
+static struct auxiliary_driver gaokun_ucsi_driver = {
+ .name = GAOKUN_DEV_UCSI,
+ .id_table = gaokun_ucsi_id_table,
+ .probe = gaokun_ucsi_probe,
+ .remove = gaokun_ucsi_remove,
+};
+
+module_auxiliary_driver(gaokun_ucsi_driver);
+
+MODULE_DESCRIPTION("HUAWEI Matebook E Go UCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index 139049368fdc..7d02470f19b9 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -85,6 +85,15 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
/* Redraw, so that we get putc(s) for output done while blanked */
return true;
}
+
+static bool dummycon_switch(struct vc_data *vc)
+{
+ /*
+ * Redraw, so that we get putc(s) for output done while switched
+ * away. Informs deferred consoles to take over the display.
+ */
+ return true;
+}
#else
static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
unsigned int x) { }
@@ -95,6 +104,10 @@ static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
{
return false;
}
+static bool dummycon_switch(struct vc_data *vc)
+{
+ return false;
+}
#endif
static const char *dummycon_startup(void)
@@ -124,11 +137,6 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
return false;
}
-static bool dummycon_switch(struct vc_data *vc)
-{
- return false;
-}
-
/*
* The console `switch' structure for the dummy console
*
diff --git a/drivers/video/screen_info_pci.c b/drivers/video/screen_info_pci.c
index 6c5833517141..66bfc1d0a6dc 100644
--- a/drivers/video/screen_info_pci.c
+++ b/drivers/video/screen_info_pci.c
@@ -7,8 +7,8 @@
static struct pci_dev *screen_info_lfb_pdev;
static size_t screen_info_lfb_bar;
-static resource_size_t screen_info_lfb_offset;
-static struct resource screen_info_lfb_res = DEFINE_RES_MEM(0, 0);
+static resource_size_t screen_info_lfb_res_start; // original start of resource
+static resource_size_t screen_info_lfb_offset; // framebuffer offset within resource
static bool __screen_info_relocation_is_valid(const struct screen_info *si, struct resource *pr)
{
@@ -31,7 +31,7 @@ void screen_info_apply_fixups(void)
if (screen_info_lfb_pdev) {
struct resource *pr = &screen_info_lfb_pdev->resource[screen_info_lfb_bar];
- if (pr->start != screen_info_lfb_res.start) {
+ if (pr->start != screen_info_lfb_res_start) {
if (__screen_info_relocation_is_valid(si, pr)) {
/*
* Only update base if we have an actual
@@ -47,46 +47,67 @@ void screen_info_apply_fixups(void)
}
}
+static int __screen_info_lfb_pci_bus_region(const struct screen_info *si, unsigned int type,
+ struct pci_bus_region *r)
+{
+ u64 base, size;
+
+ base = __screen_info_lfb_base(si);
+ if (!base)
+ return -EINVAL;
+
+ size = __screen_info_lfb_size(si, type);
+ if (!size)
+ return -EINVAL;
+
+ r->start = base;
+ r->end = base + size - 1;
+
+ return 0;
+}
+
static void screen_info_fixup_lfb(struct pci_dev *pdev)
{
unsigned int type;
- struct resource res[SCREEN_INFO_MAX_RESOURCES];
- size_t i, numres;
+ struct pci_bus_region bus_region;
int ret;
+ struct resource r = {
+ .flags = IORESOURCE_MEM,
+ };
+ const struct resource *pr;
const struct screen_info *si = &screen_info;
if (screen_info_lfb_pdev)
return; // already found
type = screen_info_video_type(si);
- if (type != VIDEO_TYPE_EFI)
- return; // only applies to EFI
+ if (!__screen_info_has_lfb(type))
+ return; // only applies to EFI; maybe VESA
- ret = screen_info_resources(si, res, ARRAY_SIZE(res));
+ ret = __screen_info_lfb_pci_bus_region(si, type, &bus_region);
if (ret < 0)
return;
- numres = ret;
- for (i = 0; i < numres; ++i) {
- struct resource *r = &res[i];
- const struct resource *pr;
-
- if (!(r->flags & IORESOURCE_MEM))
- continue;
- pr = pci_find_resource(pdev, r);
- if (!pr)
- continue;
-
- /*
- * We've found a PCI device with the framebuffer
- * resource. Store away the parameters to track
- * relocation of the framebuffer aperture.
- */
- screen_info_lfb_pdev = pdev;
- screen_info_lfb_bar = pr - pdev->resource;
- screen_info_lfb_offset = r->start - pr->start;
- memcpy(&screen_info_lfb_res, r, sizeof(screen_info_lfb_res));
- }
+ /*
+ * Translate the PCI bus address to resource. Account
+ * for an offset if the framebuffer is behind a PCI host
+ * bridge.
+ */
+ pcibios_bus_to_resource(pdev->bus, &r, &bus_region);
+
+ pr = pci_find_resource(pdev, &r);
+ if (!pr)
+ return;
+
+ /*
+ * We've found a PCI device with the framebuffer
+ * resource. Store away the parameters to track
+ * relocation of the framebuffer aperture.
+ */
+ screen_info_lfb_pdev = pdev;
+ screen_info_lfb_bar = pr - pdev->resource;
+ screen_info_lfb_offset = r.start - pr->start;
+ screen_info_lfb_res_start = bus_region.start;
}
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16,
screen_info_fixup_lfb);
diff --git a/drivers/virt/acrn/irqfd.c b/drivers/virt/acrn/irqfd.c
index b7da24ca1475..64d32c8fbf79 100644
--- a/drivers/virt/acrn/irqfd.c
+++ b/drivers/virt/acrn/irqfd.c
@@ -16,8 +16,6 @@
#include "acrn_drv.h"
-static LIST_HEAD(acrn_irqfd_clients);
-
/**
* struct hsm_irqfd - Properties of HSM irqfd
* @vm: Associated VM pointer
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 691978cddab7..e6b59d921076 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -194,16 +194,16 @@ static void w1_netlink_queue_status(struct w1_cb_block *block,
static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
int portid, int error)
{
- struct {
- struct cn_msg cn;
- struct w1_netlink_msg msg;
- } packet;
- memcpy(&packet.cn, cn, sizeof(packet.cn));
- memcpy(&packet.msg, msg, sizeof(packet.msg));
- packet.cn.len = sizeof(packet.msg);
- packet.msg.len = 0;
- packet.msg.status = (u8)-error;
- cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL);
+ DEFINE_RAW_FLEX(struct cn_msg, packet, data,
+ sizeof(struct w1_netlink_msg));
+ struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data;
+
+ *packet = *cn;
+ *pkt_msg = *msg;
+ packet->len = sizeof(*pkt_msg);
+ pkt_msg->len = 0;
+ pkt_msg->status = (u8)-error;
+ cn_netlink_send(packet, portid, 0, GFP_KERNEL);
}
/**
@@ -215,22 +215,20 @@ static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
*/
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
{
- struct {
- struct cn_msg cn;
- struct w1_netlink_msg msg;
- } packet;
- memset(&packet, 0, sizeof(packet));
+ DEFINE_RAW_FLEX(struct cn_msg, packet, data,
+ sizeof(struct w1_netlink_msg));
+ struct w1_netlink_msg *pkt_msg = (struct w1_netlink_msg *)packet->data;
- packet.cn.id.idx = CN_W1_IDX;
- packet.cn.id.val = CN_W1_VAL;
+ packet->id.idx = CN_W1_IDX;
+ packet->id.val = CN_W1_VAL;
- packet.cn.seq = dev->seq++;
- packet.cn.len = sizeof(*msg);
+ packet->seq = dev->seq++;
+ packet->len = sizeof(*msg);
- memcpy(&packet.msg, msg, sizeof(*msg));
- packet.msg.len = 0;
+ *pkt_msg = *msg;
+ pkt_msg->len = 0;
- cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);
+ cn_netlink_send(packet, 0, 0, GFP_KERNEL);
}
static void w1_send_slave(struct w1_master *dev, u64 rn)