Commit 5816b745 authored by Stephen Boyd's avatar Stephen Boyd
Browse files

Merge branches 'clk-hisi', 'clk-lochnagar', 'clk-allwinner', 'clk-rockchip'...

Merge branches 'clk-hisi', 'clk-lochnagar', 'clk-allwinner', 'clk-rockchip' and 'clk-qoriq' into clk-next

 - Mark UFS clk as critical on Hi-Silicon hi3660 SoCs
 - Support for Cirrus Logic Lochnagar clks

* clk-hisi:
  clk: hi3660: Mark clk_gate_ufs_subsys as critical

* clk-lochnagar:
  clk: lochnagar: Add support for the Cirrus Logic Lochnagar
  clk: lochnagar: Add initial binding documentation

* clk-allwinner:
  clk: sunxi-ng: sun5i: Export the MBUS clock
  clk: sunxi-ng: a83t: Add pll-video0 as parent of csi-mclk
  clk: sunxi-ng: h6: Allow video & vpu clocks to change parent rate
  clk: sunxi-ng: h6: Preset hdmi-cec clock parent
  clk: sunxi: Add Kconfig options
  clk: sunxi-ng: f1c100s: fix USB PHY gate bit offset
  clk: sunxi-ng: Allow DE clock to set parent rate

* clk-rockchip:
  clk: rockchip: undo several noc and special clocks as critical on rk3288
  clk: rockchip: add a COMPOSITE_DIV_OFFSET clock-type
  clk: rockchip: Turn on "aclk_dmac1" for suspend on rk3288
  clk: rockchip: Limit use of USB PHY clock to USB on rk3288
  clk: rockchip: Fix video codec clocks on rk3288
  clk: rockchip: Make rkpwm a critical clock on rk3288
  clk: rockchip: fix wrong clock definitions for rk3328

* clk-qoriq:
  clk: qoriq: increase array size of cmux_to_group
  dt-bindings: qoriq-clock: Add ls1028a chip compatible string
  clk: qoriq: Add ls1028a clock configuration
  clk: qoriq: add more PLL divider clocks support
  dt-bindings: qoriq-clock: add more PLL divider clocks support
Loading
Loading
Loading
Loading
+93 −0
Original line number Diff line number Diff line
Cirrus Logic Lochnagar Audio Development Board

Lochnagar is an evaluation and development board for Cirrus Logic
Smart CODEC and Amp devices. It allows the connection of most Cirrus
Logic devices on mini-cards, as well as allowing connection of
various application processor systems to provide a full evaluation
platform.  Audio system topology, clocking and power can all be
controlled through the Lochnagar, allowing the device under test
to be used in a variety of possible use cases.

This binding document describes the binding for the clock portion of
the driver.

Also see these documents for generic binding information:
  [1] Clock : ../clock/clock-bindings.txt

And these for relevant defines:
  [2] include/dt-bindings/clock/lochnagar.h

This binding must be part of the Lochnagar MFD binding:
  [3] ../mfd/cirrus,lochnagar.txt

Required properties:

  - compatible : One of the following strings:
                 "cirrus,lochnagar1-clk"
                 "cirrus,lochnagar2-clk"

  - #clock-cells : Must be 1. The first cell indicates the clock
    number, see [2] for available clocks and [1].

Optional properties:

  - clocks : Must contain an entry for each clock in clock-names.
  - clock-names : May contain entries for each of the following
    clocks:
     - ln-cdc-clkout : Output clock from CODEC card.
     - ln-dsp-clkout : Output clock from DSP card.
     - ln-gf-mclk1,ln-gf-mclk2,ln-gf-mclk3,ln-gf-mclk4 : Optional
       input audio clocks from host system.
     - ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
       external connector.
     - ln-spdif-clkout : Optional input audio clock from SPDIF.
     - ln-adat-mclk : Optional input audio clock from ADAT.
     - ln-pmic-32k : On board fixed clock.
     - ln-clk-12m : On board fixed clock.
     - ln-clk-11m : On board fixed clock.
     - ln-clk-24m : On board fixed clock.
     - ln-clk-22m : On board fixed clock.
     - ln-clk-8m : On board fixed clock.
     - ln-usb-clk-24m : On board fixed clock.
     - ln-usb-clk-12m : On board fixed clock.

  - assigned-clocks : A list of Lochnagar clocks to be reparented, see
    [2] for available clocks.
  - assigned-clock-parents : Parents to be assigned to the clocks
    listed in "assigned-clocks".

