diff options
44 files changed, 2234 insertions, 117 deletions
diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index 51c259a92d02..d0adbf5ae144 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -91,6 +91,9 @@ Required properties: at91 audio pll output on AUDIOPLLCLK that feeds the PMC and can be used by peripheral clock or generic clock + "atmel,sama5d2-clk-i2s-mux" (under pmc node): + at91 I2S clock source selection + Required properties for SCKC node: - reg : defines the IO memory reserved for the SCKC. - #size-cells : shall be 0 (reg is used to encode clk id). @@ -507,3 +510,35 @@ For example: atmel,clk-output-range = <0 83000000>; }; }; + +Required properties for I2S mux clocks: +- #size-cells : shall be 0 (reg is used to encode I2S bus id). +- #address-cells : shall be 1 (reg is used to encode I2S bus id). +- name: device tree node describing a specific mux clock. + * #clock-cells : from common clock binding; shall be set to 0. + * clocks : shall be the mux clock parent phandles; shall be 2 phandles: + peripheral and generated clock; the first phandle shall belong to the + peripheral clock and the second one shall belong to the generated + clock; "clock-indices" property can be user to specify + the correct order. + * reg: I2S bus id of the corresponding mux clock. + e.g. reg = <0>; for i2s0, reg = <1>; for i2s1 + +For example: + i2s_clkmux { + compatible = "atmel,sama5d2-clk-i2s-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2s0muxck: i2s0_muxclk { + clocks = <&i2s0_clk>, <&i2s0_gclk>; + #clock-cells = <0>; + reg = <0>; + }; + + i2s1muxck: i2s1_muxclk { + clocks = <&i2s1_clk>, <&i2s1_gclk>; + #clock-cells = <0>; + reg = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/maxim,max9485.txt b/Documentation/devicetree/bindings/clock/maxim,max9485.txt new file mode 100644 index 000000000000..61bec1100a94 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/maxim,max9485.txt @@ -0,0 +1,59 @@ +Devicetree bindings for Maxim MAX9485 Programmable Audio Clock Generator + +This device exposes 4 clocks in total: + +- MAX9485_MCLKOUT: A gated, buffered output of the input clock of 27 MHz +- MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete + frequencies +- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT + +MAX9485_CLKOUT[1,2] are children of MAX9485_CLKOUT which upchain all rate set +requests. + +Required properties: +- compatible: "maxim,max9485" +- clocks: Input clock, must provice 27.000 MHz +- clock-names: Must be set to "xclk" +- #clock-cells: From common clock binding; shall be set to 1 + +Optional properties: +- reset-gpios: GPIO descriptor connected to the #RESET input pin +- vdd-supply: A regulator node for Vdd +- clock-output-names: Name of output clocks, as defined in common clock + bindings + +If not explicitly set, the output names are "mclkout", "clkout", "clkout1" +and "clkout2". + +Clocks are defined as preprocessor macros in the dt-binding header. + +Example: + + #include <dt-bindings/clock/maxim,max9485.h> + + xo-27mhz: xo-27mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + + &i2c0 { + max9485: audio-clock@63 { + reg = <0x63>; + compatible = "maxim,max9485"; + clock-names = "xclk"; + clocks = <&xo-27mhz>; + reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + vdd-supply = <&3v3-reg>; + #clock-cells = <1>; + }; + }; + + // Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "foo-input-clk"; + clocks = <&max9485 MAX9485_CLKOUT1>; + }; diff --git a/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt new file mode 100644 index 000000000000..d60b99756bb9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r9a06g032-sysctrl.txt @@ -0,0 +1,43 @@ +* Renesas R9A06G032 SYSCTRL + +Required Properties: + + - compatible: Must be: + - "renesas,r9a06g032-sysctrl" + - reg: Base address and length of the SYSCTRL IO block. + - #clock-cells: Must be 1 + - clocks: References to the parent clocks: + - external 40mhz crystal. + - external (optional) 32.768khz + - external (optional) jtag input + - external (optional) RGMII_REFCLK + - clock-names: Must be: + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + +Examples +-------- + + - SYSCTRL node: + + sysctrl: system-controller@4000c000 { + compatible = "renesas,r9a06g032-sysctrl"; + reg = <0x4000c000 0x1000>; + #clock-cells = <1>; + + clocks = <&ext_mclk>, <&ext_rtc_clk>, + <&ext_jtag_clk>, <&ext_rgmii_ref>; + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + }; + + - Other nodes can use the clocks provided by SYSCTRL as in: + + #include <dt-bindings/clock/r9a06g032-sysctrl.h> + uart0: serial@40060000 { + compatible = "snps,dw-apb-uart"; + reg = <0x40060000 0x400>; + interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&sysctrl R9A06G032_CLK_UART0>; + clock-names = "baudclk"; + }; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 1254bf9d91b4..903f23c309df 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -27,6 +27,7 @@ config SOC_SAMA5D2 select HAVE_AT91_H32MX select HAVE_AT91_GENERATED_CLK select HAVE_AT91_AUDIO_PLL + select HAVE_AT91_I2S_MUX_CLK select PINCTRL_AT91PIO4 help Select this if ou are using one of Microchip's SAMA5D2 family SoC. @@ -129,6 +130,9 @@ config HAVE_AT91_GENERATED_CLK config HAVE_AT91_AUDIO_PLL bool +config HAVE_AT91_I2S_MUX_CLK + bool + config SOC_SAM_V4_V5 bool diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 721572a8c429..292056bbb30e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -45,6 +45,12 @@ config COMMON_CLK_MAX77686 This driver supports Maxim 77620/77686/77802 crystal oscillator clock. +config COMMON_CLK_MAX9485 + tristate "Maxim 9485 Programmable Clock Generator" + depends on I2C + help + This driver supports Maxim 9485 Programmable Audio Clock Generator + config COMMON_CLK_RK808 tristate "Clock driver for RK805/RK808/RK818" depends on MFD_RK808 diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ae40cbe770f0..24fc2b634362 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -31,6 +31,7 @@ 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_MAX77686) += clk-max77686.o +obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 082596f37c1d..facc169ebb68 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o +obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c new file mode 100644 index 000000000000..f0c3c3079f04 --- /dev/null +++ b/drivers/clk/at91/clk-i2s-mux.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Microchip Technology Inc, + * Codrin Ciubotariu <codrin.ciubotariu@microchip.com> + * + * + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include <soc/at91/atmel-sfr.h> + +#define I2S_BUS_NR 2 + +struct clk_i2s_mux { + struct clk_hw hw; + struct regmap *regmap; + u8 bus_id; +}; + +#define to_clk_i2s_mux(hw) container_of(hw, struct clk_i2s_mux, hw) + +static u8 clk_i2s_mux_get_parent(struct clk_hw *hw) +{ + struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); + u32 val; + + regmap_read(mux->regmap, AT91_SFR_I2SCLKSEL, &val); + + return (val & BIT(mux->bus_id)) >> mux->bus_id; +} + +static int clk_i2s_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_i2s_mux *mux = to_clk_i2s_mux(hw); + + return regmap_update_bits(mux->regmap, AT91_SFR_I2SCLKSEL, + BIT(mux->bus_id), index << mux->bus_id); +} + +static const struct clk_ops clk_i2s_mux_ops = { + .get_parent = clk_i2s_mux_get_parent, + .set_parent = clk_i2s_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static struct clk_hw * __init +at91_clk_i2s_mux_register(struct regmap *regmap, const char *name, + const char * const *parent_names, + unsigned int num_parents, u8 bus_id) +{ + struct clk_init_data init = {}; + struct clk_i2s_mux *i2s_ck; + int ret; + + i2s_ck = kzalloc(sizeof(*i2s_ck), GFP_KERNEL); + if (!i2s_ck) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_i2s_mux_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + + i2s_ck->hw.init = &init; + i2s_ck->bus_id = bus_id; + i2s_ck->regmap = regmap; + + ret = clk_hw_register(NULL, &i2s_ck->hw); + if (ret) { + kfree(i2s_ck); + return ERR_PTR(ret); + } + + return &i2s_ck->hw; +} + +static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np) +{ + struct regmap *regmap_sfr; + u8 bus_id; + const char *parent_names[2]; + struct device_node *i2s_mux_np; + struct clk_hw *hw; + int ret; + + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + return; + + for_each_child_of_node(np, i2s_mux_np) { + if (of_property_read_u8(i2s_mux_np, "reg", &bus_id)) + continue; + + if (bus_id > I2S_BUS_NR) + continue; + + ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2); + if (ret != 2) + continue; + + hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name, + parent_names, 2, bus_id); + if (IS_ERR(hw)) + continue; + + of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw); + } +} + +CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux", + of_sama5d2_clk_i2s_mux_setup); diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c index 38b366b00c57..f49c6842c604 100644 --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -109,7 +109,7 @@ static const struct aspeed_gate_data aspeed_gates[] = { [ASPEED_CLK_GATE_RSACLK] = { 24, -1, "rsaclk-gate", NULL, 0 }, /* RSA */ [ASPEED_CLK_GATE_UART3CLK] = { 25, -1, "uart3clk-gate", "uart", 0 }, /* UART3 */ [ASPEED_CLK_GATE_UART4CLK] = { 26, -1, "uart4clk-gate", "uart", 0 }, /* UART4 */ - [ASPEED_CLK_GATE_SDCLKCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ + [ASPEED_CLK_GATE_SDCLK] = { 27, 16, "sdclk-gate", NULL, 0 }, /* SDIO/SD */ [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */ }; diff --git a/drivers/clk/clk-max9485.c b/drivers/clk/clk-max9485.c new file mode 100644 index 000000000000..5e80f3d090f3 --- /dev/null +++ b/drivers/clk/clk-max9485.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> + +#include <dt-bindings/clock/maxim,max9485.h> + +#define MAX9485_NUM_CLKS 4 + +/* This chip has only one register of 8 bit width. */ + +#define MAX9485_FS_12KHZ (0 << 0) +#define MAX9485_FS_32KHZ (1 << 0) +#define MAX9485_FS_44_1KHZ (2 << 0) +#define MAX9485_FS_48KHZ (3 << 0) + +#define MAX9485_SCALE_256 (0 << 2) +#define MAX9485_SCALE_384 (1 << 2) +#define MAX9485_SCALE_768 (2 << 2) + +#define MAX9485_DOUBLE BIT(4) +#define MAX9485_CLKOUT1_ENABLE BIT(5) +#define MAX9485_CLKOUT2_ENABLE BIT(6) +#define MAX9485_MCLK_ENABLE BIT(7) +#define MAX9485_FREQ_MASK 0x1f + +struct max9485_rate { + unsigned long out; + u8 reg_value; +}; + +/* + * Ordered by frequency. For frequency the hardware can generate with + * multiple settings, the one with lowest jitter is listed first. + */ +static const struct max9485_rate max9485_rates[] = { + { 3072000, MAX9485_FS_12KHZ | MAX9485_SCALE_256 }, + { 4608000, MAX9485_FS_12KHZ | MAX9485_SCALE_384 }, + { 8192000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 }, + { 9126000, MAX9485_FS_12KHZ | MAX9485_SCALE_768 }, + { 11289600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 }, + { 12288000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 }, + { 12288000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 }, + { 16384000, MAX9485_FS_32KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 16934400, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 }, + { 18384000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 }, + { 22579200, MAX9485_FS_44_1KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_48KHZ | MAX9485_SCALE_256 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 24576000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 }, + { 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 33868800, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 }, + { 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_384 | MAX9485_DOUBLE }, + { 36864000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 }, + { 49152000, MAX9485_FS_32KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { 67737600, MAX9485_FS_44_1KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { 73728000, MAX9485_FS_48KHZ | MAX9485_SCALE_768 | MAX9485_DOUBLE }, + { } /* sentinel */ +}; + +struct max9485_driver_data; + +struct max9485_clk_hw { + struct clk_hw hw; + struct clk_init_data init; + u8 enable_bit; + struct max9485_driver_data *drvdata; +}; + +struct max9485_driver_data { + struct clk *xclk; + struct i2c_client *client; + u8 reg_value; + struct regulator *supply; + struct gpio_desc *reset_gpio; + struct max9485_clk_hw hw[MAX9485_NUM_CLKS]; +}; + +static inline struct max9485_clk_hw *to_max9485_clk(struct clk_hw *hw) +{ + return container_of(hw, struct max9485_clk_hw, hw); +} + +static int max9485_update_bits(struct max9485_driver_data *drvdata, + u8 mask, u8 value) +{ + int ret; + + drvdata->reg_value &= ~mask; + drvdata->reg_value |= value; + + dev_dbg(&drvdata->client->dev, + "updating mask 0x%02x value 0x%02x -> 0x%02x\n", + mask, value, drvdata->reg_value); + + ret = i2c_master_send(drvdata->client, + &drvdata->reg_value, + sizeof(drvdata->reg_value)); + + return ret < 0 ? ret : 0; +} + +static int max9485_clk_prepare(struct clk_hw *hw) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + + return max9485_update_bits(clk_hw->drvdata, + clk_hw->enable_bit, + clk_hw->enable_bit); +} + +static void max9485_clk_unprepare(struct clk_hw *hw) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + + max9485_update_bits(clk_hw->drvdata, clk_hw->enable_bit, 0); +} + +/* + * CLKOUT - configurable clock output + */ +static int max9485_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + const struct max9485_rate *entry; + + for (entry = max9485_rates; entry->out != 0; entry++) + if (entry->out == rate) + break; + + if (entry->out == 0) + return -EINVAL; + + return max9485_update_bits(clk_hw->drvdata, + MAX9485_FREQ_MASK, + entry->reg_value); +} + +static unsigned long max9485_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct max9485_clk_hw *clk_hw = to_max9485_clk(hw); + struct max9485_driver_data *drvdata = clk_hw->drvdata; + u8 val = drvdata->reg_value & MAX9485_FREQ_MASK; + const struct max9485_rate *entry; + + for (entry = max9485_rates; entry->out != 0; entry++) + if (val == entry->reg_value) + return entry->out; + + return 0; +} + +static long max9485_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + const struct max9485_rate *curr, *prev = NULL; + + for (curr = max9485_rates; curr->out != 0; curr++) { + /* Exact matches */ + if (curr->out == rate) + return rate; + + /* + * Find the first entry that has a frequency higher than the + * requested one. + */ + if (curr->out > rate) { + unsigned int mid; + + /* + * If this is the first entry, clamp the value to the + * lowest possible frequency. + */ + if (!prev) + return curr->out; + + /* + * Otherwise, determine whether the previous entry or + * current one is closer. + */ + mid = prev->out + ((curr->out - prev->out) / 2); + + return (mid > rate) ? prev->out : curr->out; + } + + prev = curr; + } + + /* If the last entry was still too high, clamp the value */ + return prev->out; +} + +struct max9485_clk { + const char *name; + int parent_index; + const struct clk_ops ops; + u8 enable_bit; +}; + +static const struct max9485_clk max9485_clks[MAX9485_NUM_CLKS] = { + [MAX9485_MCLKOUT] = { + .name = "mclkout", + .parent_index = -1, + .enable_bit = MAX9485_MCLK_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, + [MAX9485_CLKOUT] = { + .name = "clkout", + .parent_index = -1, + .ops = { + .set_rate = max9485_clkout_set_rate, + .round_rate = max9485_clkout_round_rate, + .recalc_rate = max9485_clkout_recalc_rate, + }, + }, + [MAX9485_CLKOUT1] = { + .name = "clkout1", + .parent_index = MAX9485_CLKOUT, + .enable_bit = MAX9485_CLKOUT1_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, + [MAX9485_CLKOUT2] = { + .name = "clkout2", + .parent_index = MAX9485_CLKOUT, + .enable_bit = MAX9485_CLKOUT2_ENABLE, + .ops = { + .prepare = max9485_clk_prepare, + .unprepare = max9485_clk_unprepare, + }, + }, +}; + +static struct clk_hw * +max9485_of_clk_get(struct of_phandle_args *clkspec, void *data) +{ + struct max9485_driver_data *drvdata = data; + unsigned int idx = clkspec->args[0]; + + return &drvdata->hw[idx].hw; +} + +static int max9485_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max9485_driver_data *drvdata; + struct device *dev = &client->dev; + const char *xclk_name; + int i, ret; + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(drvdata->xclk)) + return PTR_ERR(drvdata->xclk); + + xclk_name = __clk_get_name(drvdata->xclk); + + drvdata->supply = devm_regulator_get(dev, "vdd"); + if (IS_ERR(drvdata->supply)) + return PTR_ERR(drvdata->supply); + + ret = regulator_enable(drvdata->supply); + if (ret < 0) + return ret; + + drvdata->reset_gpio = + devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(drvdata->reset_gpio)) + return PTR_ERR(drvdata->reset_gpio); + + i2c_set_clientdata(client, drvdata); + drvdata->client = client; + + ret = i2c_master_recv(drvdata->client, &drvdata->reg_value, + sizeof(drvdata->reg_value)); + if (ret < 0) { + dev_warn(dev, "Unable to read device register: %d\n", ret); + return ret; + } + + for (i = 0; i < MAX9485_NUM_CLKS; i++) { + int parent_index = max9485_clks[i].parent_index; + const char *name; + + if (of_property_read_string_index(dev->of_node, + "clock-output-names", + i, &name) == 0) { + drvdata->hw[i].init.name = name; + } else { + drvdata->hw[i].init.name = max9485_clks[i].name; + } + + drvdata->hw[i].init.ops = &max9485_clks[i].ops; + drvdata->hw[i].init.num_parents = 1; + drvdata->hw[i].init.flags = 0; + + if (parent_index > 0) { + drvdata->hw[i].init.parent_names = + &drvdata->hw[parent_index].init.name; + drvdata->hw[i].init.flags |= CLK_SET_RATE_PARENT; + } else { + drvdata->hw[i].init.parent_names = &xclk_name; + } + + drvdata->hw[i].enable_bit = max9485_clks[i].enable_bit; + drvdata->hw[i].hw.init = &drvdata->hw[i].init; + drvdata->hw[i].drvdata = drvdata; + + ret = devm_clk_hw_register(dev, &drvdata->hw[i].hw); + if (ret < 0) + return ret; + } + + return devm_of_clk_add_hw_provider(dev, max9485_of_clk_get, drvdata); +} + +static int __maybe_unused max9485_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max9485_driver_data *drvdata = i2c_get_clientdata(client); + + gpiod_set_value_cansleep(drvdata->reset_gpio, 0); + + return 0; +} + +static int __maybe_unused max9485_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max9485_driver_data *drvdata = i2c_get_clientdata(client); + int ret; + + gpiod_set_value_cansleep(drvdata->reset_gpio, 1); + + ret = i2c_master_send(client, &drvdata->reg_value, + sizeof(drvdata->reg_value)); + + return ret < 0 ? ret : 0; +} + +static const struct dev_pm_ops max9485_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(max9485_suspend, max9485_resume) +}; + +static const struct of_device_id max9485_dt_ids[] = { + { .compatible = "maxim,max9485", }, + { } +}; +MODULE_DEVICE_TABLE(of, max9485_dt_ids); + +static const struct i2c_device_id max9485_i2c_ids[] = { + { .name = "max9485", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max9485_i2c_ids); + +static struct i2c_driver max9485_driver = { + .driver = { + .name = "max9485", + .pm = &max9485_pm_ops, + .of_match_table = max9485_dt_ids, + }, + .probe = max9485_i2c_probe, + .id_table = max9485_i2c_ids, +}; +module_i2c_driver(max9485_driver); + +MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>"); +MODULE_DESCRIPTION("MAX9485 Programmable Audio Clock Generator"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index 09b6718956bd..153b3a2b5857 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool enable) SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0); } +static int si514_prepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + return si514_enable_output(data, true); +} + +static void si514_unprepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + si514_enable_output(data, false); +} + +static int si514_is_prepared(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI514_REG_CONTROL, &val); + if (err < 0) + return err; + + return !!(val & SI514_CONTROL_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si514_get_muldiv(struct clk_si514 *data, struct clk_si514_muldiv *settings) @@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si514 *data = to_clk_si514(hw); struct clk_si514_muldiv settings; + unsigned int old_oe_state; int err; err = si514_calc_muldiv(&settings, rate); if (err) return err; + err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state); + if (err) + return err; + si514_enable_output(data, false); err = si514_set_muldiv(data, &settings); @@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si514_enable_output(data, true); + if (old_oe_state & SI514_CONTROL_OE) + si514_enable_output(data, true); return err; } static const struct clk_ops si514_clk_ops = { + .prepare = si514_prepare, + .unprepare = si514_unprepare, + .is_prepared = si514_is_prepared, .recalc_rate = si514_recalc_rate, .round_rate = si514_round_rate, .set_rate = si514_set_rate, diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 1e2a3b8f9454..64e607f3232a 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -86,6 +86,33 @@ static int si544_enable_output(struct clk_si544 *data, bool enable) SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0); } +static int si544_prepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + return si544_enable_output(data, true); +} + +static void si544_unprepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + si544_enable_output(data, false); +} + +static int si544_is_prepared(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val); + if (err < 0) + return err; + + return !!(val & SI544_OE_STATE_ODC_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si544_get_muldiv(struct clk_si544 *data, struct clk_si544_muldiv *settings) @@ -273,6 +300,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si544 *data = to_clk_si544(hw); struct clk_si544_muldiv settings; + unsigned int old_oe_state; int err; if (!is_valid_frequency(data, rate)) @@ -282,6 +310,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, if (err) return err; + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &old_oe_state); + if (err) + return err; + si544_enable_output(data, false); /* Allow FCAL for this frequency update */ @@ -303,12 +335,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si544_enable_output(data, true); + if (old_oe_state & SI544_OE_STATE_ODC_OE) + si544_enable_output(data, true); return err; } static const struct clk_ops si544_clk_ops = { + .prepare = si544_prepare, + .unprepare = si544_unprepare, + .is_prepared = si544_is_prepared, .recalc_rate = si544_recalc_rate, .round_rate = si544_round_rate, .set_rate = si544_set_rate, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9760b526ca31..e108f591d84a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -68,6 +68,7 @@ struct clk_core { unsigned long max_rate; unsigned long accuracy; int phase; + struct clk_duty duty; struct hlist_head children; struct hlist_node child_node; struct hlist_head clks; @@ -691,6 +692,9 @@ static void clk_core_unprepare(struct clk_core *core) "Unpreparing critical %s\n", core->name)) return; + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_unprotect(core); + if (--core->prepare_count > 0) return; @@ -765,6 +769,16 @@ static int clk_core_prepare(struct clk_core *core) core->prepare_count++; + /* + * CLK_SET_RATE_GATE is a special case of clock protection + * Instead of a consumer claiming exclusive rate control, it is + * actually the provider which prevents any consumer from making any + * operation which could result in a rate change or rate glitch while + * the clock is prepared. + */ + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_protect(core); + return 0; unprepare: clk_core_unprepare(core->parent); @@ -1888,9 +1902,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (clk_core_rate_is_protected(core)) return -EBUSY; - if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) - return -EBUSY; - /* calculate new rates and get the topmost changed clock */ top = clk_calc_new_rates(core, req_rate); if (!top) @@ -2402,6 +2413,172 @@ int clk_get_phase(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_get_phase); +static void clk_core_reset_duty_cycle_nolock(struct clk_core *core) +{ + /* Assume a default value of 50% */ + core->duty.num = 1; + core->duty.den = 2; +} + +static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core); + +static int clk_core_update_duty_cycle_nolock(struct clk_core *core) +{ + struct clk_duty *duty = &core->duty; + int ret = 0; + + if (!core->ops->get_duty_cycle) + return clk_core_update_duty_cycle_parent_nolock(core); + + ret = core->ops->get_duty_cycle(core->hw, duty); + if (ret) + goto reset; + + /* Don't trust the clock provider too much */ + if (duty->den == 0 || duty->num > duty->den) { + ret = -EINVAL; + goto reset; + } + + return 0; + +reset: + clk_core_reset_duty_cycle_nolock(core); + return ret; +} + +static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core) +{ + int ret = 0; + + if (core->parent && + core->flags & CLK_DUTY_CYCLE_PARENT) { + ret = clk_core_update_duty_cycle_nolock(core->parent); + memcpy(&core->duty, &core->parent->duty, sizeof(core->duty)); + } else { + clk_core_reset_duty_cycle_nolock(core); + } + + return ret; +} + +static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core, + struct clk_duty *duty); + +static int clk_core_set_duty_cycle_nolock(struct clk_core *core, + struct clk_duty *duty) +{ + int ret; + + lockdep_assert_held(&prepare_lock); + + if (clk_core_rate_is_protected(core)) + return -EBUSY; + + trace_clk_set_duty_cycle(core, duty); + + if (!core->ops->set_duty_cycle) + return clk_core_set_duty_cycle_parent_nolock(core, duty); + + ret = core->ops->set_duty_cycle(core->hw, duty); + if (!ret) + memcpy(&core->duty, duty, sizeof(*duty)); + + trace_clk_set_duty_cycle_complete(core, duty); + + return ret; +} + +static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core, + struct clk_duty *duty) +{ + int ret = 0; + + if (core->parent && + core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) { + ret = clk_core_set_duty_cycle_nolock(core->parent, duty); + memcpy(&core->duty, &core->parent->duty, sizeof(core->duty)); + } + + return ret; +} + +/** + * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal + * @clk: clock signal source + * @num: numerator of the duty cycle ratio to be applied + * @den: denominator of the duty cycle ratio to be applied + * + * Apply the duty cycle ratio if the ratio is valid and the clock can + * perform this operation + * + * Returns (0) on success, a negative errno otherwise. + */ +int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den) +{ + int ret; + struct clk_duty duty; + + if (!clk) + return 0; + + /* sanity check the ratio */ + if (den == 0 || num > den) + return -EINVAL; + + duty.num = num; + duty.den = den; + + clk_prepare_lock(); + + if (clk->exclusive_count) + clk_core_rate_unprotect(clk->core); + + ret = clk_core_set_duty_cycle_nolock(clk->core, &duty); + + if (clk->exclusive_count) + clk_core_rate_protect(clk->core); + + clk_prepare_unlock(); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_set_duty_cycle); + +static int clk_core_get_scaled_duty_cycle(struct clk_core *core, + unsigned int scale) +{ + struct clk_duty *duty = &core->duty; + int ret; + + clk_prepare_lock(); + + ret = clk_core_update_duty_cycle_nolock(core); + if (!ret) + ret = mult_frac(scale, duty->num, duty->den); + + clk_prepare_unlock(); + + return ret; +} + +/** + * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal + * @clk: clock signal source + * @scale: scaling factor to be applied to represent the ratio as an integer + * + * Returns the duty cycle ratio of a clock node multiplied by the provided + * scaling factor, or negative errno on error. + */ +int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale) +{ + if (!clk) + return 0; + + return clk_core_get_scaled_duty_cycle(clk->core, scale); +} +EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle); + /** * clk_is_match - check if two clk's point to the same hardware clock * @p: clk compared against q @@ -2455,12 +2632,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, if (!c) return; - seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n", + seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n", level * 3 + 1, "", 30 - level * 3, c->name, c->enable_count, c->prepare_count, c->protect_count, clk_core_get_rate(c), clk_core_get_accuracy(c), - clk_core_get_phase(c)); + clk_core_get_phase(c), + clk_core_get_scaled_duty_cycle(c, 100000)); } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -2482,9 +2660,9 @@ static int clk_summary_show(struct seq_file *s, void *data) struct clk_core *c; struct hlist_head **lists = (struct hlist_head **)s->private; - seq_puts(s, " enable prepare protect \n"); - seq_puts(s, " clock count count count rate accuracy phase\n"); - seq_puts(s, "----------------------------------------------------------------------------------------\n"); + seq_puts(s, " enable prepare protect duty\n"); + seq_puts(s, " clock count count count rate accuracy phase cycle\n"); + seq_puts(s, "---------------------------------------------------------------------------------------------\n"); clk_prepare_lock(); @@ -2511,6 +2689,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); + seq_printf(s, "\"duty_cycle\": %u", + clk_core_get_scaled_duty_cycle(c, 100000)); } static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) @@ -2572,6 +2752,7 @@ static const struct { ENTRY(CLK_SET_RATE_UNGATE), ENTRY(CLK_IS_CRITICAL), ENTRY(CLK_OPS_PARENT_ENABLE), + ENTRY(CLK_DUTY_CYCLE_PARENT), #undef ENTRY }; @@ -2610,6 +2791,17 @@ static int possible_parents_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(possible_parents); +static int clk_duty_cycle_show(struct seq_file *s, void *data) +{ + struct clk_core *core = s->private; + struct clk_duty *duty = &core->duty; + + seq_printf(s, "%u/%u\n", duty->num, duty->den); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle); + static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { struct dentry *root; @@ -2628,6 +2820,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count); debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count); debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count); + debugfs_create_file("clk_duty_cycle", 0444, root, core, + &clk_duty_cycle_fops); if (core->num_parents > 1) debugfs_create_file("clk_possible_parents", 0444, root, core, @@ -2846,6 +3040,11 @@ static int __clk_core_init(struct clk_core *core) core->phase = 0; /* + * Set clk's duty cycle. + */ + clk_core_update_duty_cycle_nolock(core); + + /* * Set clk's rate. The preferred method is to use .recalc_rate. For * simple clocks and lazy developers the default fallback is to use the * parent's rate. If a clock doesn't have a parent (or is orphaned) diff --git a/drivers/clk/imx/clk-imx51-imx53.c b/drivers/clk/imx/clk-imx51-imx53.c index caa8bd40692c..fc8e782d817b 100644 --- a/drivers/clk/imx/clk-imx51-imx53.c +++ b/drivers/clk/imx/clk-imx51-imx53.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/sizes.h> #include <soc/imx/revision.h> #include <dt-bindings/clock/imx5-clock.h> @@ -175,13 +176,13 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_PER_ROOT] = imx_clk_mux("per_root", MXC_CCM_CBCMR, 0, 1, per_root_sel, ARRAY_SIZE(per_root_sel)); clk[IMX5_CLK_AHB] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3); - clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28); - clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24); - clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26); - clk[IMX5_CLK_TMAX1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0); - clk[IMX5_CLK_TMAX2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2); - clk[IMX5_CLK_TMAX3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4); - clk[IMX5_CLK_SPBA] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0); + clk[IMX5_CLK_AHB_MAX] = imx_clk_gate2_flags("ahb_max", "ahb", MXC_CCM_CCGR0, 28, CLK_IS_CRITICAL); + clk[IMX5_CLK_AIPS_TZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", MXC_CCM_CCGR0, 24, CLK_IS_CRITICAL); + clk[IMX5_CLK_AIPS_TZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", MXC_CCM_CCGR0, 26, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX1] = imx_clk_gate2_flags("tmax1", "ahb", MXC_CCM_CCGR1, 0, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX2] = imx_clk_gate2_flags("tmax2", "ahb", MXC_CCM_CCGR1, 2, CLK_IS_CRITICAL); + clk[IMX5_CLK_TMAX3] = imx_clk_gate2_flags("tmax3", "ahb", MXC_CCM_CCGR1, 4, CLK_IS_CRITICAL); + clk[IMX5_CLK_SPBA] = imx_clk_gate2_flags("spba", "ipg", MXC_CCM_CCGR5, 0, CLK_IS_CRITICAL); clk[IMX5_CLK_IPG] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2); clk[IMX5_CLK_AXI_A] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3); clk[IMX5_CLK_AXI_B] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3); @@ -252,8 +253,8 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_ECSPI2_PER_GATE] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24); clk[IMX5_CLK_CSPI_IPG_GATE] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26); clk[IMX5_CLK_SDMA_GATE] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30); - clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14); - clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16); + clk[IMX5_CLK_EMI_FAST_GATE] = imx_clk_gate2_flags("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14, CLK_IS_CRITICAL); + clk[IMX5_CLK_EMI_SLOW_GATE] = imx_clk_gate2_flags("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16, CLK_IS_CRITICAL); clk[IMX5_CLK_IPU_SEL] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); clk[IMX5_CLK_IPU_GATE] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10); clk[IMX5_CLK_NFC_GATE] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20); @@ -267,7 +268,7 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_VPU_SEL] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel)); clk[IMX5_CLK_VPU_GATE] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6); clk[IMX5_CLK_VPU_REFERENCE_GATE] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); - clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24); + clk[IMX5_CLK_GPC_DVFS] = imx_clk_gate2_flags("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24, CLK_IS_CRITICAL); clk[IMX5_CLK_SSI_APM] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels)); clk[IMX5_CLK_SSI1_ROOT_SEL] = imx_clk_mux("ssi1_root_sel", MXC_CCM_CSCMR1, 14, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); @@ -316,21 +317,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) /* move usb phy clk to 24MHz */ clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]); - - clk_prepare_enable(clk[IMX5_CLK_GPC_DVFS]); - clk_prepare_enable(clk[IMX5_CLK_AHB_MAX]); /* esdhc3 */ - clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ1]); - clk_prepare_enable(clk[IMX5_CLK_AIPS_TZ2]); /* fec */ - clk_prepare_enable(clk[IMX5_CLK_SPBA]); - clk_prepare_enable(clk[IMX5_CLK_EMI_FAST_GATE]); /* fec */ - clk_prepare_enable(clk[IMX5_CLK_EMI_SLOW_GATE]); /* eim */ - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC1_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSC2_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_ESC_GATE]); - clk_prepare_enable(clk[IMX5_CLK_MIPI_HSP_GATE]); - clk_prepare_enable(clk[IMX5_CLK_TMAX1]); - clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */ - clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */ } static void __init mx50_clocks_init(struct device_node *np) @@ -442,10 +428,10 @@ static void __init mx51_clocks_init(struct device_node *np) clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0); clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22); - clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6); - clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8); - clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10); - clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12); + clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL); + clk[IMX5_CLK_MIPI_HSP_GATE] = imx_clk_gate2_flags("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12, CLK_IS_CRITICAL); clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2, mx51_spdif_xtal_sel, ARRAY_SIZE(mx51_spdif_xtal_sel)); clk[IMX5_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", MXC_CCM_CSCMR2, 2, 2, diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index b9ea7037e193..0662db5d37c6 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -65,7 +65,7 @@ static const char *ipg_per_sels[] = { "ipg", "osc", }; static const char *ecspi_sels[] = { "pll3_60m", "osc", }; static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", }; static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", - "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", + "video_27m", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", }; static const char *cko2_sels[] = { "mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1", diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 3651c77fbabe..627064597af9 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -253,6 +253,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10); clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); + clks[IMX6SLL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30); /* CCGR1 */ clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -267,13 +268,17 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); + clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); /* CCGR2 */ + clks[IMX6SLL_CLK_GPIO6] = imx_clk_gate2("gpio6", "ipg", base + 0x70, 0); clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2); clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6SLL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26); clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); @@ -283,6 +288,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node) clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4); clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4); clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6SLL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index ba563ba50b40..d3f7f4db80af 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -79,12 +79,6 @@ static const char *cko_sels[] = { "cko1", "cko2", }; static struct clk *clks[IMX6UL_CLK_END]; static struct clk_onecell_data clk_data; -static int const clks_init_on[] __initconst = { - IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, - IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, - IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, -}; - static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -129,7 +123,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -336,8 +329,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); /* CCGR0 */ - clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL); clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); @@ -360,6 +353,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); if (clk_on_imx6ull()) clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18); + clks[IMX6UL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30); /* CCGR1 */ clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -376,6 +370,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24); + clks[IMX6UL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); + clks[IMX6UL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); /* CCGR2 */ if (clk_on_imx6ull()) { @@ -389,6 +385,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); + clks[IMX6UL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26); clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); @@ -405,11 +402,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); - clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); + clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); @@ -423,7 +421,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); /* CCGR5 */ - clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6UL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8); clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); @@ -497,10 +495,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); - /* keep all the clks on just for bringup */ - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - if (clk_on_imx6ull()) clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]); diff --git a/drivers/clk/ingenic/jz4740-cgu.c b/drivers/clk/ingenic/jz4740-cgu.c index 32fcc75f6f77..4479c102e899 100644 --- a/drivers/clk/ingenic/jz4740-cgu.c +++ b/drivers/clk/ingenic/jz4740-cgu.c @@ -134,7 +134,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { "i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 31, 1 }, - .div = { CGU_REG_I2SCDR, 0, 1, 8, -1, -1, -1 }, + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, .gate = { CGU_REG_CLKGR, 6 }, }, @@ -161,7 +161,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = { }, [JZ4740_CLK_UDC] = { - "udc", CGU_CLK_MUX | CGU_CLK_DIV, + "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 }, .mux = { CGU_REG_CPCCR, 29, 1 }, .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c index 6416c1f8e632..e88f8e01fe3a 100644 --- a/drivers/clk/pxa/clk-pxa25x.c +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -292,8 +292,10 @@ static void __init pxa25x_register_plls(void) { clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL, CLK_GET_RATE_NOCACHE, 3686400); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, 32768); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768)); clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz", 0, 26, 1); diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index 25a30194d27a..d40b63e7bbce 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -314,9 +314,10 @@ static void __init pxa27x_register_plls(void) clk_register_fixed_rate(NULL, "osc_13mhz", NULL, CLK_GET_RATE_NOCACHE, 13 * MHz); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, - 32768 * KHz); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768 * KHz)); clk_register_fixed_rate(NULL, "clk_dummy", NULL, 0, 0); clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); } diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c index 2d126df2bccd..7aa120c3bd08 100644 --- a/drivers/clk/pxa/clk-pxa3xx.c +++ b/drivers/clk/pxa/clk-pxa3xx.c @@ -286,9 +286,10 @@ static void __init pxa3xx_register_plls(void) clk_register_fixed_rate(NULL, "osc_13mhz", NULL, CLK_GET_RATE_NOCACHE, 13 * MHz); - clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, - CLK_GET_RATE_NOCACHE, - 32768); + clkdev_pxa_register(CLK_OSC32k768, "osc_32_768khz", NULL, + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE, + 32768)); clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL, CLK_GET_RATE_NOCACHE, 120 * MHz); diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 28eb200d0f1e..5f61225657ab 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -1220,7 +1220,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1269,7 +1268,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1353,7 +1351,6 @@ static struct clk_rcg tsif_ref_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index b99dd406e907..849046fbed6d 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -947,7 +947,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -996,7 +995,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index c347a0d44bc8..7e930e25c79f 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -1558,7 +1558,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1607,7 +1606,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1656,7 +1654,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1705,7 +1702,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1754,7 +1750,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index eb551c75fba6..fd495e0471bb 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -1628,7 +1628,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1677,7 +1676,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1726,7 +1724,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1775,7 +1772,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1824,7 +1820,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index e78e6f5b99fc..0f694ed4238a 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -1103,6 +1103,7 @@ static struct clk_branch gcc_camera_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1129,6 +1130,7 @@ static struct clk_branch gcc_camera_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_camera_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1270,6 +1272,7 @@ static struct clk_branch gcc_disp_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1328,6 +1331,7 @@ static struct clk_branch gcc_disp_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_disp_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -1397,6 +1401,7 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_cfg_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2985,6 +2990,7 @@ static struct clk_branch gcc_video_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_ahb_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3011,6 +3017,7 @@ static struct clk_branch gcc_video_xo_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_video_xo_clk", + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3049,6 +3056,36 @@ static struct clk_branch gcc_vs_ctrl_clk = { }, }; +static struct clk_branch gcc_cpuss_dvm_bus_clk = { + .halt_reg = 0x48190, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x48190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_dvm_bus_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_gnoc_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_gnoc_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, .pd = { @@ -3344,6 +3381,8 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, [GPLL4] = &gpll4.clkr, + [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, + [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { @@ -3433,10 +3472,6 @@ static int gcc_sdm845_probe(struct platform_device *pdev) regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); regmap_update_bits(regmap, 0x71028, 0x3, 0x3); - /* Enable CPUSS clocks */ - regmap_update_bits(regmap, 0x48190, BIT(0), 0x1); - regmap_update_bits(regmap, 0x52004, BIT(22), 0x1); - return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); } diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index f9ba71311727..9022bbe1297e 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -21,6 +21,7 @@ config CLK_RENESAS select CLK_R8A77980 if ARCH_R8A77980 select CLK_R8A77990 if ARCH_R8A77990 select CLK_R8A77995 if ARCH_R8A77995 + select CLK_R9A06G032 if ARCH_R9A06G032 select CLK_SH73A0 if ARCH_SH73A0 if CLK_RENESAS @@ -125,6 +126,11 @@ config CLK_R8A77995 bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R9A06G032 + bool "Renesas R9A06G032 clock driver" + help + This is a driver for R9A06G032 clocks + config CLK_SH73A0 bool "SH-Mobile AG5 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index fe5bac9215e5..e4aa3d6143d2 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o obj-$(CONFIG_CLK_R8A77980) += r8a77980-cpg-mssr.o obj-$(CONFIG_CLK_R8A77990) += r8a77990-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o +obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 775b0ceaa337..a85dd50e8911 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -103,6 +103,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_GEN3_SD("sd3", R8A7795_CLK_SD3, CLK_SDSRC, 0x26c), DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cr", R8A7795_CLK_CR, CLK_PLL1_DIV4, 2, 1), DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), DEF_DIV6P1("canfd", R8A7795_CLK_CANFD, CLK_PLL1_DIV4, 0x244), @@ -132,6 +133,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S0D3), DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S0D3), DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S0D3), + DEF_MOD("sceg-pub", 229, R8A7795_CLK_CR), DEF_MOD("cmt3", 300, R8A7795_CLK_R), DEF_MOD("cmt2", 301, R8A7795_CLK_R), DEF_MOD("cmt1", 302, R8A7795_CLK_R), diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c new file mode 100644 index 000000000000..a0b6ecdc63dd --- /dev/null +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -0,0 +1,893 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R9A09G032 clock driver + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <dt-bindings/clock/r9a06g032-sysctrl.h> + +struct r9a06g032_gate { + u16 gate, reset, ready, midle, + scon, mirack, mistat; +}; + +/* This is used to describe a clock for instantiation */ +struct r9a06g032_clkdesc { + const char *name; + uint32_t type: 3; + uint32_t index: 8; + uint32_t source : 8; /* source index + 1 (0 == none) */ + /* these are used to populate the bitsel struct */ + union { + struct r9a06g032_gate gate; + /* for dividers */ + struct { + unsigned int div_min : 10, div_max : 10, reg: 10; + u16 div_table[4]; + }; + /* For fixed-factor ones */ + struct { + u16 div, mul; + }; + unsigned int factor; + unsigned int frequency; + /* for dual gate */ + struct { + uint16_t group : 1, index: 3; + u16 sel, g1, r1, g2, r2; + } dual; + }; +} __packed; + +#define I_GATE(_clk, _rst, _rdy, _midle, _scon, _mirack, _mistat) \ + { .gate = _clk, .reset = _rst, \ + .ready = _rdy, .midle = _midle, \ + .scon = _scon, .mirack = _mirack, .mistat = _mistat } +#define D_GATE(_idx, _n, _src, ...) \ + { .type = K_GATE, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .gate = I_GATE(__VA_ARGS__), } +#define D_ROOT(_idx, _n, _mul, _div) \ + { .type = K_FFC, .index = R9A06G032_##_idx, .name = _n, \ + .div = _div, .mul = _mul } +#define D_FFC(_idx, _n, _src, _div) \ + { .type = K_FFC, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .div = _div, .mul = 1} +#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) \ + { .type = K_DIV, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .reg = _reg, .div_min = _min, .div_max = _max, \ + .div_table = { __VA_ARGS__ } } +#define D_UGATE(_idx, _n, _src, _g, _gi, _g1, _r1, _g2, _r2) \ + { .type = K_DUALGATE, .index = R9A06G032_##_idx, \ + .source = 1 + R9A06G032_##_src, .name = _n, \ + .dual = { .group = _g, .index = _gi, \ + .g1 = _g1, .r1 = _r1, .g2 = _g2, .r2 = _r2 }, } + +enum { K_GATE = 0, K_FFC, K_DIV, K_BITSEL, K_DUALGATE }; + +/* Internal clock IDs */ +#define R9A06G032_CLKOUT 0 +#define R9A06G032_CLKOUT_D10 2 +#define R9A06G032_CLKOUT_D16 3 +#define R9A06G032_CLKOUT_D160 4 +#define R9A06G032_CLKOUT_D1OR2 5 +#define R9A06G032_CLKOUT_D20 6 +#define R9A06G032_CLKOUT_D40 7 +#define R9A06G032_CLKOUT_D5 8 +#define R9A06G032_CLKOUT_D8 9 +#define R9A06G032_DIV_ADC 10 +#define R9A06G032_DIV_I2C 11 +#define R9A06G032_DIV_NAND 12 +#define R9A06G032_DIV_P1_PG 13 +#define R9A06G032_DIV_P2_PG 14 +#define R9A06G032_DIV_P3_PG 15 +#define R9A06G032_DIV_P4_PG 16 +#define R9A06G032_DIV_P5_PG 17 +#define R9A06G032_DIV_P6_PG 18 +#define R9A06G032_DIV_QSPI0 19 +#define R9A06G032_DIV_QSPI1 20 +#define R9A06G032_DIV_REF_SYNC 21 +#define R9A06G032_DIV_SDIO0 22 +#define R9A06G032_DIV_SDIO1 23 +#define R9A06G032_DIV_SWITCH 24 +#define R9A06G032_DIV_UART 25 +#define R9A06G032_DIV_MOTOR 64 +#define R9A06G032_CLK_DDRPHY_PLLCLK_D4 78 +#define R9A06G032_CLK_ECAT100_D4 79 +#define R9A06G032_CLK_HSR100_D2 80 +#define R9A06G032_CLK_REF_SYNC_D4 81 +#define R9A06G032_CLK_REF_SYNC_D8 82 +#define R9A06G032_CLK_SERCOS100_D2 83 +#define R9A06G032_DIV_CA7 84 + +#define R9A06G032_UART_GROUP_012 154 +#define R9A06G032_UART_GROUP_34567 155 + +#define R9A06G032_CLOCK_COUNT (R9A06G032_UART_GROUP_34567 + 1) + +static const struct r9a06g032_clkdesc r9a06g032_clocks[] __initconst = { + D_ROOT(CLKOUT, "clkout", 25, 1), + D_ROOT(CLK_PLL_USB, "clk_pll_usb", 12, 10), + D_FFC(CLKOUT_D10, "clkout_d10", CLKOUT, 10), + D_FFC(CLKOUT_D16, "clkout_d16", CLKOUT, 16), + D_FFC(CLKOUT_D160, "clkout_d160", CLKOUT, 160), + D_DIV(CLKOUT_D1OR2, "clkout_d1or2", CLKOUT, 0, 1, 2), + D_FFC(CLKOUT_D20, "clkout_d20", CLKOUT, 20), + D_FFC(CLKOUT_D40, "clkout_d40", CLKOUT, 40), + D_FFC(CLKOUT_D5, "clkout_d5", CLKOUT, 5), + D_FFC(CLKOUT_D8, "clkout_d8", CLKOUT, 8), + D_DIV(DIV_ADC, "div_adc", CLKOUT, 77, 50, 250), + D_DIV(DIV_I2C, "div_i2c", CLKOUT, 78, 12, 16), + D_DIV(DIV_NAND, "div_nand", CLKOUT, 82, 12, 32), + D_DIV(DIV_P1_PG, "div_p1_pg", CLKOUT, 68, 12, 200), + D_DIV(DIV_P2_PG, "div_p2_pg", CLKOUT, 62, 12, 128), + D_DIV(DIV_P3_PG, "div_p3_pg", CLKOUT, 64, 8, 128), + D_DIV(DIV_P4_PG, "div_p4_pg", CLKOUT, 66, 8, 128), + D_DIV(DIV_P5_PG, "div_p5_pg", CLKOUT, 71, 10, 40), + D_DIV(DIV_P6_PG, "div_p6_pg", CLKOUT, 18, 12, 64), + D_DIV(DIV_QSPI0, "div_qspi0", CLKOUT, 73, 3, 7), + D_DIV(DIV_QSPI1, "div_qspi1", CLKOUT, 25, 3, 7), + D_DIV(DIV_REF_SYNC, "div_ref_sync", CLKOUT, 56, 2, 16, 2, 4, 8, 16), + D_DIV(DIV_SDIO0, "div_sdio0", CLKOUT, 74, 20, 128), + D_DIV(DIV_SDIO1, "div_sdio1", CLKOUT, 75, 20, 128), + D_DIV(DIV_SWITCH, "div_switch", CLKOUT, 37, 5, 40), + D_DIV(DIV_UART, "div_uart", CLKOUT, 79, 12, 128), + D_GATE(CLK_25_PG4, "clk_25_pg4", CLKOUT_D40, 0x749, 0x74a, 0x74b, 0, 0xae3, 0, 0), + D_GATE(CLK_25_PG5, "clk_25_pg5", CLKOUT_D40, 0x74c, 0x74d, 0x74e, 0, 0xae4, 0, 0), + D_GATE(CLK_25_PG6, "clk_25_pg6", CLKOUT_D40, 0x74f, 0x750, 0x751, 0, 0xae5, 0, 0), + D_GATE(CLK_25_PG7, "clk_25_pg7", CLKOUT_D40, 0x752, 0x753, 0x754, 0, 0xae6, 0, 0), + D_GATE(CLK_25_PG8, "clk_25_pg8", CLKOUT_D40, 0x755, 0x756, 0x757, 0, 0xae7, 0, 0), + D_GATE(CLK_ADC, "clk_adc", DIV_ADC, 0x1ea, 0x1eb, 0, 0, 0, 0, 0), + D_GATE(CLK_ECAT100, "clk_ecat100", CLKOUT_D10, 0x405, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_HSR100, "clk_hsr100", CLKOUT_D10, 0x483, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_I2C0, "clk_i2c0", DIV_I2C, 0x1e6, 0x1e7, 0, 0, 0, 0, 0), + D_GATE(CLK_I2C1, "clk_i2c1", DIV_I2C, 0x1e8, 0x1e9, 0, 0, 0, 0, 0), + D_GATE(CLK_MII_REF, "clk_mii_ref", CLKOUT_D40, 0x342, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_NAND, "clk_nand", DIV_NAND, 0x284, 0x285, 0, 0, 0, 0, 0), + D_GATE(CLK_NOUSBP2_PG6, "clk_nousbp2_pg6", DIV_P2_PG, 0x774, 0x775, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG2, "clk_p1_pg2", DIV_P1_PG, 0x862, 0x863, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG3, "clk_p1_pg3", DIV_P1_PG, 0x864, 0x865, 0, 0, 0, 0, 0), + D_GATE(CLK_P1_PG4, "clk_p1_pg4", DIV_P1_PG, 0x866, 0x867, 0, 0, 0, 0, 0), + D_GATE(CLK_P4_PG3, "clk_p4_pg3", DIV_P4_PG, 0x824, 0x825, 0, 0, 0, 0, 0), + D_GATE(CLK_P4_PG4, "clk_p4_pg4", DIV_P4_PG, 0x826, 0x827, 0, 0, 0, 0, 0), + D_GATE(CLK_P6_PG1, "clk_p6_pg1", DIV_P6_PG, 0x8a0, 0x8a1, 0x8a2, 0, 0xb60, 0, 0), + D_GATE(CLK_P6_PG2, "clk_p6_pg2", DIV_P6_PG, 0x8a3, 0x8a4, 0x8a5, 0, 0xb61, 0, 0), + D_GATE(CLK_P6_PG3, "clk_p6_pg3", DIV_P6_PG, 0x8a6, 0x8a7, 0x8a8, 0, 0xb62, 0, 0), + D_GATE(CLK_P6_PG4, "clk_p6_pg4", DIV_P6_PG, 0x8a9, 0x8aa, 0x8ab, 0, 0xb63, 0, 0), + D_GATE(CLK_QSPI0, "clk_qspi0", DIV_QSPI0, 0x2a4, 0x2a5, 0, 0, 0, 0, 0), + D_GATE(CLK_QSPI1, "clk_qspi1", DIV_QSPI1, 0x484, 0x485, 0, 0, 0, 0, 0), + D_GATE(CLK_RGMII_REF, "clk_rgmii_ref", CLKOUT_D8, 0x340, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_RMII_REF, "clk_rmii_ref", CLKOUT_D20, 0x341, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SDIO0, "clk_sdio0", DIV_SDIO0, 0x64, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SDIO1, "clk_sdio1", DIV_SDIO1, 0x644, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SERCOS100, "clk_sercos100", CLKOUT_D10, 0x425, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_SLCD, "clk_slcd", DIV_P1_PG, 0x860, 0x861, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI0, "clk_spi0", DIV_P3_PG, 0x7e0, 0x7e1, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI1, "clk_spi1", DIV_P3_PG, 0x7e2, 0x7e3, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI2, "clk_spi2", DIV_P3_PG, 0x7e4, 0x7e5, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI3, "clk_spi3", DIV_P3_PG, 0x7e6, 0x7e7, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI4, "clk_spi4", DIV_P4_PG, 0x820, 0x821, 0, 0, 0, 0, 0), + D_GATE(CLK_SPI5, "clk_spi5", DIV_P4_PG, 0x822, 0x823, 0, 0, 0, 0, 0), + D_GATE(CLK_SWITCH, "clk_switch", DIV_SWITCH, 0x982, 0x983, 0, 0, 0, 0, 0), + D_DIV(DIV_MOTOR, "div_motor", CLKOUT_D5, 84, 2, 8), + D_GATE(HCLK_ECAT125, "hclk_ecat125", CLKOUT_D8, 0x400, 0x401, 0, 0x402, 0, 0x440, 0x441), + D_GATE(HCLK_PINCONFIG, "hclk_pinconfig", CLKOUT_D40, 0x740, 0x741, 0x742, 0, 0xae0, 0, 0), + D_GATE(HCLK_SERCOS, "hclk_sercos", CLKOUT_D10, 0x420, 0x422, 0, 0x421, 0, 0x460, 0x461), + D_GATE(HCLK_SGPIO2, "hclk_sgpio2", DIV_P5_PG, 0x8c3, 0x8c4, 0x8c5, 0, 0xb41, 0, 0), + D_GATE(HCLK_SGPIO3, "hclk_sgpio3", DIV_P5_PG, 0x8c6, 0x8c7, 0x8c8, 0, 0xb42, 0, 0), + D_GATE(HCLK_SGPIO4, "hclk_sgpio4", DIV_P5_PG, 0x8c9, 0x8ca, 0x8cb, 0, 0xb43, 0, 0), + D_GATE(HCLK_TIMER0, "hclk_timer0", CLKOUT_D40, 0x743, 0x744, 0x745, 0, 0xae1, 0, 0), + D_GATE(HCLK_TIMER1, "hclk_timer1", CLKOUT_D40, 0x746, 0x747, 0x748, 0, 0xae2, 0, 0), + D_GATE(HCLK_USBF, "hclk_usbf", CLKOUT_D8, 0xe3, 0, 0, 0xe4, 0, 0x102, 0x103), + D_GATE(HCLK_USBH, "hclk_usbh", CLKOUT_D8, 0xe0, 0xe1, 0, 0xe2, 0, 0x100, 0x101), + D_GATE(HCLK_USBPM, "hclk_usbpm", CLKOUT_D8, 0xe5, 0, 0, 0, 0, 0, 0), + D_GATE(CLK_48_PG_F, "clk_48_pg_f", CLK_48, 0x78c, 0x78d, 0, 0x78e, 0, 0xb04, 0xb05), + D_GATE(CLK_48_PG4, "clk_48_pg4", CLK_48, 0x789, 0x78a, 0x78b, 0, 0xb03, 0, 0), + D_FFC(CLK_DDRPHY_PLLCLK_D4, "clk_ddrphy_pllclk_d4", CLK_DDRPHY_PLLCLK, 4), + D_FFC(CLK_ECAT100_D4, "clk_ecat100_d4", CLK_ECAT100, 4), + D_FFC(CLK_HSR100_D2, "clk_hsr100_d2", CLK_HSR100, 2), + D_FFC(CLK_REF_SYNC_D4, "clk_ref_sync_d4", CLK_REF_SYNC, 4), + D_FFC(CLK_REF_SYNC_D8, "clk_ref_sync_d8", CLK_REF_SYNC, 8), + D_FFC(CLK_SERCOS100_D2, "clk_sercos100_d2", CLK_SERCOS100, 2), + D_DIV(DIV_CA7, "div_ca7", CLK_REF_SYNC, 57, 1, 4, 1, 2, 4), + D_GATE(HCLK_CAN0, "hclk_can0", CLK_48, 0x783, 0x784, 0x785, 0, 0xb01, 0, 0), + D_GATE(HCLK_CAN1, "hclk_can1", CLK_48, 0x786, 0x787, 0x788, 0, 0xb02, 0, 0), + D_GATE(HCLK_DELTASIGMA, "hclk_deltasigma", DIV_MOTOR, 0x1ef, 0x1f0, 0x1f1, 0, 0, 0, 0), + D_GATE(HCLK_PWMPTO, "hclk_pwmpto", DIV_MOTOR, 0x1ec, 0x1ed, 0x1ee, 0, 0, 0, 0), + D_GATE(HCLK_RSV, "hclk_rsv", CLK_48, 0x780, 0x781, 0x782, 0, 0xb00, 0, 0), + D_GATE(HCLK_SGPIO0, "hclk_sgpio0", DIV_MOTOR, 0x1e0, 0x1e1, 0x1e2, 0, 0, 0, 0), + D_GATE(HCLK_SGPIO1, "hclk_sgpio1", DIV_MOTOR, 0x1e3, 0x1e4, 0x1e5, 0, 0, 0, 0), + D_DIV(RTOS_MDC, "rtos_mdc", CLK_REF_SYNC, 100, 80, 640, 80, 160, 320, 640), + D_GATE(CLK_CM3, "clk_cm3", CLK_REF_SYNC_D4, 0xba0, 0xba1, 0, 0xba2, 0, 0xbc0, 0xbc1), + D_GATE(CLK_DDRC, "clk_ddrc", CLK_DDRPHY_PLLCLK_D4, 0x323, 0x324, 0, 0, 0, 0, 0), + D_GATE(CLK_ECAT25, "clk_ecat25", CLK_ECAT100_D4, 0x403, 0x404, 0, 0, 0, 0, 0), + D_GATE(CLK_HSR50, "clk_hsr50", CLK_HSR100_D2, 0x484, 0x485, 0, 0, 0, 0, 0), + D_GATE(CLK_HW_RTOS, "clk_hw_rtos", CLK_REF_SYNC_D4, 0xc60, 0xc61, 0, 0, 0, 0, 0), + D_GATE(CLK_SERCOS50, "clk_sercos50", CLK_SERCOS100_D2, 0x424, 0x423, 0, 0, 0, 0, 0), + D_GATE(HCLK_ADC, "hclk_adc", CLK_REF_SYNC_D8, 0x1af, 0x1b0, 0x1b1, 0, 0, 0, 0), + D_GATE(HCLK_CM3, "hclk_cm3", CLK_REF_SYNC_D4, 0xc20, 0xc21, 0xc22, 0, 0, 0, 0), + D_GATE(HCLK_CRYPTO_EIP150, "hclk_crypto_eip150", CLK_REF_SYNC_D4, 0x123, 0x124, 0x125, 0, 0x142, 0, 0), + D_GATE(HCLK_CRYPTO_EIP93, "hclk_crypto_eip93", CLK_REF_SYNC_D4, 0x120, 0x121, 0, 0x122, 0, 0x140, 0x141), + D_GATE(HCLK_DDRC, "hclk_ddrc", CLK_REF_SYNC_D4, 0x320, 0x322, 0, 0x321, 0, 0x3a0, 0x3a1), + D_GATE(HCLK_DMA0, "hclk_dma0", CLK_REF_SYNC_D4, 0x260, 0x261, 0x262, 0x263, 0x2c0, 0x2c1, 0x2c2), + D_GATE(HCLK_DMA1, "hclk_dma1", CLK_REF_SYNC_D4, 0x264, 0x265, 0x266, 0x267, 0x2c3, 0x2c4, 0x2c5), + D_GATE(HCLK_GMAC0, "hclk_gmac0", CLK_REF_SYNC_D4, 0x360, 0x361, 0x362, 0x363, 0x3c0, 0x3c1, 0x3c2), + D_GATE(HCLK_GMAC1, "hclk_gmac1", CLK_REF_SYNC_D4, 0x380, 0x381, 0x382, 0x383, 0x3e0, 0x3e1, 0x3e2), + D_GATE(HCLK_GPIO0, "hclk_gpio0", CLK_REF_SYNC_D4, 0x212, 0x213, 0x214, 0, 0, 0, 0), + D_GATE(HCLK_GPIO1, "hclk_gpio1", CLK_REF_SYNC_D4, 0x215, 0x216, 0x217, 0, 0, 0, 0), + D_GATE(HCLK_GPIO2, "hclk_gpio2", CLK_REF_SYNC_D4, 0x229, 0x22a, 0x22b, 0, 0, 0, 0), + D_GATE(HCLK_HSR, "hclk_hsr", CLK_HSR100_D2, 0x480, 0x482, 0, 0x481, 0, 0x4c0, 0x4c1), + D_GATE(HCLK_I2C0, "hclk_i2c0", CLK_REF_SYNC_D8, 0x1a9, 0x1aa, 0x1ab, 0, 0, 0, 0), + D_GATE(HCLK_I2C1, "hclk_i2c1", CLK_REF_SYNC_D8, 0x1ac, 0x1ad, 0x1ae, 0, 0, 0, 0), + D_GATE(HCLK_LCD, "hclk_lcd", CLK_REF_SYNC_D4, 0x7a0, 0x7a1, 0x7a2, 0, 0xb20, 0, 0), + D_GATE(HCLK_MSEBI_M, "hclk_msebi_m", CLK_REF_SYNC_D4, 0x164, 0x165, 0x166, 0, 0x183, 0, 0), + D_GATE(HCLK_MSEBI_S, "hclk_msebi_s", CLK_REF_SYNC_D4, 0x160, 0x161, 0x162, 0x163, 0x180, 0x181, 0x182), + D_GATE(HCLK_NAND, "hclk_nand", CLK_REF_SYNC_D4, 0x280, 0x281, 0x282, 0x283, 0x2e0, 0x2e1, 0x2e2), + D_GATE(HCLK_PG_I, "hclk_pg_i", CLK_REF_SYNC_D4, 0x7ac, 0x7ad, 0, 0x7ae, 0, 0xb24, 0xb25), + D_GATE(HCLK_PG19, "hclk_pg19", CLK_REF_SYNC_D4, 0x22c, 0x22d, 0x22e, 0, 0, 0, 0), + D_GATE(HCLK_PG20, "hclk_pg20", CLK_REF_SYNC_D4, 0x22f, 0x230, 0x231, 0, 0, 0, 0), + D_GATE(HCLK_PG3, "hclk_pg3", CLK_REF_SYNC_D4, 0x7a6, 0x7a7, 0x7a8, 0, 0xb22, 0, 0), + D_GATE(HCLK_PG4, "hclk_pg4", CLK_REF_SYNC_D4, 0x7a9, 0x7aa, 0x7ab, 0, 0xb23, 0, 0), + D_GATE(HCLK_QSPI0, "hclk_qspi0", CLK_REF_SYNC_D4, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x300, 0x301, 0x302), + D_GATE(HCLK_QSPI1, "hclk_qspi1", CLK_REF_SYNC_D4, 0x480, 0x481, 0x482, 0x483, 0x4c0, 0x4c1, 0x4c2), + D_GATE(HCLK_ROM, "hclk_rom", CLK_REF_SYNC_D4, 0xaa0, 0xaa1, 0xaa2, 0, 0xb80, 0, 0), + D_GATE(HCLK_RTC, "hclk_rtc", CLK_REF_SYNC_D8, 0xa00, 0, 0, 0, 0, 0, 0), + D_GATE(HCLK_SDIO0, "hclk_sdio0", CLK_REF_SYNC_D4, 0x60, 0x61, 0x62, 0x63, 0x80, 0x81, 0x82), + D_GATE(HCLK_SDIO1, "hclk_sdio1", CLK_REF_SYNC_D4, 0x640, 0x641, 0x642, 0x643, 0x660, 0x661, 0x662), + D_GATE(HCLK_SEMAP, "hclk_semap", CLK_REF_SYNC_D4, 0x7a3, 0x7a4, 0x7a5, 0, 0xb21, 0, 0), + D_GATE(HCLK_SPI0, "hclk_spi0", CLK_REF_SYNC_D4, 0x200, 0x201, 0x202, 0, 0, 0, 0), + D_GATE(HCLK_SPI1, "hclk_spi1", CLK_REF_SYNC_D4, 0x203, 0x204, 0x205, 0, 0, 0, 0), + D_GATE(HCLK_SPI2, "hclk_spi2", CLK_REF_SYNC_D4, 0x206, 0x207, 0x208, 0, 0, 0, 0), + D_GATE(HCLK_SPI3, "hclk_spi3", CLK_REF_SYNC_D4, 0x209, 0x20a, 0x20b, 0, 0, 0, 0), + D_GATE(HCLK_SPI4, "hclk_spi4", CLK_REF_SYNC_D4, 0x20c, 0x20d, 0x20e, 0, 0, 0, 0), + D_GATE(HCLK_SPI5, "hclk_spi5", CLK_REF_SYNC_D4, 0x20f, 0x210, 0x211, 0, 0, 0, 0), + D_GATE(HCLK_SWITCH, "hclk_switch", CLK_REF_SYNC_D4, 0x980, 0, 0x981, 0, 0, 0, 0), + D_GATE(HCLK_SWITCH_RG, "hclk_switch_rg", CLK_REF_SYNC_D4, 0xc40, 0xc41, 0xc42, 0, 0, 0, 0), + D_GATE(HCLK_UART0, "hclk_uart0", CLK_REF_SYNC_D8, 0x1a0, 0x1a1, 0x1a2, 0, 0, 0, 0), + D_GATE(HCLK_UART1, "hclk_uart1", CLK_REF_SYNC_D8, 0x1a3, 0x1a4, 0x1a5, 0, 0, 0, 0), + D_GATE(HCLK_UART2, "hclk_uart2", CLK_REF_SYNC_D8, 0x1a6, 0x1a7, 0x1a8, 0, 0, 0, 0), + D_GATE(HCLK_UART3, "hclk_uart3", CLK_REF_SYNC_D4, 0x218, 0x219, 0x21a, 0, 0, 0, 0), + D_GATE(HCLK_UART4, "hclk_uart4", CLK_REF_SYNC_D4, 0x21b, 0x21c, 0x21d, 0, 0, 0, 0), + D_GATE(HCLK_UART5, "hclk_uart5", CLK_REF_SYNC_D4, 0x220, 0x221, 0x222, 0, 0, 0, 0), + D_GATE(HCLK_UART6, "hclk_uart6", CLK_REF_SYNC_D4, 0x223, 0x224, 0x225, 0, 0, 0, 0), + D_GATE(HCLK_UART7, "hclk_uart7", CLK_REF_SYNC_D4, 0x226, 0x227, 0x228, 0, 0, 0, 0), + /* + * These are not hardware clocks, but are needed to handle the special + * case where we have a 'selector bit' that doesn't just change the + * parent for a clock, but also the gate it's suposed to use. + */ + { + .index = R9A06G032_UART_GROUP_012, + .name = "uart_group_012", + .type = K_BITSEL, + .source = 1 + R9A06G032_DIV_UART, + /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG1_PR2 */ + .dual.sel = ((0xec / 4) << 5) | 24, + .dual.group = 0, + }, + { + .index = R9A06G032_UART_GROUP_34567, + .name = "uart_group_34567", + .type = K_BITSEL, + .source = 1 + R9A06G032_DIV_P2_PG, + /* R9A06G032_SYSCTRL_REG_PWRCTRL_PG0_0 */ + .dual.sel = ((0x34 / 4) << 5) | 30, + .dual.group = 1, + }, + D_UGATE(CLK_UART0, "clk_uart0", UART_GROUP_012, 0, 0, 0x1b2, 0x1b3, 0x1b4, 0x1b5), + D_UGATE(CLK_UART1, "clk_uart1", UART_GROUP_012, 0, 1, 0x1b6, 0x1b7, 0x1b8, 0x1b9), + D_UGATE(CLK_UART2, "clk_uart2", UART_GROUP_012, 0, 2, 0x1ba, 0x1bb, 0x1bc, 0x1bd), + D_UGATE(CLK_UART3, "clk_uart3", UART_GROUP_34567, 1, 0, 0x760, 0x761, 0x762, 0x763), + D_UGATE(CLK_UART4, "clk_uart4", UART_GROUP_34567, 1, 1, 0x764, 0x765, 0x766, 0x767), + D_UGATE(CLK_UART5, "clk_uart5", UART_GROUP_34567, 1, 2, 0x768, 0x769, 0x76a, 0x76b), + D_UGATE(CLK_UART6, "clk_uart6", UART_GROUP_34567, 1, 3, 0x76c, 0x76d, 0x76e, 0x76f), + D_UGATE(CLK_UART7, "clk_uart7", UART_GROUP_34567, 1, 4, 0x770, 0x771, 0x772, 0x773), +}; + +struct r9a06g032_priv { + struct clk_onecell_data data; + spinlock_t lock; /* protects concurent access to gates */ + void __iomem *reg; +}; + +/* register/bit pairs are encoded as an uint16_t */ +static void +clk_rdesc_set(struct r9a06g032_priv *clocks, + u16 one, unsigned int on) +{ + u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); + u32 val = readl(reg); + + val = (val & ~(1U << (one & 0x1f))) | ((!!on) << (one & 0x1f)); + writel(val, reg); +} + +static int +clk_rdesc_get(struct r9a06g032_priv *clocks, + uint16_t one) +{ + u32 __iomem *reg = clocks->reg + (4 * (one >> 5)); + u32 val = readl(reg); + + return !!(val & (1U << (one & 0x1f))); +} + +/* + * This implements the R9A09G032 clock gate 'driver'. We cannot use the system's + * clock gate framework as the gates on the R9A09G032 have a special enabling + * sequence, therefore we use this little proxy. + */ +struct r9a06g032_clk_gate { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + + struct r9a06g032_gate gate; +}; + +#define to_r9a06g032_gate(_hw) container_of(_hw, struct r9a06g032_clk_gate, hw) + +static void +r9a06g032_clk_gate_set(struct r9a06g032_priv *clocks, + struct r9a06g032_gate *g, int on) +{ + unsigned long flags; + + WARN_ON(!g->gate); + + spin_lock_irqsave(&clocks->lock, flags); + clk_rdesc_set(clocks, g->gate, on); + /* De-assert reset */ + if (g->reset) + clk_rdesc_set(clocks, g->reset, 1); + spin_unlock_irqrestore(&clocks->lock, flags); + + /* Hardware manual recommends 5us delay after enabling clock & reset */ + udelay(5); + + /* If the peripheral is memory mapped (i.e. an AXI slave), there is an + * associated SLVRDY bit in the System Controller that needs to be set + * so that the FlexWAY bus fabric passes on the read/write requests. + */ + if (g->ready || g->midle) { + spin_lock_irqsave(&clocks->lock, flags); + if (g->ready) + clk_rdesc_set(clocks, g->ready, on); + /* Clear 'Master Idle Request' bit */ + if (g->midle) + clk_rdesc_set(clocks, g->midle, !on); + spin_unlock_irqrestore(&clocks->lock, flags); + } + /* Note: We don't wait for FlexWAY Socket Connection signal */ +} + +static int r9a06g032_clk_gate_enable(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + r9a06g032_clk_gate_set(g->clocks, &g->gate, 1); + return 0; +} + +static void r9a06g032_clk_gate_disable(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + r9a06g032_clk_gate_set(g->clocks, &g->gate, 0); +} + +static int r9a06g032_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct r9a06g032_clk_gate *g = to_r9a06g032_gate(hw); + + /* if clock is in reset, the gate might be on, and still not 'be' on */ + if (g->gate.reset && !clk_rdesc_get(g->clocks, g->gate.reset)) + return 0; + + return clk_rdesc_get(g->clocks, g->gate.gate); +} + +static const struct clk_ops r9a06g032_clk_gate_ops = { + .enable = r9a06g032_clk_gate_enable, + .disable = r9a06g032_clk_gate_disable, + .is_enabled = r9a06g032_clk_gate_is_enabled, +}; + +static struct clk * +r9a06g032_register_gate(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct clk *clk; + struct r9a06g032_clk_gate *g; + struct clk_init_data init; + + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + + init.name = desc->name; + init.ops = &r9a06g032_clk_gate_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + g->clocks = clocks; + g->index = desc->index; + g->gate = desc->gate; + g->hw.init = &init; + + /* + * important here, some clocks are already in use by the CM3, we + * have to assume they are not Linux's to play with and try to disable + * at the end of the boot! + */ + if (r9a06g032_clk_gate_is_enabled(&g->hw)) { + init.flags |= CLK_IS_CRITICAL; + pr_debug("%s was enabled, making read-only\n", desc->name); + } + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +struct r9a06g032_clk_div { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 reg; + u16 min, max; + u8 table_size; + u16 table[8]; /* we know there are no more than 8 */ +}; + +#define to_r9a06g032_div(_hw) \ + container_of(_hw, struct r9a06g032_clk_div, hw) + +static unsigned long +r9a06g032_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); + u32 div = readl(reg); + + if (div < clk->min) + div = clk->min; + else if (div > clk->max) + div = clk->max; + return DIV_ROUND_UP(parent_rate, div); +} + +/* + * Attempts to find a value that is in range of min,max, + * and if a table of set dividers was specified for this + * register, try to find the fixed divider that is the closest + * to the target frequency + */ +static long +r9a06g032_div_clamp_div(struct r9a06g032_clk_div *clk, + unsigned long rate, unsigned long prate) +{ + /* + 1 to cope with rates that have the remainder dropped */ + u32 div = DIV_ROUND_UP(prate, rate + 1); + int i; + + if (div <= clk->min) + return clk->min; + if (div >= clk->max) + return clk->max; + + for (i = 0; clk->table_size && i < clk->table_size - 1; i++) { + if (div >= clk->table[i] && div <= clk->table[i + 1]) { + unsigned long m = rate - + DIV_ROUND_UP(prate, clk->table[i]); + unsigned long p = + DIV_ROUND_UP(prate, clk->table[i + 1]) - + rate; + /* + * select the divider that generates + * the value closest to the ideal frequency + */ + div = p >= m ? clk->table[i] : clk->table[i + 1]; + return div; + } + } + return div; +} + +static long +r9a06g032_div_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *prate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + u32 div = DIV_ROUND_UP(*prate, rate); + + pr_devel("%s %pC %ld (prate %ld) (wanted div %u)\n", __func__, + hw->clk, rate, *prate, div); + pr_devel(" min %d (%ld) max %d (%ld)\n", + clk->min, DIV_ROUND_UP(*prate, clk->min), + clk->max, DIV_ROUND_UP(*prate, clk->max)); + + div = r9a06g032_div_clamp_div(clk, rate, *prate); + /* + * this is a hack. Currently the serial driver asks for a clock rate + * that is 16 times the baud rate -- and that is wildly outside the + * range of the UART divider, somehow there is no provision for that + * case of 'let the divider as is if outside range'. + * The serial driver *shouldn't* play with these clocks anyway, there's + * several uarts attached to this divider, and changing this impacts + * everyone. + */ + if (clk->index == R9A06G032_DIV_UART) { + pr_devel("%s div uart hack!\n", __func__); + return clk_get_rate(hw->clk); + } + pr_devel("%s %pC %ld / %u = %ld\n", __func__, hw->clk, + *prate, div, DIV_ROUND_UP(*prate, div)); + return DIV_ROUND_UP(*prate, div); +} + +static int +r9a06g032_div_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct r9a06g032_clk_div *clk = to_r9a06g032_div(hw); + /* + 1 to cope with rates that have the remainder dropped */ + u32 div = DIV_ROUND_UP(parent_rate, rate + 1); + u32 __iomem *reg = clk->clocks->reg + (4 * clk->reg); + + pr_devel("%s %pC rate %ld parent %ld div %d\n", __func__, hw->clk, + rate, parent_rate, div); + + /* + * Need to write the bit 31 with the divider value to + * latch it. Technically we should wait until it has been + * cleared too. + * TODO: Find whether this callback is sleepable, in case + * the hardware /does/ require some sort of spinloop here. + */ + writel(div | BIT(31), reg); + + return 0; +} + +static const struct clk_ops r9a06g032_clk_div_ops = { + .recalc_rate = r9a06g032_div_recalc_rate, + .round_rate = r9a06g032_div_round_rate, + .set_rate = r9a06g032_div_set_rate, +}; + +static struct clk * +r9a06g032_register_div(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct r9a06g032_clk_div *div; + struct clk *clk; + struct clk_init_data init; + unsigned int i; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) + return NULL; + + init.name = desc->name; + init.ops = &r9a06g032_clk_div_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + div->clocks = clocks; + div->index = desc->index; + div->reg = desc->reg; + div->hw.init = &init; + div->min = desc->div_min; + div->max = desc->div_max; + /* populate (optional) divider table fixed values */ + for (i = 0; i < ARRAY_SIZE(div->table) && + i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) { + div->table[div->table_size++] = desc->div_table[i]; + } + + clk = clk_register(NULL, &div->hw); + if (IS_ERR(clk)) { + kfree(div); + return NULL; + } + return clk; +} + +/* + * This clock provider handles the case of the R9A06G032 where you have + * peripherals that have two potential clock source and two gates, one for + * each of the clock source - the used clock source (for all sub clocks) + * is selected by a single bit. + * That single bit affects all sub-clocks, and therefore needs to change the + * active gate (and turn the others off) and force a recalculation of the rates. + * + * This implements two clock providers, one 'bitselect' that + * handles the switch between both parents, and another 'dualgate' + * that knows which gate to poke at, depending on the parent's bit position. + */ +struct r9a06g032_clk_bitsel { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 selector; /* selector register + bit */ +}; + +#define to_clk_bitselect(_hw) \ + container_of(_hw, struct r9a06g032_clk_bitsel, hw) + +static u8 r9a06g032_clk_mux_get_parent(struct clk_hw *hw) +{ + struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); + + return clk_rdesc_get(set->clocks, set->selector); +} + +static int r9a06g032_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct r9a06g032_clk_bitsel *set = to_clk_bitselect(hw); + + /* a single bit in the register selects one of two parent clocks */ + clk_rdesc_set(set->clocks, set->selector, !!index); + + return 0; +} + +static const struct clk_ops clk_bitselect_ops = { + .get_parent = r9a06g032_clk_mux_get_parent, + .set_parent = r9a06g032_clk_mux_set_parent, +}; + +static struct clk * +r9a06g032_register_bitsel(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc) +{ + struct clk *clk; + struct r9a06g032_clk_bitsel *g; + struct clk_init_data init; + const char *names[2]; + + /* allocate the gate */ + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + + names[0] = parent_name; + names[1] = "clk_pll_usb"; + + init.name = desc->name; + init.ops = &clk_bitselect_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = names; + init.num_parents = 2; + + g->clocks = clocks; + g->index = desc->index; + g->selector = desc->dual.sel; + g->hw.init = &init; + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +struct r9a06g032_clk_dualgate { + struct clk_hw hw; + struct r9a06g032_priv *clocks; + u16 index; + u16 selector; /* selector register + bit */ + struct r9a06g032_gate gate[2]; +}; + +#define to_clk_dualgate(_hw) \ + container_of(_hw, struct r9a06g032_clk_dualgate, hw) + +static int +r9a06g032_clk_dualgate_setenable(struct r9a06g032_clk_dualgate *g, int enable) +{ + u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); + + /* we always turn off the 'other' gate, regardless */ + r9a06g032_clk_gate_set(g->clocks, &g->gate[!sel_bit], 0); + r9a06g032_clk_gate_set(g->clocks, &g->gate[sel_bit], enable); + + return 0; +} + +static int r9a06g032_clk_dualgate_enable(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); + + r9a06g032_clk_dualgate_setenable(gate, 1); + + return 0; +} + +static void r9a06g032_clk_dualgate_disable(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *gate = to_clk_dualgate(hw); + + r9a06g032_clk_dualgate_setenable(gate, 0); +} + +static int r9a06g032_clk_dualgate_is_enabled(struct clk_hw *hw) +{ + struct r9a06g032_clk_dualgate *g = to_clk_dualgate(hw); + u8 sel_bit = clk_rdesc_get(g->clocks, g->selector); + + return clk_rdesc_get(g->clocks, g->gate[sel_bit].gate); +} + +static const struct clk_ops r9a06g032_clk_dualgate_ops = { + .enable = r9a06g032_clk_dualgate_enable, + .disable = r9a06g032_clk_dualgate_disable, + .is_enabled = r9a06g032_clk_dualgate_is_enabled, +}; + +static struct clk * +r9a06g032_register_dualgate(struct r9a06g032_priv *clocks, + const char *parent_name, + const struct r9a06g032_clkdesc *desc, + uint16_t sel) +{ + struct r9a06g032_clk_dualgate *g; + struct clk *clk; + struct clk_init_data init; + + /* allocate the gate */ + g = kzalloc(sizeof(*g), GFP_KERNEL); + if (!g) + return NULL; + g->clocks = clocks; + g->index = desc->index; + g->selector = sel; + g->gate[0].gate = desc->dual.g1; + g->gate[0].reset = desc->dual.r1; + g->gate[1].gate = desc->dual.g2; + g->gate[1].reset = desc->dual.r2; + + init.name = desc->name; + init.ops = &r9a06g032_clk_dualgate_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + g->hw.init = &init; + /* + * important here, some clocks are already in use by the CM3, we + * have to assume they are not Linux's to play with and try to disable + * at the end of the boot! + */ + if (r9a06g032_clk_dualgate_is_enabled(&g->hw)) { + init.flags |= CLK_IS_CRITICAL; + pr_debug("%s was enabled, making read-only\n", desc->name); + } + + clk = clk_register(NULL, &g->hw); + if (IS_ERR(clk)) { + kfree(g); + return NULL; + } + return clk; +} + +static void r9a06g032_clocks_del_clk_provider(void *data) +{ + of_clk_del_provider(data); +} + +static int __init r9a06g032_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct r9a06g032_priv *clocks; + struct clk **clks; + struct clk *mclk; + unsigned int i; + u16 uart_group_sel[2]; + int error; + + clocks = devm_kzalloc(dev, sizeof(*clocks), GFP_KERNEL); + clks = devm_kcalloc(dev, R9A06G032_CLOCK_COUNT, sizeof(struct clk *), + GFP_KERNEL); + if (!clocks || !clks) + return -ENOMEM; + + spin_lock_init(&clocks->lock); + + clocks->data.clks = clks; + clocks->data.clk_num = R9A06G032_CLOCK_COUNT; + + mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(mclk)) + return PTR_ERR(mclk); + + clocks->reg = of_iomap(np, 0); + if (WARN_ON(!clocks->reg)) + return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(r9a06g032_clocks); ++i) { + const struct r9a06g032_clkdesc *d = &r9a06g032_clocks[i]; + const char *parent_name = d->source ? + __clk_get_name(clocks->data.clks[d->source - 1]) : + __clk_get_name(mclk); + struct clk *clk = NULL; + + switch (d->type) { + case K_FFC: + clk = clk_register_fixed_factor(NULL, d->name, + parent_name, 0, + d->mul, d->div); + break; + case K_GATE: + clk = r9a06g032_register_gate(clocks, parent_name, d); + break; + case K_DIV: + clk = r9a06g032_register_div(clocks, parent_name, d); + break; + case K_BITSEL: + /* keep that selector register around */ + uart_group_sel[d->dual.group] = d->dual.sel; + clk = r9a06g032_register_bitsel(clocks, parent_name, d); + break; + case K_DUALGATE: + clk = r9a06g032_register_dualgate(clocks, parent_name, + d, + uart_group_sel[d->dual.group]); + break; + } + clocks->data.clks[d->index] = clk; + } + error = of_clk_add_provider(np, of_clk_src_onecell_get, &clocks->data); + if (error) + return error; + + return devm_add_action_or_reset(dev, + r9a06g032_clocks_del_clk_provider, np); +} + +static const struct of_device_id r9a06g032_match[] = { + { .compatible = "renesas,r9a06g032-sysctrl" }, + { } +}; + +static struct platform_driver r9a06g032_clock_driver = { + .driver = { + .name = "renesas,r9a06g032-sysctrl", + .of_match_table = r9a06g032_match, + }, +}; + +static int __init r9a06g032_clocks_init(void) +{ + return platform_driver_probe(&r9a06g032_clock_driver, + r9a06g032_clocks_probe); +} + +subsys_initcall(r9a06g032_clocks_init); diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 72714633e39c..5b238fc314ac 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -28,7 +28,7 @@ static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"}; static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"}; static const char * const emac_ptp_free_mux[] = {"peri_emac_ptp_clk", "boot_clk"}; static const char * const gpio_db_free_mux[] = {"peri_gpio_db_clk", "boot_clk"}; -static const char * const sdmmc_free_mux[] = {"peri_sdmmc_clk", "boot_clk"}; +static const char * const sdmmc_free_mux[] = {"main_sdmmc_clk", "boot_clk"}; static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk"}; static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"}; static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",}; @@ -37,6 +37,11 @@ static const char * const s2f_usr0_mux[] = {"f2s_free_clk", "boot_clk"}; static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"}; static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"}; +static const char * const mpu_free_mux[] = {"main_mpu_base_clk", + "peri_mpu_base_clk", + "osc1", "cb_intosc_hs_div2_clk", + "f2s_free_clk"}; + /* clocks in AO (always on) controller */ static const struct stratix10_pll_clock s10_pll_clks[] = { { STRATIX10_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0, @@ -57,7 +62,7 @@ static const struct stratix10_perip_c_clock s10_main_perip_c_clks[] = { }; static const struct stratix10_perip_cnt_clock s10_main_perip_cnt_clks[] = { - { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, cntr_mux, ARRAY_SIZE(cntr_mux), + { STRATIX10_MPU_FREE_CLK, "mpu_free_clk", NULL, mpu_free_mux, ARRAY_SIZE(mpu_free_mux), 0, 0x48, 0, 0, 0}, { STRATIX10_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux), 0, 0x4C, 0, 0, 0}, diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 16e0aee14773..58874c1bbf5e 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -194,6 +194,7 @@ static const struct clk_div_table mc_div_table[] = { struct clk *tegra_clk_register_mc(const char *name, const char *parent_name, void __iomem *reg, spinlock_t *lock) { - return clk_register_divider_table(NULL, name, parent_name, 0, reg, - 16, 1, 0, mc_div_table, lock); + return clk_register_divider_table(NULL, name, parent_name, + CLK_IS_CRITICAL, reg, 16, 1, 0, + mc_div_table, lock); } diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 5234acd30e89..0621a3a82ea6 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -132,7 +132,7 @@ static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) timing = tegra->timings + i; if (timing->rate > req->max_rate) { - i = min(i, 1); + i = max(i, 1); req->rate = tegra->timings[i - 1].rate; return 0; } diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 0c69c7970950..b6cf28ca2ed2 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1267,7 +1267,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, - { TEGRA124_CLK_VDE, TEGRA124_CLK_CLK_MAX, 600000000, 0 }, + { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_C3, 600000000, 0 }, { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, @@ -1290,6 +1290,7 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1 }, { TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1 }, { TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0 }, + { TEGRA124_CLK_VIC03, TEGRA124_CLK_PLL_C3, 0, 0 }, /* must be the last entry */ { TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 }, }; diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h index 44761849fcbe..f43738607d77 100644 --- a/include/dt-bindings/clock/aspeed-clock.h +++ b/include/dt-bindings/clock/aspeed-clock.h @@ -25,7 +25,7 @@ #define ASPEED_CLK_GATE_RSACLK 19 #define ASPEED_CLK_GATE_UART3CLK 20 #define ASPEED_CLK_GATE_UART4CLK 21 -#define ASPEED_CLK_GATE_SDCLKCLK 22 +#define ASPEED_CLK_GATE_SDCLK 22 #define ASPEED_CLK_GATE_LHCCLK 23 #define ASPEED_CLK_HPLL 24 #define ASPEED_CLK_AHB 25 diff --git a/include/dt-bindings/clock/imx6sll-clock.h b/include/dt-bindings/clock/imx6sll-clock.h index 151111e68f4f..1036475f997d 100644 --- a/include/dt-bindings/clock/imx6sll-clock.h +++ b/include/dt-bindings/clock/imx6sll-clock.h @@ -197,6 +197,13 @@ #define IMX6SLL_CLK_EXTERN_AUDIO_PODF 171 #define IMX6SLL_CLK_EXTERN_AUDIO 172 -#define IMX6SLL_CLK_END 173 +#define IMX6SLL_CLK_GPIO1 173 +#define IMX6SLL_CLK_GPIO2 174 +#define IMX6SLL_CLK_GPIO3 175 +#define IMX6SLL_CLK_GPIO4 176 +#define IMX6SLL_CLK_GPIO5 177 +#define IMX6SLL_CLK_GPIO6 178 + +#define IMX6SLL_CLK_END 179 #endif /* __DT_BINDINGS_CLOCK_IMX6SLL_H */ diff --git a/include/dt-bindings/clock/imx6ul-clock.h b/include/dt-bindings/clock/imx6ul-clock.h index 9564597cbfac..f8e0476a3a0e 100644 --- a/include/dt-bindings/clock/imx6ul-clock.h +++ b/include/dt-bindings/clock/imx6ul-clock.h @@ -235,27 +235,31 @@ #define IMX6UL_CLK_CSI_PODF 222 #define IMX6UL_CLK_PLL3_120M 223 #define IMX6UL_CLK_KPP 224 -#define IMX6UL_CLK_CKO1_SEL 225 -#define IMX6UL_CLK_CKO1_PODF 226 -#define IMX6UL_CLK_CKO1 227 -#define IMX6UL_CLK_CKO2_SEL 228 -#define IMX6UL_CLK_CKO2_PODF 229 -#define IMX6UL_CLK_CKO2 230 -#define IMX6UL_CLK_CKO 231 +#define IMX6ULL_CLK_ESAI_PRED 225 +#define IMX6ULL_CLK_ESAI_PODF 226 +#define IMX6ULL_CLK_ESAI_EXTAL 227 +#define IMX6ULL_CLK_ESAI_MEM 228 +#define IMX6ULL_CLK_ESAI_IPG 229 +#define IMX6ULL_CLK_DCP_CLK 230 +#define IMX6ULL_CLK_EPDC_PRE_SEL 231 +#define IMX6ULL_CLK_EPDC_SEL 232 +#define IMX6ULL_CLK_EPDC_PODF 233 +#define IMX6ULL_CLK_EPDC_ACLK 234 +#define IMX6ULL_CLK_EPDC_PIX 235 +#define IMX6ULL_CLK_ESAI_SEL 236 +#define IMX6UL_CLK_CKO1_SEL 237 +#define IMX6UL_CLK_CKO1_PODF 238 +#define IMX6UL_CLK_CKO1 239 +#define IMX6UL_CLK_CKO2_SEL 240 +#define IMX6UL_CLK_CKO2_PODF 241 +#define IMX6UL_CLK_CKO2 242 +#define IMX6UL_CLK_CKO 243 +#define IMX6UL_CLK_GPIO1 244 +#define IMX6UL_CLK_GPIO2 245 +#define IMX6UL_CLK_GPIO3 246 +#define IMX6UL_CLK_GPIO4 247 +#define IMX6UL_CLK_GPIO5 248 -/* For i.MX6ULL */ -#define IMX6ULL_CLK_ESAI_PRED 232 -#define IMX6ULL_CLK_ESAI_PODF 233 -#define IMX6ULL_CLK_ESAI_EXTAL 234 -#define IMX6ULL_CLK_ESAI_MEM 235 -#define IMX6ULL_CLK_ESAI_IPG 236 -#define IMX6ULL_CLK_DCP_CLK 237 -#define IMX6ULL_CLK_EPDC_PRE_SEL 238 -#define IMX6ULL_CLK_EPDC_SEL 239 -#define IMX6ULL_CLK_EPDC_PODF 240 -#define IMX6ULL_CLK_EPDC_ACLK 241 -#define IMX6ULL_CLK_EPDC_PIX 242 -#define IMX6ULL_CLK_ESAI_SEL 243 -#define IMX6UL_CLK_END 244 +#define IMX6UL_CLK_END 249 #endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */ diff --git a/include/dt-bindings/clock/maxim,max9485.h b/include/dt-bindings/clock/maxim,max9485.h new file mode 100644 index 000000000000..185b09ce1869 --- /dev/null +++ b/include/dt-bindings/clock/maxim,max9485.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DT_BINDINGS_MAX9485_CLK_H +#define __DT_BINDINGS_MAX9485_CLK_H + +#define MAX9485_MCLKOUT 0 +#define MAX9485_CLKOUT 1 +#define MAX9485_CLKOUT1 2 +#define MAX9485_CLKOUT2 3 + +#endif /* __DT_BINDINGS_MAX9485_CLK_H */ diff --git a/include/dt-bindings/clock/pxa-clock.h b/include/dt-bindings/clock/pxa-clock.h index e65803b1dc7e..0b0fd2b01538 100644 --- a/include/dt-bindings/clock/pxa-clock.h +++ b/include/dt-bindings/clock/pxa-clock.h @@ -72,6 +72,7 @@ #define CLK_USIM 58 #define CLK_USIM1 59 #define CLK_USMI0 60 -#define CLK_MAX 61 +#define CLK_OSC32k768 61 +#define CLK_MAX 62 #endif diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index aca61264f12c..f96fc2dbf60e 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -192,6 +192,8 @@ #define GCC_VS_CTRL_CLK_SRC 182 #define GCC_VSENSOR_CLK_SRC 183 #define GPLL4 184 +#define GCC_CPUSS_DVM_BUS_CLK 185 +#define GCC_CPUSS_GNOC_CLK 186 /* GCC Resets */ #define GCC_MMSS_BCR 0 diff --git a/include/dt-bindings/clock/r9a06g032-sysctrl.h b/include/dt-bindings/clock/r9a06g032-sysctrl.h new file mode 100644 index 000000000000..90c0f3dc1ba1 --- /dev/null +++ b/include/dt-bindings/clock/r9a06g032-sysctrl.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R9A06G032 sysctrl IDs + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> + */ + +#ifndef __DT_BINDINGS_R9A06G032_SYSCTRL_H__ +#define __DT_BINDINGS_R9A06G032_SYSCTRL_H__ + +#define R9A06G032_CLK_PLL_USB 1 +#define R9A06G032_CLK_48 1 /* AKA CLK_PLL_USB */ +#define R9A06G032_MSEBIS_CLK 3 /* AKA CLKOUT_D16 */ +#define R9A06G032_MSEBIM_CLK 3 /* AKA CLKOUT_D16 */ +#define R9A06G032_CLK_DDRPHY_PLLCLK 5 /* AKA CLKOUT_D1OR2 */ +#define R9A06G032_CLK50 6 /* AKA CLKOUT_D20 */ +#define R9A06G032_CLK25 7 /* AKA CLKOUT_D40 */ +#define R9A06G032_CLK125 9 /* AKA CLKOUT_D8 */ +#define R9A06G032_CLK_P5_PG1 17 /* AKA DIV_P5_PG */ +#define R9A06G032_CLK_REF_SYNC 21 /* AKA DIV_REF_SYNC */ +#define R9A06G032_CLK_25_PG4 26 +#define R9A06G032_CLK_25_PG5 27 +#define R9A06G032_CLK_25_PG6 28 +#define R9A06G032_CLK_25_PG7 29 +#define R9A06G032_CLK_25_PG8 30 +#define R9A06G032_CLK_ADC 31 +#define R9A06G032_CLK_ECAT100 32 +#define R9A06G032_CLK_HSR100 33 +#define R9A06G032_CLK_I2C0 34 +#define R9A06G032_CLK_I2C1 35 +#define R9A06G032_CLK_MII_REF 36 +#define R9A06G032_CLK_NAND 37 +#define R9A06G032_CLK_NOUSBP2_PG6 38 +#define R9A06G032_CLK_P1_PG2 39 +#define R9A06G032_CLK_P1_PG3 40 +#define R9A06G032_CLK_P1_PG4 41 +#define R9A06G032_CLK_P4_PG3 42 +#define R9A06G032_CLK_P4_PG4 43 +#define R9A06G032_CLK_P6_PG1 44 +#define R9A06G032_CLK_P6_PG2 45 +#define R9A06G032_CLK_P6_PG3 46 +#define R9A06G032_CLK_P6_PG4 47 +#define R9A06G032_CLK_PCI_USB 48 +#define R9A06G032_CLK_QSPI0 49 +#define R9A06G032_CLK_QSPI1 50 +#define R9A06G032_CLK_RGMII_REF 51 +#define R9A06G032_CLK_RMII_REF 52 +#define R9A06G032_CLK_SDIO0 53 +#define R9A06G032_CLK_SDIO1 54 +#define R9A06G032_CLK_SERCOS100 55 +#define R9A06G032_CLK_SLCD 56 +#define R9A06G032_CLK_SPI0 57 +#define R9A06G032_CLK_SPI1 58 +#define R9A06G032_CLK_SPI2 59 +#define R9A06G032_CLK_SPI3 60 +#define R9A06G032_CLK_SPI4 61 +#define R9A06G032_CLK_SPI5 62 +#define R9A06G032_CLK_SWITCH 63 +#define R9A06G032_HCLK_ECAT125 65 +#define R9A06G032_HCLK_PINCONFIG 66 +#define R9A06G032_HCLK_SERCOS 67 +#define R9A06G032_HCLK_SGPIO2 68 +#define R9A06G032_HCLK_SGPIO3 69 +#define R9A06G032_HCLK_SGPIO4 70 +#define R9A06G032_HCLK_TIMER0 71 +#define R9A06G032_HCLK_TIMER1 72 +#define R9A06G032_HCLK_USBF 73 +#define R9A06G032_HCLK_USBH 74 +#define R9A06G032_HCLK_USBPM 75 +#define R9A06G032_CLK_48_PG_F 76 +#define R9A06G032_CLK_48_PG4 77 +#define R9A06G032_CLK_DDRPHY_PCLK 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_FW 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_CRYPTO 81 /* AKA CLK_REF_SYNC_D4 */ +#define R9A06G032_CLK_A7MP 84 /* AKA DIV_CA7 */ +#define R9A06G032_HCLK_CAN0 85 +#define R9A06G032_HCLK_CAN1 86 +#define R9A06G032_HCLK_DELTASIGMA 87 +#define R9A06G032_HCLK_PWMPTO 88 +#define R9A06G032_HCLK_RSV 89 +#define R9A06G032_HCLK_SGPIO0 90 +#define R9A06G032_HCLK_SGPIO1 91 +#define R9A06G032_RTOS_MDC 92 +#define R9A06G032_CLK_CM3 93 +#define R9A06G032_CLK_DDRC 94 +#define R9A06G032_CLK_ECAT25 95 +#define R9A06G032_CLK_HSR50 96 +#define R9A06G032_CLK_HW_RTOS 97 +#define R9A06G032_CLK_SERCOS50 98 +#define R9A06G032_HCLK_ADC 99 +#define R9A06G032_HCLK_CM3 100 +#define R9A06G032_HCLK_CRYPTO_EIP150 101 +#define R9A06G032_HCLK_CRYPTO_EIP93 102 +#define R9A06G032_HCLK_DDRC 103 +#define R9A06G032_HCLK_DMA0 104 +#define R9A06G032_HCLK_DMA1 105 +#define R9A06G032_HCLK_GMAC0 106 +#define R9A06G032_HCLK_GMAC1 107 +#define R9A06G032_HCLK_GPIO0 108 +#define R9A06G032_HCLK_GPIO1 109 +#define R9A06G032_HCLK_GPIO2 110 +#define R9A06G032_HCLK_HSR 111 +#define R9A06G032_HCLK_I2C0 112 +#define R9A06G032_HCLK_I2C1 113 +#define R9A06G032_HCLK_LCD 114 +#define R9A06G032_HCLK_MSEBI_M 115 +#define R9A06G032_HCLK_MSEBI_S 116 +#define R9A06G032_HCLK_NAND 117 +#define R9A06G032_HCLK_PG_I 118 +#define R9A06G032_HCLK_PG19 119 +#define R9A06G032_HCLK_PG20 120 +#define R9A06G032_HCLK_PG3 121 +#define R9A06G032_HCLK_PG4 122 +#define R9A06G032_HCLK_QSPI0 123 +#define R9A06G032_HCLK_QSPI1 124 +#define R9A06G032_HCLK_ROM 125 +#define R9A06G032_HCLK_RTC 126 +#define R9A06G032_HCLK_SDIO0 127 +#define R9A06G032_HCLK_SDIO1 128 +#define R9A06G032_HCLK_SEMAP 129 +#define R9A06G032_HCLK_SPI0 130 +#define R9A06G032_HCLK_SPI1 131 +#define R9A06G032_HCLK_SPI2 132 +#define R9A06G032_HCLK_SPI3 133 +#define R9A06G032_HCLK_SPI4 134 +#define R9A06G032_HCLK_SPI5 135 +#define R9A06G032_HCLK_SWITCH 136 +#define R9A06G032_HCLK_SWITCH_RG 137 +#define R9A06G032_HCLK_UART0 138 +#define R9A06G032_HCLK_UART1 139 +#define R9A06G032_HCLK_UART2 140 +#define R9A06G032_HCLK_UART3 141 +#define R9A06G032_HCLK_UART4 142 +#define R9A06G032_HCLK_UART5 143 +#define R9A06G032_HCLK_UART6 144 +#define R9A06G032_HCLK_UART7 145 +#define R9A06G032_CLK_UART0 146 +#define R9A06G032_CLK_UART1 147 +#define R9A06G032_CLK_UART2 148 +#define R9A06G032_CLK_UART3 149 +#define R9A06G032_CLK_UART4 150 +#define R9A06G032_CLK_UART5 151 +#define R9A06G032_CLK_UART6 152 +#define R9A06G032_CLK_UART7 153 + +#endif /* __DT_BINDINGS_R9A06G032_SYSCTRL_H__ */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index b7cfa037e593..08b1aa70a38d 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -38,6 +38,8 @@ #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ /* parents need enable during gate/ungate, set rate and re-parent */ #define CLK_OPS_PARENT_ENABLE BIT(12) +/* duty cycle call may be forwarded to the parent clock */ +#define CLK_DUTY_CYCLE_PARENT BIT(13) struct clk; struct clk_hw; @@ -67,6 +69,17 @@ struct clk_rate_request { }; /** + * struct clk_duty - Struture encoding the duty cycle ratio of a clock + * + * @num: Numerator of the duty cycle ratio + * @den: Denominator of the duty cycle ratio + */ +struct clk_duty { + unsigned int num; + unsigned int den; +}; + +/** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers * through the clk_* api. @@ -169,6 +182,15 @@ struct clk_rate_request { * by the second argument. Valid values for degrees are * 0-359. Return 0 on success, otherwise -EERROR. * + * @get_duty_cycle: Queries the hardware to get the current duty cycle ratio + * of a clock. Returned values denominator cannot be 0 and must be + * superior or equal to the numerator. + * + * @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by + * the numerator (2nd argurment) and denominator (3rd argument). + * Argument must be a valid ratio (denominator > 0 + * and >= numerator) Return 0 on success, otherwise -EERROR. + * * @init: Perform platform-specific initialization magic. * This is not not used by any of the basic clock types. * Please consider other ways of solving initialization problems @@ -218,6 +240,10 @@ struct clk_ops { unsigned long parent_accuracy); int (*get_phase)(struct clk_hw *hw); int (*set_phase)(struct clk_hw *hw, int degrees); + int (*get_duty_cycle)(struct clk_hw *hw, + struct clk_duty *duty); + int (*set_duty_cycle)(struct clk_hw *hw, + struct clk_duty *duty); void (*init)(struct clk_hw *hw); void (*debug_init)(struct clk_hw *hw, struct dentry *dentry); }; diff --git a/include/linux/clk.h b/include/linux/clk.h index 0dbd0885b2c2..4f750c481b82 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -142,6 +142,27 @@ int clk_set_phase(struct clk *clk, int degrees); int clk_get_phase(struct clk *clk); /** + * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal + * @clk: clock signal source + * @num: numerator of the duty cycle ratio to be applied + * @den: denominator of the duty cycle ratio to be applied + * + * Adjust the duty cycle of a clock signal by the specified ratio. Returns 0 on + * success, -EERROR otherwise. + */ +int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den); + +/** + * clk_get_duty_cycle - return the duty cycle ratio of a clock signal + * @clk: clock signal source + * @scale: scaling factor to be applied to represent the ratio as an integer + * + * Returns the duty cycle ratio multiplied by the scale provided, otherwise + * returns -EERROR. + */ +int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale); + +/** * clk_is_match - check if two clk's point to the same hardware clock * @p: clk compared against q * @q: clk compared against p @@ -183,6 +204,18 @@ static inline long clk_get_phase(struct clk *clk) return -ENOTSUPP; } +static inline int clk_set_duty_cycle(struct clk *clk, unsigned int num, + unsigned int den) +{ + return -ENOTSUPP; +} + +static inline unsigned int clk_get_scaled_duty_cycle(struct clk *clk, + unsigned int scale) +{ + return 0; +} + static inline bool clk_is_match(const struct clk *p, const struct clk *q) { return p == q; diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h index 2cd449328aee..9004ffff7f32 100644 --- a/include/trace/events/clk.h +++ b/include/trace/events/clk.h @@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete, TP_ARGS(core, phase) ); +DECLARE_EVENT_CLASS(clk_duty_cycle, + + TP_PROTO(struct clk_core *core, struct clk_duty *duty), + + TP_ARGS(core, duty), + + TP_STRUCT__entry( + __string( name, core->name ) + __field( unsigned int, num ) + __field( unsigned int, den ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->num = duty->num; + __entry->den = duty->den; + ), + + TP_printk("%s %u/%u", __get_str(name), (unsigned int)__entry->num, + (unsigned int)__entry->den) +); + +DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle, + + TP_PROTO(struct clk_core *core, struct clk_duty *duty), + + TP_ARGS(core, duty) +); + +DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle_complete, + + TP_PROTO(struct clk_core *core, struct clk_duty *duty), + + TP_ARGS(core, duty) +); + #endif /* _TRACE_CLK_H */ /* This part must be outside protection */ |