0d9d32f54c
-----BEGIN PGP SIGNATURE----- iQIyBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmQModwACgkQONu9yGCS aT7W7A/1EyhortcaMdZXEkdl7kZYupASsOm2QgOzeRkK0ELtbYRTt1qXdZgl40hU binrh5Yib2avHTEAF9I6AKVXMirSUTtODe/zQ7icyxVNcXeanlIbobEVBzSWIBtC Wxj129KZyCQlucagWihngQ9D+66bvD5JCsJ3EHKJjpheSqmZI88KVnOSnvyoJArj yLDY21UgxRN4KASgB+tpLBT4x0yN9zk8VuCGpyJjO/nHzhj6Y6DkOcx2q7hAxdn+ H1OBCQ2QBCODCMrpW4xBuwy2blBZsRytUdEy8JsfxjgXvUp8+TdxUsuxb16a31jW pVo9LYB0cdKVoAzNJ2pTD8rhaATSbq+2MYDEUYCz8Rr+dZ/Nt2nTKSYeJprLsTwx TzPRNErQMKxKoQUQU/seWx47ebwt+Z8Rk4FAoyQMxRITw/9bBGLWpDKrGjNsByz9 A2Q9UU+uM+jyqZnjQMvkzKSznggwfJ+SgaeqDMjwyyCQysJS8DTXPr9nA+IC9cht Kz00QetNgvPvZPE/gg81XOcKtJVTmA4AITQ0PlxYJT0hHCHx02GxvdPH2XBspgUt aNbDgVsupq8ONvRZlEf9hJKltTUmIRvI9JSOXnuhaN2jCv88SNv1M0TKfAo0XDNK Z/prv3qCnugMZ0KB0TD7d09XqSlKbefOq8TdtbXoTcC0NzFQkw== =29jZ -----END PGP SIGNATURE----- Merge 5.4.235 into android11-5.4-lts Changes in 5.4.235 HID: asus: Remove check for same LED brightness on set HID: asus: use spinlock to protect concurrent accesses HID: asus: use spinlock to safely schedule workers ARM: OMAP2+: Fix memory leak in realtime_counter_init() arm64: dts: qcom: qcs404: use symbol names for PCIe resets ARM: zynq: Fix refcount leak in zynq_early_slcr_init arm64: dts: meson-gx: Fix Ethernet MAC address unit name arm64: dts: meson-g12a: Fix internal Ethernet PHY unit name arm64: dts: meson-gx: Fix the SCPI DVFS node name and unit address arm64: dts: meson: remove CPU opps below 1GHz for G12A boards ARM: OMAP1: call platform_device_put() in error case in omap1_dm_timer_init() ARM: dts: exynos: correct wr-active property in Exynos3250 Rinato ARM: imx: Call ida_simple_remove() for ida_simple_get arm64: dts: amlogic: meson-gx: fix SCPI clock dvfs node name arm64: dts: amlogic: meson-axg: fix SCPI clock dvfs node name arm64: dts: amlogic: meson-gx: add missing SCPI sensors compatible arm64: dts: amlogic: meson-gx: add missing unit address to rng node name arm64: dts: amlogic: meson-gxl: add missing unit address to eth-phy-mux node name arm64: dts: amlogic: meson-gxl-s905d-phicomm-n1: fix led node name ARM: dts: imx7s: correct iomuxc gpr mux controller cells arm64: dts: mediatek: mt7622: Add missing pwm-cells to pwm node Revert "scsi: core: run queue if SCSI device queue isn't ready and queue is idle" block: Limit number of items taken from the I/O scheduler in one go blk-mq: remove stale comment for blk_mq_sched_mark_restart_hctx blk-mq: wait on correct sbitmap_queue in blk_mq_mark_tag_wait blk-mq: correct stale comment of .get_budget s390/dasd: Prepare for additional path event handling s390/dasd: Fix potential memleak in dasd_eckd_init() sched/deadline,rt: Remove unused parameter from pick_next_[rt|dl]_entity() sched/rt: pick_next_rt_entity(): check list_entry block: bio-integrity: Copy flags when bio_integrity_payload is cloned wifi: rsi: Fix memory leak in rsi_coex_attach() net/wireless: Delete unnecessary checks before the macro call “dev_kfree_skb” wifi: iwlegacy: common: don't call dev_kfree_skb() under spin_lock_irqsave() wifi: libertas: fix memory leak in lbs_init_adapter() wifi: rtl8xxxu: don't call dev_kfree_skb() under spin_lock_irqsave() rtlwifi: fix -Wpointer-sign warning wifi: rtlwifi: Fix global-out-of-bounds bug in _rtl8812ae_phy_set_txpower_limit() ipw2x00: switch from 'pci_' to 'dma_' API wifi: ipw2x00: don't call dev_kfree_skb() under spin_lock_irqsave() wifi: ipw2200: fix memory leak in ipw_wdev_init() wilc1000: let wilc_mac_xmit() return NETDEV_TX_OK wifi: wilc1000: fix potential memory leak in wilc_mac_xmit() wifi: brcmfmac: fix potential memory leak in brcmf_netdev_start_xmit() wifi: brcmfmac: unmap dma buffer in brcmf_msgbuf_alloc_pktid() wifi: libertas_tf: don't call kfree_skb() under spin_lock_irqsave() wifi: libertas: if_usb: don't call kfree_skb() under spin_lock_irqsave() wifi: libertas: main: don't call kfree_skb() under spin_lock_irqsave() wifi: libertas: cmdresp: don't call kfree_skb() under spin_lock_irqsave() wifi: wl3501_cs: don't call kfree_skb() under spin_lock_irqsave() crypto: x86/ghash - fix unaligned access in ghash_setkey() ACPICA: Drop port I/O validation for some regions genirq: Fix the return type of kstat_cpu_irqs_sum() lib/mpi: Fix buffer overrun when SG is too long ACPICA: nsrepair: handle cases without a return value correctly wifi: orinoco: check return value of hermes_write_wordrec() wifi: ath9k: htc_hst: free skb in ath9k_htc_rx_msg() if there is no callback function ath9k: hif_usb: simplify if-if to if-else ath9k: htc: clean up statistics macros wifi: ath9k: hif_usb: clean up skbs if ath9k_hif_usb_rx_stream() fails wifi: ath9k: Fix potential stack-out-of-bounds write in ath9k_wmi_rsp_callback() ACPI: battery: Fix missing NUL-termination with large strings crypto: ccp - Failure on re-initialization due to duplicate sysfs filename crypto: essiv - remove redundant null pointer check before kfree crypto: essiv - Handle EBUSY correctly crypto: seqiv - Handle EBUSY correctly powercap: fix possible name leak in powercap_register_zone() net/mlx5: Enhance debug print in page allocation failure irqchip/alpine-msi: Fix refcount leak in alpine_msix_init_domains irqchip/irq-mvebu-gicp: Fix refcount leak in mvebu_gicp_probe irqchip/ti-sci: Fix refcount leak in ti_sci_intr_irq_domain_probe mptcp: add sk_stop_timer_sync helper net: add sock_init_data_uid() tun: tun_chr_open(): correctly initialize socket uid tap: tap_open(): correctly initialize socket uid OPP: fix error checking in opp_migrate_dentry() Bluetooth: L2CAP: Fix potential user-after-free libbpf: Fix alen calculation in libbpf_nla_dump_errormsg() rds: rds_rm_zerocopy_callback() correct order for list_add_tail() crypto: rsa-pkcs1pad - Use akcipher_request_complete m68k: /proc/hardware should depend on PROC_FS RISC-V: time: initialize hrtimer based broadcast clock event device usb: gadget: udc: Avoid tasklet passing a global treewide: Replace DECLARE_TASKLET() with DECLARE_TASKLET_OLD() wifi: iwl3945: Add missing check for create_singlethread_workqueue wifi: iwl4965: Add missing check for create_singlethread_workqueue() wifi: mwifiex: fix loop iterator in mwifiex_update_ampdu_txwinsize() crypto: crypto4xx - Call dma_unmap_page when done wifi: mac80211: make rate u32 in sta_set_rate_info_rx() thermal/drivers/hisi: Drop second sensor hi3660 can: esd_usb: Move mislocated storage of SJA1000_ECC_SEG bits in case of a bus error irqchip/irq-brcmstb-l2: Set IRQ_LEVEL for level triggered interrupts irqchip/irq-bcm7120-l2: Set IRQ_LEVEL for level triggered interrupts selftests/net: Interpret UDP_GRO cmsg data as an int value selftest: fib_tests: Always cleanup before exit drm/fourcc: Add missing big-endian XRGB1555 and RGB565 formats drm: mxsfb: DRM_MXSFB should depend on ARCH_MXS || ARCH_MXC drm/bridge: megachips: Fix error handling in i2c_register_driver() drm/vc4: dpi: Add option for inverting pixel clock and output enable drm/vc4: dpi: Fix format mapping for RGB565 gpu: ipu-v3: common: Add of_node_put() for reference returned by of_graph_get_port_by_id() drm/msm/hdmi: Add missing check for alloc_ordered_workqueue pinctrl: stm32: Fix refcount leak in stm32_pctrl_get_irq_domain ASoC: fsl_sai: initialize is_dsp_mode flag ALSA: hda/ca0132: minor fix for allocation size drm/mipi-dsi: Fix byte order of 16-bit DCS set/get brightness drm/msm: use strscpy instead of strncpy drm/msm/dpu: Add check for cstate drm/msm/dpu: Add check for pstates drm/exynos: Don't reset bridge->next drm/bridge: Rename bridge helpers targeting a bridge chain drm/bridge: Introduce drm_bridge_get_next_bridge() drm: Initialize struct drm_crtc_state.no_vblank from device settings drm/msm/mdp5: Add check for kzalloc gpu: host1x: Don't skip assigning syncpoints to channels drm/mediatek: remove cast to pointers passed to kfree drm/mediatek: Use NULL instead of 0 for NULL pointer drm/mediatek: Drop unbalanced obj unref drm/mediatek: Clean dangling pointer on bind error path ASoC: soc-compress.c: fixup private_data on snd_soc_new_compress() gpio: vf610: connect GPIO label to dev name hwmon: (ltc2945) Handle error case in ltc2945_value_store scsi: aic94xx: Add missing check for dma_map_single() spi: bcm63xx-hsspi: fix pm_runtime spi: bcm63xx-hsspi: Fix multi-bit mode setting hwmon: (mlxreg-fan) Return zero speed for broken fan dm: remove flush_scheduled_work() during local_exit() spi: synquacer: Fix timeout handling in synquacer_spi_transfer_one() ASoC: dapm: declare missing structure prototypes ASoC: soc-dapm.h: fixup warning struct snd_pcm_substream not declared HID: bigben: use spinlock to protect concurrent accesses HID: bigben_worker() remove unneeded check on report_field HID: bigben: use spinlock to safely schedule workers HID: asus: Only set EV_REP if we are adding a mapping HID: asus: Add report_size to struct asus_touchpad_info HID: asus: Add support for multi-touch touchpad on Medion Akoya E1239T HID: asus: Fix mute and touchpad-toggle keys on Medion Akoya E1239T hid: bigben_probe(): validate report count nfsd: fix race to check ls_layouts cifs: Fix lost destroy smbd connection when MR allocate failed cifs: Fix warning and UAF when destroy the MR list gfs2: jdata writepage fix perf llvm: Fix inadvertent file creation perf tools: Fix auto-complete on aarch64 sparc: allow PM configs for sparc32 COMPILE_TEST selftests/ftrace: Fix bash specific "==" operator mfd: pcf50633-adc: Fix potential memleak in pcf50633_adc_async_read() clk: qcom: gcc-qcs404: disable gpll[04]_out_aux parents clk: qcom: gcc-qcs404: fix names of the DSI clocks used as parents mtd: rawnand: sunxi: Fix the size of the last OOB region clk: renesas: cpg-mssr: Fix use after free if cpg_mssr_common_init() failed clk: renesas: cpg-mssr: Use enum clk_reg_layout instead of a boolean flag clk: renesas: cpg-mssr: Remove superfluous check in resume code Input: ads7846 - don't report pressure for ads7845 Input: ads7846 - don't check penirq immediately for 7845 clk: qcom: gpucc-sdm845: fix clk_dis_wait being programmed for CX GDSC powerpc/powernv/ioda: Skip unallocated resources when mapping to PE clk: Honor CLK_OPS_PARENT_ENABLE in clk_core_is_enabled() powerpc/pseries/lpar: add missing RTAS retry status handling powerpc/pseries/lparcfg: add missing RTAS retry status handling powerpc/rtas: make all exports GPL powerpc/rtas: ensure 4KB alignment for rtas_data_buf powerpc/eeh: Small refactor of eeh_handle_normal_event() powerpc/eeh: Set channel state after notifying the drivers MIPS: SMP-CPS: fix build error when HOTPLUG_CPU not set MIPS: vpe-mt: drop physical_memsize remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers media: platform: ti: Add missing check for devm_regulator_get powerpc: Remove linker flag from KBUILD_AFLAGS media: ov5675: Fix memleak in ov5675_init_controls() media: i2c: ov772x: Fix memleak in ov772x_probe() media: rc: Fix use-after-free bugs caused by ene_tx_irqsim() media: i2c: ov7670: 0 instead of -EINVAL was returned media: usb: siano: Fix use after free bugs caused by do_submit_urb rpmsg: glink: Avoid infinite loop on intent for missing channel udf: Define EFSCORRUPTED error code ARM: dts: exynos: Use Exynos5420 compatible for the MIPI video phy blk-iocost: fix divide by 0 error in calc_lcoefs() wifi: brcmfmac: Fix potential stack-out-of-bounds in brcmf_c_preinit_dcmds() rcu: Suppress smp_processor_id() complaint in synchronize_rcu_expedited_wait() thermal: intel: Fix unsigned comparison with less than zero timers: Prevent union confusion from unexpected restart_syscall() x86/bugs: Reset speculation control settings on init wifi: brcmfmac: ensure CLM version is null-terminated to prevent stack-out-of-bounds wifi: mt7601u: fix an integer underflow inet: fix fast path in __inet_hash_connect() ice: add missing checks for PF vsi type ACPI: Don't build ACPICA with '-Os' net: bcmgenet: Add a check for oversized packets m68k: Check syscall_trace_enter() return code wifi: mt76: dma: free rx_head in mt76_dma_rx_cleanup ACPI: video: Fix Lenovo Ideapad Z570 DMI match net/mlx5: fw_tracer: Fix debug print coda: Avoid partial allocation of sig_inputArgs uaccess: Add minimum bounds check on kernel buffer size drm/amd/display: Fix potential null-deref in dm_resume drm/omap: dsi: Fix excessive stack usage HID: Add Mapping for System Microphone Mute drm/radeon: free iio for atombios when driver shutdown drm/msm/dsi: Add missing check for alloc_ordered_workqueue docs/scripts/gdb: add necessary make scripts_gdb step ASoC: kirkwood: Iterate over array indexes instead of using pointer math regulator: max77802: Bounds check regulator id against opmode regulator: s5m8767: Bounds check id indexing into arrays hwmon: (coretemp) Simplify platform device handling pinctrl: at91: use devm_kasprintf() to avoid potential leaks drm: panel-orientation-quirks: Add quirk for Lenovo IdeaPad Duet 3 10IGL5 dm thin: add cond_resched() to various workqueue loops dm cache: add cond_resched() to various workqueue loops nfsd: zero out pointers after putting nfsd_files on COPY setup error wifi: rtl8xxxu: fixing transmisison failure for rtl8192eu firmware: coreboot: framebuffer: Ignore reserved pixel color bits rtc: pm8xxx: fix set-alarm race ipmi_ssif: Rename idle state and check s390: discard .interp section s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler s390/kprobes: fix current_kprobe never cleared after kprobes reenter ARM: dts: exynos: correct HDMI phy compatible in Exynos4 hfs: fix missing hfs_bnode_get() in __hfs_bnode_create fs: hfsplus: fix UAF issue in hfsplus_put_super f2fs: fix information leak in f2fs_move_inline_dirents() f2fs: fix cgroup writeback accounting with fs-layer encryption ocfs2: fix defrag path triggering jbd2 ASSERT ocfs2: fix non-auto defrag path not working issue udf: Truncate added extents on failed expansion udf: Do not bother merging very long extents udf: Do not update file length for failed writes to inline files udf: Preserve link count of system files udf: Detect system inodes linked into directory hierarchy udf: Fix file corruption when appending just after end of preallocated extent KVM: Destroy target device if coalesced MMIO unregistration fails KVM: s390: disable migration mode when dirty tracking is disabled x86/virt: Force GIF=1 prior to disabling SVM (for reboot flows) x86/crash: Disable virt in core NMI crash handler to avoid double shootdown x86/reboot: Disable virtualization in an emergency if SVM is supported x86/reboot: Disable SVM, not just VMX, when stopping CPUs x86/kprobes: Fix __recover_optprobed_insn check optimizing logic x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe range x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter x86/microcode/AMD: Add a @cpu parameter to the reloading functions x86/microcode/AMD: Fix mixed steppings support x86/speculation: Allow enabling STIBP with legacy IBRS Documentation/hw-vuln: Document the interaction between IBRS and STIBP ima: Align ima_file_mmap() parameters with mmap_file LSM hook irqdomain: Fix association race irqdomain: Fix disassociation race irqdomain: Drop bogus fwspec-mapping error handling ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls() ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC ext4: optimize ea_inode block expansion ext4: refuse to create ea block when umounted wifi: rtl8xxxu: Use a longer retry limit of 48 wifi: cfg80211: Fix use after free for wext thermal: intel: powerclamp: Fix cur_state for multi package system dm flakey: fix logic when corrupting a bio dm flakey: don't corrupt the zero page ARM: dts: exynos: correct TMU phandle in Exynos4 ARM: dts: exynos: correct TMU phandle in Odroid XU rbd: avoid use-after-free in do_rbd_add() when rbd_dev_create() fails alpha: fix FEN fault handling mips: fix syscall_get_nr media: ipu3-cio2: Fix PM runtime usage_count in driver unbind mm: memcontrol: deprecate charge moving mm/thp: check and bail out if page in deferred queue already ktest.pl: Give back console on Ctrt^C on monitor ktest.pl: Fix missing "end_monitor" when machine check fails ktest.pl: Add RUN_TIMEOUT option with default unlimited scsi: qla2xxx: Fix link failure in NPIV environment scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests scsi: qla2xxx: Fix erroneous link down scsi: ses: Don't attach if enclosure has no components scsi: ses: Fix slab-out-of-bounds in ses_enclosure_data_process() scsi: ses: Fix possible addl_desc_ptr out-of-bounds accesses scsi: ses: Fix possible desc_ptr out-of-bounds accesses scsi: ses: Fix slab-out-of-bounds in ses_intf_remove() PCI/PM: Observe reset delay irrespective of bridge_d3 PCI: hotplug: Allow marking devices as disconnected during bind/unbind PCI: Avoid FLR for AMD FCH AHCI adapters drm/i915/quirks: Add inverted backlight quirk for HP 14-r206nv drm/radeon: Fix eDP for single-display iMac11,2 wifi: ath9k: use proper statements in conditionals kbuild: Port silent mode detection to future gnu make. net/sched: Retire tcindex classifier fs/jfs: fix shift exponent db_agl2size negative pwm: sifive: Reduce time the controller lock is held pwm: sifive: Always let the first pwm_apply_state succeed pwm: stm32-lp: fix the check on arr and cmp registers update f2fs: use memcpy_{to,from}_page() where possible fs: f2fs: initialize fsdata in pagecache_write() um: vector: Fix memory leak in vector_config ubi: ensure that VID header offset + VID header size <= alloc, size ubifs: Fix build errors as symbol undefined ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted ubifs: Rectify space budget for ubifs_xrename() ubifs: Fix wrong dirty space budget for dirty inode ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1 ubifs: Reserve one leb for each journal head while doing budget ubi: Fix use-after-free when volume resizing failed ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume() ubifs: Fix memory leak in alloc_wbufs() ubi: Fix possible null-ptr-deref in ubi_free_volume() ubifs: Re-statistic cleaned znode count if commit failed ubifs: dirty_cow_znode: Fix memleak in error handling path ubifs: ubifs_writepage: Mark page dirty after writing inode failed ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show() ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed x86: um: vdso: Add '%rcx' and '%r11' to the syscall clobber list watchdog: at91sam9_wdt: use devm_request_irq to avoid missing free_irq() in error path watchdog: Fix kmemleak in watchdog_cdev_register watchdog: pcwd_usb: Fix attempting to access uninitialized memory netfilter: ctnetlink: fix possible refcount leak in ctnetlink_create_conntrack() ipv6: Add lwtunnel encap size of all siblings in nexthop calculation sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop net: fix __dev_kfree_skb_any() vs drop monitor 9p/xen: fix version parsing 9p/xen: fix connection sequence 9p/rdma: unmap receive dma buffer in rdma_request()/post_recv() net/mlx5: Geneve, Fix handling of Geneve object id as error code nfc: fix memory leak of se_io context in nfc_genl_se_io net/sched: act_sample: fix action bind logic ARM: dts: spear320-hmi: correct STMPE GPIO compatible tcp: tcp_check_req() can be called from process context vc_screen: modify vcs_size() handling in vcs_read() rtc: sun6i: Make external 32k oscillator optional rtc: sun6i: Always export the internal oscillator scsi: ipr: Work around fortify-string warning thermal: intel: quark_dts: fix error pointer dereference thermal: intel: BXT_PMIC: select REGMAP instead of depending on it tracing: Add NULL checks for buffer in ring_buffer_free_read_page() firmware/efi sysfb_efi: Add quirk for Lenovo IdeaPad Duet 3 mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak media: uvcvideo: Handle cameras with invalid descriptors media: uvcvideo: Handle errors from calls to usb_string media: uvcvideo: Quirk for autosuspend in Logitech B910 and C910 media: uvcvideo: Silence memcpy() run-time false positive warnings staging: emxx_udc: Add checks for dma_alloc_coherent() tty: fix out-of-bounds access in tty_driver_lookup_tty() tty: serial: fsl_lpuart: disable the CTS when send break signal mei: bus-fixup:upon error print return values of send and receive tools/iio/iio_utils:fix memory leak iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_status_word() iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_config_word() usb: host: xhci: mvebu: Iterate over array indexes instead of using pointer math USB: ene_usb6250: Allocate enough memory for full object usb: uvc: Enumerate valid values for color matching kernel/fail_function: fix memory leak with using debugfs_lookup() PCI: Add ACS quirk for Wangxun NICs phy: rockchip-typec: Fix unsigned comparison with less than zero net: tls: avoid hanging tasks on the tx_lock x86/resctrl: Apply READ_ONCE/WRITE_ONCE to task_struct.{rmid,closid} x86/resctl: fix scheduler confusion with 'current' Bluetooth: hci_sock: purge socket queues in the destruct() callback tcp: Fix listen() regression in 5.4.229. media: uvcvideo: Provide sync and async uvc_ctrl_status_event media: uvcvideo: Fix race condition with usb_kill_urb dt-bindings: rtc: sun6i-a31-rtc: Loosen the requirements on the clocks Linux 5.4.235 Change-Id: I256ca8288bf61707f5103c9b7c7831da0d7a08a0 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
349 lines
9.2 KiB
C
349 lines
9.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2017-2018 SiFive
|
|
* For SiFive's PWM IP block documentation please refer Chapter 14 of
|
|
* Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
|
|
*
|
|
* Limitations:
|
|
* - When changing both duty cycle and period, we cannot prevent in
|
|
* software that the output might produce a period with mixed
|
|
* settings (new period length and old duty cycle).
|
|
* - The hardware cannot generate a 100% duty cycle.
|
|
* - The hardware generates only inverted output.
|
|
*/
|
|
#include <linux/clk.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pwm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/bitfield.h>
|
|
|
|
/* Register offsets */
|
|
#define PWM_SIFIVE_PWMCFG 0x0
|
|
#define PWM_SIFIVE_PWMCOUNT 0x8
|
|
#define PWM_SIFIVE_PWMS 0x10
|
|
#define PWM_SIFIVE_PWMCMP0 0x20
|
|
|
|
/* PWMCFG fields */
|
|
#define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0)
|
|
#define PWM_SIFIVE_PWMCFG_STICKY BIT(8)
|
|
#define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9)
|
|
#define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10)
|
|
#define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12)
|
|
#define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13)
|
|
#define PWM_SIFIVE_PWMCFG_CENTER BIT(16)
|
|
#define PWM_SIFIVE_PWMCFG_GANG BIT(24)
|
|
#define PWM_SIFIVE_PWMCFG_IP BIT(28)
|
|
|
|
/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
|
|
#define PWM_SIFIVE_SIZE_PWMCMP 4
|
|
#define PWM_SIFIVE_CMPWIDTH 16
|
|
#define PWM_SIFIVE_DEFAULT_PERIOD 10000000
|
|
|
|
struct pwm_sifive_ddata {
|
|
struct pwm_chip chip;
|
|
struct mutex lock; /* lock to protect user_count and approx_period */
|
|
struct notifier_block notifier;
|
|
struct clk *clk;
|
|
void __iomem *regs;
|
|
unsigned int real_period;
|
|
unsigned int approx_period;
|
|
int user_count;
|
|
};
|
|
|
|
static inline
|
|
struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c)
|
|
{
|
|
return container_of(c, struct pwm_sifive_ddata, chip);
|
|
}
|
|
|
|
static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
|
|
|
mutex_lock(&ddata->lock);
|
|
ddata->user_count++;
|
|
mutex_unlock(&ddata->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
|
|
|
mutex_lock(&ddata->lock);
|
|
ddata->user_count--;
|
|
mutex_unlock(&ddata->lock);
|
|
}
|
|
|
|
/* Called holding ddata->lock */
|
|
static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
|
|
unsigned long rate)
|
|
{
|
|
unsigned long long num;
|
|
unsigned long scale_pow;
|
|
int scale;
|
|
u32 val;
|
|
/*
|
|
* The PWM unit is used with pwmzerocmp=0, so the only way to modify the
|
|
* period length is using pwmscale which provides the number of bits the
|
|
* counter is shifted before being feed to the comparators. A period
|
|
* lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
|
|
* (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
|
|
*/
|
|
scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC);
|
|
scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
|
|
|
|
val = PWM_SIFIVE_PWMCFG_EN_ALWAYS |
|
|
FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
|
|
writel(val, ddata->regs + PWM_SIFIVE_PWMCFG);
|
|
|
|
/* As scale <= 15 the shift operation cannot overflow. */
|
|
num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale);
|
|
ddata->real_period = div64_ul(num, rate);
|
|
dev_dbg(ddata->chip.dev,
|
|
"New real_period = %u ns\n", ddata->real_period);
|
|
}
|
|
|
|
static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
struct pwm_state *state)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
|
u32 duty, val;
|
|
|
|
duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 +
|
|
pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
|
|
|
|
state->enabled = duty > 0;
|
|
|
|
val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
|
|
if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS))
|
|
state->enabled = false;
|
|
|
|
state->period = ddata->real_period;
|
|
state->duty_cycle =
|
|
(u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH;
|
|
state->polarity = PWM_POLARITY_INVERSED;
|
|
}
|
|
|
|
static int pwm_sifive_enable(struct pwm_chip *chip, bool enable)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
|
int ret;
|
|
|
|
if (enable) {
|
|
ret = clk_enable(ddata->clk);
|
|
if (ret) {
|
|
dev_err(ddata->chip.dev, "Enable clk failed\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (!enable)
|
|
clk_disable(ddata->clk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
const struct pwm_state *state)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
|
struct pwm_state cur_state;
|
|
unsigned int duty_cycle;
|
|
unsigned long long num;
|
|
bool enabled;
|
|
int ret = 0;
|
|
u32 frac;
|
|
|
|
if (state->polarity != PWM_POLARITY_INVERSED)
|
|
return -EINVAL;
|
|
|
|
ret = clk_enable(ddata->clk);
|
|
if (ret) {
|
|
dev_err(ddata->chip.dev, "Enable clk failed\n");
|
|
return ret;
|
|
}
|
|
|
|
cur_state = pwm->state;
|
|
enabled = cur_state.enabled;
|
|
|
|
duty_cycle = state->duty_cycle;
|
|
if (!state->enabled)
|
|
duty_cycle = 0;
|
|
|
|
/*
|
|
* The problem of output producing mixed setting as mentioned at top,
|
|
* occurs here. To minimize the window for this problem, we are
|
|
* calculating the register values first and then writing them
|
|
* consecutively
|
|
*/
|
|
num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH);
|
|
frac = DIV64_U64_ROUND_CLOSEST(num, state->period);
|
|
/* The hardware cannot generate a 100% duty cycle */
|
|
frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
|
|
|
|
mutex_lock(&ddata->lock);
|
|
if (state->period != ddata->approx_period) {
|
|
/*
|
|
* Don't let a 2nd user change the period underneath the 1st user.
|
|
* However if ddate->approx_period == 0 this is the first time we set
|
|
* any period, so let whoever gets here first set the period so other
|
|
* users who agree on the period won't fail.
|
|
*/
|
|
if (ddata->user_count != 1 && ddata->approx_period) {
|
|
mutex_unlock(&ddata->lock);
|
|
ret = -EBUSY;
|
|
goto exit;
|
|
}
|
|
ddata->approx_period = state->period;
|
|
pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
|
|
}
|
|
mutex_unlock(&ddata->lock);
|
|
|
|
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 +
|
|
pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
|
|
|
|
if (state->enabled != enabled)
|
|
pwm_sifive_enable(chip, state->enabled);
|
|
|
|
exit:
|
|
clk_disable(ddata->clk);
|
|
return ret;
|
|
}
|
|
|
|
static const struct pwm_ops pwm_sifive_ops = {
|
|
.request = pwm_sifive_request,
|
|
.free = pwm_sifive_free,
|
|
.get_state = pwm_sifive_get_state,
|
|
.apply = pwm_sifive_apply,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static int pwm_sifive_clock_notifier(struct notifier_block *nb,
|
|
unsigned long event, void *data)
|
|
{
|
|
struct clk_notifier_data *ndata = data;
|
|
struct pwm_sifive_ddata *ddata =
|
|
container_of(nb, struct pwm_sifive_ddata, notifier);
|
|
|
|
if (event == POST_RATE_CHANGE) {
|
|
mutex_lock(&ddata->lock);
|
|
pwm_sifive_update_clock(ddata, ndata->new_rate);
|
|
mutex_unlock(&ddata->lock);
|
|
}
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static int pwm_sifive_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct pwm_sifive_ddata *ddata;
|
|
struct pwm_chip *chip;
|
|
struct resource *res;
|
|
int ret;
|
|
|
|
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
|
|
if (!ddata)
|
|
return -ENOMEM;
|
|
|
|
mutex_init(&ddata->lock);
|
|
chip = &ddata->chip;
|
|
chip->dev = dev;
|
|
chip->ops = &pwm_sifive_ops;
|
|
chip->of_xlate = of_pwm_xlate_with_flags;
|
|
chip->of_pwm_n_cells = 3;
|
|
chip->base = -1;
|
|
chip->npwm = 4;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
ddata->regs = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(ddata->regs))
|
|
return PTR_ERR(ddata->regs);
|
|
|
|
ddata->clk = devm_clk_get(dev, NULL);
|
|
if (IS_ERR(ddata->clk)) {
|
|
if (PTR_ERR(ddata->clk) != -EPROBE_DEFER)
|
|
dev_err(dev, "Unable to find controller clock\n");
|
|
return PTR_ERR(ddata->clk);
|
|
}
|
|
|
|
ret = clk_prepare_enable(ddata->clk);
|
|
if (ret) {
|
|
dev_err(dev, "failed to enable clock for pwm: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Watch for changes to underlying clock frequency */
|
|
ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
|
|
ret = clk_notifier_register(ddata->clk, &ddata->notifier);
|
|
if (ret) {
|
|
dev_err(dev, "failed to register clock notifier: %d\n", ret);
|
|
goto disable_clk;
|
|
}
|
|
|
|
ret = pwmchip_add(chip);
|
|
if (ret < 0) {
|
|
dev_err(dev, "cannot register PWM: %d\n", ret);
|
|
goto unregister_clk;
|
|
}
|
|
|
|
platform_set_drvdata(pdev, ddata);
|
|
dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
|
|
|
|
return 0;
|
|
|
|
unregister_clk:
|
|
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
|
disable_clk:
|
|
clk_disable_unprepare(ddata->clk);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int pwm_sifive_remove(struct platform_device *dev)
|
|
{
|
|
struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
|
|
bool is_enabled = false;
|
|
struct pwm_device *pwm;
|
|
int ret, ch;
|
|
|
|
for (ch = 0; ch < ddata->chip.npwm; ch++) {
|
|
pwm = &ddata->chip.pwms[ch];
|
|
if (pwm->state.enabled) {
|
|
is_enabled = true;
|
|
break;
|
|
}
|
|
}
|
|
if (is_enabled)
|
|
clk_disable(ddata->clk);
|
|
|
|
clk_disable_unprepare(ddata->clk);
|
|
ret = pwmchip_remove(&ddata->chip);
|
|
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct of_device_id pwm_sifive_of_match[] = {
|
|
{ .compatible = "sifive,pwm0" },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, pwm_sifive_of_match);
|
|
|
|
static struct platform_driver pwm_sifive_driver = {
|
|
.probe = pwm_sifive_probe,
|
|
.remove = pwm_sifive_remove,
|
|
.driver = {
|
|
.name = "pwm-sifive",
|
|
.of_match_table = pwm_sifive_of_match,
|
|
},
|
|
};
|
|
module_platform_driver(pwm_sifive_driver);
|
|
|
|
MODULE_DESCRIPTION("SiFive PWM driver");
|
|
MODULE_LICENSE("GPL v2");
|