Optional nodes:

  - fixed-clock nodes may be registered for the following on board clocks:
     - ln-pmic-32k : 32768 Hz
     - ln-clk-12m : 12288000 Hz
     - ln-clk-11m : 11298600 Hz
     - ln-clk-24m : 24576000 Hz
     - ln-clk-22m : 22579200 Hz
     - ln-clk-8m : 8192000 Hz
     - ln-usb-clk-24m : 24576000 Hz
     - ln-usb-clk-12m : 12288000 Hz

Example:

lochnagar {
	lochnagar-clk {
		compatible = "cirrus,lochnagar2-clk";

		#clock-cells = <1>;

		clocks = <&clk-audio>, <&clk_pmic>;
		clock-names = "ln-gf-mclk2", "ln-pmic-32k";

		assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>,
				  <&lochnagar-clk LOCHNAGAR_CDC_MCLK2>;
		assigned-clock-parents = <&clk-audio>,
					 <&clk-pmic>;
	};

	clk-pmic: clk-pmic {
		compatible = "fixed-clock";
		clock-cells = <0>;
		clock-frequency = <32768>;
	};
};
+3 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ Required properties:
	* "fsl,b4860-clockgen"
	* "fsl,ls1012a-clockgen"
	* "fsl,ls1021a-clockgen"
	* "fsl,ls1028a-clockgen"
	* "fsl,ls1043a-clockgen"
	* "fsl,ls1046a-clockgen"
	* "fsl,ls1088a-clockgen"
@@ -83,8 +84,8 @@ second cell is the clock index for the specified type.
	1	cmux		index (n in CLKCnCSR)
	2	hwaccel		index (n in CLKCGnHWACSR)
	3	fman		0 for fm1, 1 for fm2
	4	platform pll	0=pll, 1=pll/2, 2=pll/3, 3=pll/4
				4=pll/5, 5=pll/6, 6=pll/7, 7=pll/8
	4	platform pll	n=pll/(n+1). For example, when n=1,
				that means output_freq=PLL_freq/2.
	5	coreclk		must be 0

3. Example
+8 −0
Original line number Diff line number Diff line
@@ -219,6 +219,13 @@ config COMMON_CLK_XGENE
	---help---
	  Sypport for the APM X-Gene SoC reference, PLL, and device clocks.

config COMMON_CLK_LOCHNAGAR
	tristate "Cirrus Logic Lochnagar clock driver"
	depends on MFD_LOCHNAGAR
	help
	  This driver supports the clocking features of the Cirrus Logic
	  Lochnagar audio development board.

config COMMON_CLK_NXP
	def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
	select REGMAP_MMIO if ARCH_LPC32XX
@@ -310,6 +317,7 @@ source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sprd/Kconfig"
source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED)		+= clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR)	+= clk-lochnagar.o
obj-$(CONFIG_COMMON_CLK_MAX77686)	+= clk-max77686.o
obj-$(CONFIG_COMMON_CLK_MAX9485)	+= clk-max9485.o
obj-$(CONFIG_ARCH_MILBEAUT_M10V)	+= clk-milbeaut.o
+336 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Lochnagar clock control
 *
 * Copyright (c) 2017-2018 Cirrus Logic, Inc. and
 *                         Cirrus Logic International Semiconductor Ltd.
 *
 * Author: Charles Keepax <ckeepax@opensource.cirrus.com>
 */

#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>

#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>

#include <dt-bindings/clk/lochnagar.h>

#define LOCHNAGAR_NUM_CLOCKS	(LOCHNAGAR_SPDIF_CLKOUT + 1)

struct lochnagar_clk {
	const char * const name;
	struct clk_hw hw;

	struct lochnagar_clk_priv *priv;

	u16 cfg_reg;
	u16 ena_mask;

	u16 src_reg;
	u16 src_mask;
};

struct lochnagar_clk_priv {
	struct device *dev;
	struct regmap *regmap;
	enum lochnagar_type type;

	const char **parents;
	unsigned int nparents;

	struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
};

