2b9f49ee80
* refs/heads/tmp-de197c5: Linux 5.4.8 mm/hugetlbfs: fix for_each_hstate() loop in init_hugetlbfs_fs() mmc: sdhci-of-esdhc: re-implement erratum A-009204 workaround mmc: sdhci-of-esdhc: fix up erratum A-008171 workaround vhost/vsock: accept only packets with the right dst_cid net: ena: fix napi handler misbehavior when the napi budget is zero net: phylink: fix interface passed to mac_link_up ipv6/addrconf: only check invalid header values when NETLINK_F_STRICT_CHK is set bnxt: apply computed clamp value for coalece parameter gtp: do not allow adding duplicate tid and ms_addr pdp context gtp: fix an use-after-free in ipv4_pdp_find() hv_netvsc: Fix tx_table init in rndis_set_subchannel() tcp/dccp: fix possible race __inet_lookup_established() tcp: do not send empty skb from tcp_write_xmit() bonding: fix active-backup transition after link failure gtp: avoid zero size hashtable gtp: fix wrong condition in gtp_genl_dump_pdp() net: marvell: mvpp2: phylink requires the link interrupt net: dsa: sja1105: Reconcile the meaning of TPID and TPID2 for E/T and P/Q/R/S net/dst: do not confirm neighbor for vxlan and geneve pmtu update sit: do not confirm neighbor when do pmtu update vti: do not confirm neighbor when do pmtu update tunnel: do not confirm neighbor when do pmtu update net/dst: add new function skb_dst_update_pmtu_no_confirm gtp: do not confirm neighbor when do pmtu update ip6_gre: do not confirm neighbor when do pmtu update net: add bool confirm_neigh parameter for dst_ops.update_pmtu mlxsw: spectrum: Use dedicated policer for VRRP packets mlxsw: spectrum_router: Skip loopback RIFs during MAC validation bnxt_en: Add missing devlink health reporters for VFs. bnxt_en: Fix the logic that creates the health reporters. bnxt_en: Remove unnecessary NULL checks for fw_health bnxt_en: Fix bp->fw_health allocation and free logic. bnxt_en: Return error if FW returns more data than dump length bnxt_en: Free context memory in the open path if firmware has been reset. bnxt_en: Fix MSIX request logic for RDMA driver. udp: fix integer overflow while computing available space in sk_rcvbuf tcp: Fix highest_sack and highest_sack_seq ptp: fix the race between the release of ptp_clock and cdev net: stmmac: dwmac-meson8b: Fix the RGMII TX delay on Meson8b/8m2 SoCs net_sched: sch_fq: properly set sk->sk_pacing_status net/sched: add delete_empty() to filters and use it in cls_flower net/sched: act_mirred: Pull mac prior redir to non mac_header_xmit device net: phy: aquantia: add suspend / resume ops for AQR105 net/mlxfw: Fix out-of-memory error in mfa2 flash burning net: dsa: bcm_sf2: Fix IP fragment location and behavior cxgb4/cxgb4vf: fix flow control display for auto negotiation xfs: fix mount failure crash on invalid iclog memory access drm: limit to INT_MAX in create_blob ioctl uaccess: disallow > INT_MAX copy sizes tomoyo: Don't use nifty names on sockets. hrtimer: Annotate lockless access to timer->state net: icmp: fix data-race in cmp_global_allow() net: add a READ_ONCE() in skb_peek_tail() inetpeer: fix data-race in inet_putpeer / inet_putpeer netfilter: bridge: make sure to pull arp header in br_nf_forward_arp() net/smc: add fallback check to connect() powerpc: Fix __clear_user() with KUAP enabled 6pack,mkiss: fix possible deadlock netfilter: ebtables: compat: reject all padding in matches/watchers Revert "iwlwifi: assign directly to iwl_trans->cfg in QuZ detection" md: make sure desc_nr less than MD_SB_DISKS sctp: fix err handling of stream initialization Revert "powerpc/vcpu: Assume dedicated processors as non-preempt" userfaultfd: require CAP_SYS_PTRACE for UFFD_FEATURE_EVENT_FORK kernel: sysctl: make drop_caches write-only mm/hugetlbfs: fix error handling when setting up mounts selftests: vm: add fragment CONFIG_TEST_VMALLOC s390: disable preemption when switching to nodat stack with CALL_ON_STACK mailbox: imx: Fix Tx doorbell shutdown path ocfs2: fix passing zero to 'PTR_ERR' warning s390/cpum_sf: Check for SDBT and SDB consistency s390/unwind: filter out unreliable bogus %r14 libfdt: define INT32_MAX and UINT32_MAX in libfdt_env.h mailbox: imx: Clear the right interrupts at shutdown s390/zcrypt: handle new reply code FILTERED_BY_HYPERVISOR perf regs: Make perf_reg_name() return "unknown" instead of NULL perf script: Fix brstackinsn for AUXTRACE perf diff: Use llabs() with 64-bit values cifs: move cifsFileInfo_put logic into a work-queue cdrom: respect device capabilities during opening action of: unittest: fix memory leak in attach_node_and_children io_uring: io_allocate_scq_urings() should return a sane state um: virtio: Keep reading on -EAGAIN cifs: Fix use-after-free bug in cifs_reconnect() powerpc: Don't add -mabi= flags when building with Clang scripts/kallsyms: fix definitely-lost memory leak drm/amdgpu: Call find_vma under mmap_sem apparmor: fix unsigned len comparison with less than zero Drivers: hv: vmbus: Fix crash handler reset of Hyper-V synic tools/power/x86/intel-speed-select: Ignore missing config level gpio: lynxpoint: Setup correct IRQ handlers gpio: mpc8xxx: Don't overwrite default irq_set_type callback platform/x86: intel_pmc_core: Add Comet Lake (CML) platform support to intel_pmc_core driver platform/x86: intel_pmc_core: Fix the SoC naming inconsistency gpio/mpc8xxx: fix qoriq GPIO reading habanalabs: skip VA block list update in reset flow f2fs: Fix deadlock in f2fs_gc() context during atomic files handling scsi: target: iscsi: Wait for all commands to finish before freeing a session scsi: iscsi: Don't send data to unbound connection scsi: ufs: Fix up auto hibern8 enablement scsi: target: core: Release SPC-2 reservations when closing a session scsi: NCR5380: Add disconnect_mask module parameter scsi: scsi_debug: num_tgts must be >= 0 scsi: ufs: Fix error handing during hibern8 enter scsi: pm80xx: Fix for SATA device discovery powerpc/fixmap: Use __fix_to_virt() instead of fix_to_virt() watchdog: Fix the race between the release of watchdog_core_data and cdev watchdog: prevent deferral of watchdogd wakeup on RT watchdog: imx7ulp: Fix reboot hang HID: rmi: Check that the RMI_STARTED bit is set before unregistering the RMI transport device HID: Improve Windows Precision Touchpad detection. libnvdimm/btt: fix variable 'rc' set but not used ARM: 8937/1: spectre-v2: remove Brahma-B53 from hardening HID: i2c-hid: fix no irq after reset on raydium 3118 HID: logitech-hidpp: Silence intermittent get_battery_capacity errors dt-bindings: Improve validation build error handling HID: quirks: Add quirk for HP MSU1465 PIXART OEM mouse bcache: at least try to shrink 1 node in bch_mca_scan() clk: pxa: fix one of the pxa RTC clocks scsi: atari_scsi: sun3_scsi: Set sg_tablesize to 1 instead of SG_NONE powerpc/book3s/mm: Update Oops message to print the correct translation in use powerpc/eeh: differentiate duplicate detection message powerpc/security: Fix wrong message when RFI Flush is disable PCI: rpaphp: Correctly match ibm, my-drc-index to drc-name when using drc-info PCI: rpaphp: Annotate and correctly byte swap DRC properties PCI: rpaphp: Don't rely on firmware feature to imply drc-info support powerpc/pseries/cmm: Implement release() function for sysfs device scsi: ufs: fix potential bug which ends in system hang PCI: rpaphp: Fix up pointer to first drc-info entry scsi: zorro_esp: Limit DMA transfers to 65536 bytes (except on Fastlane) scsi: lpfc: fix: Coverity: lpfc_cmpl_els_rsp(): Null pointer dereferences Input: ili210x - handle errors from input_mt_init_slots() iomap: fix return value of iomap_dio_bio_actor on 32bit systems i2c: stm32f7: fix & reorder remove & probe error handling iommu/arm-smmu-v3: Don't display an error when IRQ lines are missing fs/quota: handle overflows of sysctl fs.quota.* and report as unsigned long dma-direct: check for overflows on 32 bit DMA addresses irqchip: ingenic: Error out if IRQ domain creation failed irqchip/irq-bcm7038-l1: Enable parent IRQ if necessary clk: clk-gpio: propagate rate change to parent clk: qcom: Allow constant ratio freq tables for rcg clk: qcom: smd: Add missing pnoc clock f2fs: fix to update dir's i_pino during cross_rename scsi: lpfc: Fix duplicate unreg_rpi error in port offline flow scsi: lpfc: Fix unexpected error messages during RSCN handling scsi: tracing: Fix handling of TRANSFER LENGTH == 0 for READ(6) and WRITE(6) jbd2: Fix statistics for the number of logged blocks ext4: iomap that extends beyond EOF should be marked dirty ext4: update direct I/O read lock pattern for IOCB_NOWAIT powerpc/book3s64/hash: Add cond_resched to avoid soft lockup warning powerpc/security/book3s64: Report L1TF status in sysfs selftests/powerpc: Skip tm-signal-sigreturn-nt if TM not available dtc: Use pkg-config to locate libyaml clocksource/drivers/timer-of: Use unique device name instead of timer clocksource/drivers/asm9260: Add a check for of_clk_get leds: trigger: netdev: fix handling on interface rename leds: an30259a: add a check for devm_regmap_init_i2c leds: lm3692x: Handle failure to probe the regulator dmaengine: fsl-qdma: Handle invalid qdma-queue0 IRQ dma-mapping: fix handling of dma-ranges for reserved memory (again) dma-mapping: Add vmap checks to dma_map_single() dma-debug: add a schedule point in debug_dma_dump_mappings() powerpc/tools: Don't quote $objdump in scripts selftests/powerpc: Fixup clobbers for TM tests Input: st1232 - do not reset the chip too early powerpc/pseries: Don't fail hash page table insert for bolted mapping powerpc/pseries: Mark accumulate_stolen_time() as notrace scsi: hisi_sas: Delete the debugfs folder of hisi_sas when the probe fails scsi: hisi_sas: Replace in_softirq() check in hisi_sas_task_exec() scsi: csiostor: Don't enable IRQs too early scsi: lpfc: Fix SLI3 hba in loop mode not discovering devices scsi: lpfc: Fix hardlockup in lpfc_abort_handler scsi: target: compare full CHAP_A Algorithm strings dmaengine: xilinx_dma: Clear desc_pendingcount in xilinx_dma_reset iommu/tegra-smmu: Fix page tables in > 4 GiB memory iommu: rockchip: Free domain on .domain_free platform/x86: peaq-wmi: switch to using polled mode of input devices tools/power/x86/intel-speed-select: Remove warning for unused result powerpc/papr_scm: Fix an off-by-one check in papr_scm_meta_{get, set} f2fs: fix to update time in lazytime mode Input: atmel_mxt_ts - disable IRQ across suspend scsi: lpfc: Fix list corruption in lpfc_sli_get_iocbq gpio: mxc: Only get the second IRQ when there is more than one IRQ scsi: mpt3sas: Reject NVMe Encap cmnds to unsupported HBA scsi: lpfc: Fix locking on mailbox command completion scsi: mpt3sas: Fix clear pending bit in ioctl status scsi: lpfc: Fix discovery failures when target device connectivity bounces scsi: lpfc: Fix spinlock_irq issues in lpfc_els_flush_cmd() Revert "MIPS: futex: Emit Loongson3 sync workarounds within asm" Revert "MIPS: futex: Restore \n after sync instructions" UPSTREAM: exit: panic before exit_mm() on global init exit ANDROID: serdev: Fix platform device support Conflicts: Documentation/devicetree/bindings Documentation/devicetree/bindings/Makefile kernel/time/hrtimer.c Change-Id: I271162549a080e2b747572f5c87cfd8fa111da51 Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>
304 lines
7.6 KiB
C
304 lines
7.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
|
|
*
|
|
* Authors:
|
|
* Jyri Sarha <jsarha@ti.com>
|
|
* Sergej Sawazki <ce3a@gmx.de>
|
|
*
|
|
* Gpio controlled clock implementation
|
|
*/
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/export.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/err.h>
|
|
#include <linux/device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_device.h>
|
|
|
|
/**
|
|
* DOC: basic gpio gated clock which can be enabled and disabled
|
|
* with gpio output
|
|
* Traits of this clock:
|
|
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
|
* enable - clk_enable and clk_disable are functional & control gpio
|
|
* rate - inherits rate from parent. No clk_set_rate support
|
|
* parent - fixed parent. No clk_set_parent support
|
|
*/
|
|
|
|
static int clk_gpio_gate_enable(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
gpiod_set_value(clk->gpiod, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clk_gpio_gate_disable(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
gpiod_set_value(clk->gpiod, 0);
|
|
}
|
|
|
|
static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
return gpiod_get_value(clk->gpiod);
|
|
}
|
|
|
|
const struct clk_ops clk_gpio_gate_ops = {
|
|
.enable = clk_gpio_gate_enable,
|
|
.disable = clk_gpio_gate_disable,
|
|
.is_enabled = clk_gpio_gate_is_enabled,
|
|
};
|
|
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
|
|
|
|
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
gpiod_set_value_cansleep(clk->gpiod, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
gpiod_set_value_cansleep(clk->gpiod, 0);
|
|
}
|
|
|
|
static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
return gpiod_get_value_cansleep(clk->gpiod);
|
|
}
|
|
|
|
static const struct clk_ops clk_sleeping_gpio_gate_ops = {
|
|
.prepare = clk_sleeping_gpio_gate_prepare,
|
|
.unprepare = clk_sleeping_gpio_gate_unprepare,
|
|
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
|
|
};
|
|
|
|
/**
|
|
* DOC: basic clock multiplexer which can be controlled with a gpio output
|
|
* Traits of this clock:
|
|
* prepare - clk_prepare only ensures that parents are prepared
|
|
* rate - rate is only affected by parent switching. No clk_set_rate support
|
|
* parent - parent is adjustable through clk_set_parent
|
|
*/
|
|
|
|
static u8 clk_gpio_mux_get_parent(struct clk_hw *hw)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
return gpiod_get_value_cansleep(clk->gpiod);
|
|
}
|
|
|
|
static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
|
|
{
|
|
struct clk_gpio *clk = to_clk_gpio(hw);
|
|
|
|
gpiod_set_value_cansleep(clk->gpiod, index);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct clk_ops clk_gpio_mux_ops = {
|
|
.get_parent = clk_gpio_mux_get_parent,
|
|
.set_parent = clk_gpio_mux_set_parent,
|
|
.determine_rate = __clk_mux_determine_rate,
|
|
};
|
|
EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
|
|
|
|
static struct clk_hw *clk_register_gpio(struct device *dev, const char *name,
|
|
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
|
|
unsigned long flags, const struct clk_ops *clk_gpio_ops)
|
|
{
|
|
struct clk_gpio *clk_gpio;
|
|
struct clk_hw *hw;
|
|
struct clk_init_data init = {};
|
|
int err;
|
|
|
|
if (dev)
|
|
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
|
|
else
|
|
clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
|
|
|
|
if (!clk_gpio)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
init.name = name;
|
|
init.ops = clk_gpio_ops;
|
|
init.flags = flags;
|
|
init.parent_names = parent_names;
|
|
init.num_parents = num_parents;
|
|
|
|
clk_gpio->gpiod = gpiod;
|
|
clk_gpio->hw.init = &init;
|
|
|
|
hw = &clk_gpio->hw;
|
|
if (dev)
|
|
err = devm_clk_hw_register(dev, hw);
|
|
else
|
|
err = clk_hw_register(NULL, hw);
|
|
hw->init = NULL;
|
|
if (!err)
|
|
return hw;
|
|
|
|
if (!dev) {
|
|
kfree(clk_gpio);
|
|
}
|
|
|
|
return ERR_PTR(err);
|
|
}
|
|
|
|
/**
|
|
* clk_hw_register_gpio_gate - register a gpio clock gate with the clock
|
|
* framework
|
|
* @dev: device that is registering this clock
|
|
* @name: name of this clock
|
|
* @parent_name: name of this clock's parent
|
|
* @gpiod: gpio descriptor to gate this clock
|
|
* @flags: clock flags
|
|
*/
|
|
struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
|
|
const char *parent_name, struct gpio_desc *gpiod,
|
|
unsigned long flags)
|
|
{
|
|
const struct clk_ops *ops;
|
|
|
|
if (gpiod_cansleep(gpiod))
|
|
ops = &clk_sleeping_gpio_gate_ops;
|
|
else
|
|
ops = &clk_gpio_gate_ops;
|
|
|
|
return clk_register_gpio(dev, name,
|
|
(parent_name ? &parent_name : NULL),
|
|
(parent_name ? 1 : 0), gpiod, flags, ops);
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
|
|
|
|
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
|
|
const char *parent_name, struct gpio_desc *gpiod,
|
|
unsigned long flags)
|
|
{
|
|
struct clk_hw *hw;
|
|
|
|
hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpiod, flags);
|
|
if (IS_ERR(hw))
|
|
return ERR_CAST(hw);
|
|
return hw->clk;
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
|
|
|
|
/**
|
|
* clk_hw_register_gpio_mux - register a gpio clock mux with the clock framework
|
|
* @dev: device that is registering this clock
|
|
* @name: name of this clock
|
|
* @parent_names: names of this clock's parents
|
|
* @num_parents: number of parents listed in @parent_names
|
|
* @gpiod: gpio descriptor to gate this clock
|
|
* @flags: clock flags
|
|
*/
|
|
struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name,
|
|
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
|
|
unsigned long flags)
|
|
{
|
|
if (num_parents != 2) {
|
|
pr_err("mux-clock %s must have 2 parents\n", name);
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
return clk_register_gpio(dev, name, parent_names, num_parents,
|
|
gpiod, flags, &clk_gpio_mux_ops);
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux);
|
|
|
|
struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
|
|
const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod,
|
|
unsigned long flags)
|
|
{
|
|
struct clk_hw *hw;
|
|
|
|
hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents,
|
|
gpiod, flags);
|
|
if (IS_ERR(hw))
|
|
return ERR_CAST(hw);
|
|
return hw->clk;
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
|
|
|
|
static int gpio_clk_driver_probe(struct platform_device *pdev)
|
|
{
|
|
struct device_node *node = pdev->dev.of_node;
|
|
const char **parent_names, *gpio_name;
|
|
unsigned int num_parents;
|
|
struct gpio_desc *gpiod;
|
|
struct clk *clk;
|
|
bool is_mux;
|
|
int ret;
|
|
|
|
num_parents = of_clk_get_parent_count(node);
|
|
if (num_parents) {
|
|
parent_names = devm_kcalloc(&pdev->dev, num_parents,
|
|
sizeof(char *), GFP_KERNEL);
|
|
if (!parent_names)
|
|
return -ENOMEM;
|
|
|
|
of_clk_parent_fill(node, parent_names, num_parents);
|
|
} else {
|
|
parent_names = NULL;
|
|
}
|
|
|
|
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
|
|
|
|
gpio_name = is_mux ? "select" : "enable";
|
|
gpiod = devm_gpiod_get(&pdev->dev, gpio_name, GPIOD_OUT_LOW);
|
|
if (IS_ERR(gpiod)) {
|
|
ret = PTR_ERR(gpiod);
|
|
if (ret == -EPROBE_DEFER)
|
|
pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
|
|
node, __func__);
|
|
else
|
|
pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
|
|
node, __func__,
|
|
gpio_name);
|
|
return ret;
|
|
}
|
|
|
|
if (is_mux)
|
|
clk = clk_register_gpio_mux(&pdev->dev, node->name,
|
|
parent_names, num_parents, gpiod, 0);
|
|
else
|
|
clk = clk_register_gpio_gate(&pdev->dev, node->name,
|
|
parent_names ? parent_names[0] : NULL, gpiod,
|
|
CLK_SET_RATE_PARENT);
|
|
if (IS_ERR(clk))
|
|
return PTR_ERR(clk);
|
|
|
|
return of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
|
}
|
|
|
|
static const struct of_device_id gpio_clk_match_table[] = {
|
|
{ .compatible = "gpio-mux-clock" },
|
|
{ .compatible = "gpio-gate-clock" },
|
|
{ }
|
|
};
|
|
|
|
static struct platform_driver gpio_clk_driver = {
|
|
.probe = gpio_clk_driver_probe,
|
|
.driver = {
|
|
.name = "gpio-clk",
|
|
.of_match_table = gpio_clk_match_table,
|
|
},
|
|
};
|
|
builtin_platform_driver(gpio_clk_driver);
|