static const char * const lochnagar1_clk_parents[] = {
	"ln-none",
	"ln-spdif-mclk",
	"ln-psia1-mclk",
	"ln-psia2-mclk",
	"ln-cdc-clkout",
	"ln-dsp-clkout",
	"ln-pmic-32k",
	"ln-gf-mclk1",
	"ln-gf-mclk3",
	"ln-gf-mclk2",
	"ln-gf-mclk4",
};

static const char * const lochnagar2_clk_parents[] = {
	"ln-none",
	"ln-cdc-clkout",
	"ln-dsp-clkout",
	"ln-pmic-32k",
	"ln-spdif-mclk",
	"ln-clk-12m",
	"ln-clk-11m",
	"ln-clk-24m",
	"ln-clk-22m",
	"ln-clk-8m",
	"ln-usb-clk-24m",
	"ln-gf-mclk1",
	"ln-gf-mclk3",
	"ln-gf-mclk2",
	"ln-psia1-mclk",
	"ln-psia2-mclk",
	"ln-spdif-clkout",
	"ln-adat-mclk",
	"ln-usb-clk-12m",
};

#define LN1_CLK(ID, NAME, REG) \
	[LOCHNAGAR_##ID] = { \
		.name = NAME, \
		.cfg_reg = LOCHNAGAR1_##REG, \
		.ena_mask = LOCHNAGAR1_##ID##_ENA_MASK, \
		.src_reg = LOCHNAGAR1_##ID##_SEL, \
		.src_mask = LOCHNAGAR1_SRC_MASK, \
	}

#define LN2_CLK(ID, NAME) \
	[LOCHNAGAR_##ID] = { \
		.name = NAME, \
		.cfg_reg = LOCHNAGAR2_##ID##_CTRL, \
		.src_reg = LOCHNAGAR2_##ID##_CTRL, \
		.ena_mask = LOCHNAGAR2_CLK_ENA_MASK, \
		.src_mask = LOCHNAGAR2_CLK_SRC_MASK, \
	}

static const struct lochnagar_clk lochnagar1_clks[LOCHNAGAR_NUM_CLOCKS] = {
	LN1_CLK(CDC_MCLK1,      "ln-cdc-mclk1",  CDC_AIF_CTRL2),
	LN1_CLK(CDC_MCLK2,      "ln-cdc-mclk2",  CDC_AIF_CTRL2),
	LN1_CLK(DSP_CLKIN,      "ln-dsp-clkin",  DSP_AIF),
	LN1_CLK(GF_CLKOUT1,     "ln-gf-clkout1", GF_AIF1),
};

static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
	LN2_CLK(CDC_MCLK1,      "ln-cdc-mclk1"),
	LN2_CLK(CDC_MCLK2,      "ln-cdc-mclk2"),
	LN2_CLK(DSP_CLKIN,      "ln-dsp-clkin"),
	LN2_CLK(GF_CLKOUT1,     "ln-gf-clkout1"),
	LN2_CLK(GF_CLKOUT2,     "ln-gf-clkout2"),
	LN2_CLK(PSIA1_MCLK,     "ln-psia1-mclk"),
	LN2_CLK(PSIA2_MCLK,     "ln-psia2-mclk"),
	LN2_CLK(SPDIF_MCLK,     "ln-spdif-mclk"),
	LN2_CLK(ADAT_MCLK,      "ln-adat-mclk"),
	LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
};

static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
{
	return container_of(hw, struct lochnagar_clk, hw);
}

static int lochnagar_clk_prepare(struct clk_hw *hw)
{
	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
	struct lochnagar_clk_priv *priv = lclk->priv;
	struct regmap *regmap = priv->regmap;
	int ret;

	ret = regmap_update_bits(regmap, lclk->cfg_reg,
				 lclk->ena_mask, lclk->ena_mask);
	if (ret < 0)
		dev_dbg(priv->dev, "Failed to prepare %s: %d\n",
			lclk->name, ret);

	return ret;
}

static void lochnagar_clk_unprepare(struct clk_hw *hw)
{
	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
	struct lochnagar_clk_priv *priv = lclk->priv;
	struct regmap *regmap = priv->regmap;
	int ret;

	ret = regmap_update_bits(regmap, lclk->cfg_reg, lclk->ena_mask, 0);
	if (ret < 0)
		dev_dbg(priv->dev, "Failed to unprepare %s: %d\n",
			lclk->name, ret);
}

static int lochnagar_clk_set_parent(struct clk_hw *hw, u8 index)
{
	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
	struct lochnagar_clk_priv *priv = lclk->priv;
	struct regmap *regmap = priv->regmap;
	int ret;

	ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index);
	if (ret < 0)
		dev_dbg(priv->dev, "Failed to reparent %s: %d\n",
			lclk->name, ret);

	return ret;
}

static u8 lochnagar_clk_get_parent(struct clk_hw *hw)
{
	struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
	struct lochnagar_clk_priv *priv = lclk->priv;
	struct regmap *regmap = priv->regmap;
	unsigned int val;
	int ret;

	ret = regmap_read(regmap, lclk->src_reg, &val);
	if (ret < 0) {
		dev_dbg(priv->dev, "Failed to read parent of %s: %d\n",
			lclk->name, ret);
		return priv->nparents;
	}

	val &= lclk->src_mask;

	return val;
}

static const struct clk_ops lochnagar_clk_ops = {
	.prepare = lochnagar_clk_prepare,
	.unprepare = lochnagar_clk_unprepare,
	.set_parent = lochnagar_clk_set_parent,
	.get_parent = lochnagar_clk_get_parent,
};

static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
{
	struct device_node *np = priv->dev->of_node;
	int i, j;

	switch (priv->type) {
	case LOCHNAGAR1:
		memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));

		priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
		priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
					     sizeof(lochnagar1_clk_parents),
					     GFP_KERNEL);
		break;
	case LOCHNAGAR2:
		memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));

		priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
		priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
					     sizeof(lochnagar2_clk_parents),
					     GFP_KERNEL);
		break;
	default:
		dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
		return -EINVAL;
	}

	if (!priv->parents)
		return -ENOMEM;

	for (i = 0; i < priv->nparents; i++) {
		j = of_property_match_string(np, "clock-names",
					     priv->parents[i]);
		if (j >= 0)
			priv->parents[i] = of_clk_get_parent_name(np, j);
	}

	return 0;
}

static struct clk_hw *
lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
{
	struct lochnagar_clk_priv *priv = data;
	unsigned int idx = clkspec->args[0];

	if (idx >= ARRAY_SIZE(priv->lclks)) {
		dev_err(priv->dev, "Invalid index %u\n", idx);
		return ERR_PTR(-EINVAL);
	}

	return &priv->lclks[idx].hw;
}

static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
{
	struct clk_init_data clk_init = {
		.ops = &lochnagar_clk_ops,
		.parent_names = priv->parents,
		.num_parents = priv->nparents,
	};
	struct lochnagar_clk *lclk;
	int ret, i;

	for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
		lclk = &priv->lclks[i];

		if (!lclk->name)
			continue;

		clk_init.name = lclk->name;

		lclk->priv = priv;
		lclk->hw.init = &clk_init;

		ret = devm_clk_hw_register(priv->dev, &lclk->hw);
		if (ret) {
			dev_err(priv->dev, "Failed to register %s: %d\n",
				lclk->name, ret);
			return ret;
		}
	}

	ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get,
					  priv);
	if (ret < 0)
		dev_err(priv->dev, "Failed to register provider: %d\n", ret);

	return ret;
}

static const struct of_device_id lochnagar_of_match[] = {
	{ .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
	{ .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
	{}
};
MODULE_DEVICE_TABLE(of, lochnagar_of_match);

static int lochnagar_clk_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct lochnagar_clk_priv *priv;
	const struct of_device_id *of_id;
	int ret;

	of_id = of_match_device(lochnagar_of_match, dev);
	if (!of_id)
		return -EINVAL;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->dev = dev;
	priv->regmap = dev_get_regmap(dev->parent, NULL);
	priv->type = (enum lochnagar_type)of_id->data;

	ret = lochnagar_init_parents(priv);
	if (ret)
		return ret;

	return lochnagar_init_clks(priv);
}

static struct platform_driver lochnagar_clk_driver = {
	.driver = {
		.name = "lochnagar-clk",
		.of_match_table = lochnagar_of_match,
	},
	.probe = lochnagar_clk_probe,
};
module_platform_driver(lochnagar_clk_driver);

MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
MODULE_LICENSE("GPL v2");
Loading