From 2f25528e4edddc6eddd42c8d41c9c9e341c8b9da Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 19 Jun 2019 11:39:25 +0200 Subject: clk: Add clk_bulk_get_optional() function clk_bulk_get_optional() allows to get a group of clocks where one or more is optional. For a not available clock, e.g. not specifed in the clock consumer node in DT, its respective struct clk pointer will be NULL. This allows for operating on a group of returned clocks (struct clk_bulk_data array) with existing clk_bulk* APIs. Signed-off-by: Sylwester Nawrocki Signed-off-by: Stephen Boyd --- include/linux/clk.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'include') diff --git a/include/linux/clk.h b/include/linux/clk.h index f689fc58d7be..1b50e7d1675c 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -332,6 +332,19 @@ int __must_check clk_bulk_get(struct device *dev, int num_clks, */ int __must_check clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks); + +/** + * clk_bulk_get_optional - lookup and obtain a number of references to clock producer + * @dev: device for clock "consumer" + * @num_clks: the number of clk_bulk_data + * @clks: the clk_bulk_data table of consumer + * + * Behaves the same as clk_bulk_get() except where there is no clock producer. + * In this case, instead of returning -ENOENT, the function returns 0 and + * NULL for a clk for which a clock producer could not be determined. + */ +int __must_check clk_bulk_get_optional(struct device *dev, int num_clks, + struct clk_bulk_data *clks); /** * devm_clk_bulk_get - managed get multiple clk consumers * @dev: device for clock "consumer" @@ -718,6 +731,12 @@ static inline int __must_check clk_bulk_get(struct device *dev, int num_clks, return 0; } +static inline int __must_check clk_bulk_get_optional(struct device *dev, + int num_clks, struct clk_bulk_data *clks) +{ + return 0; +} + static inline int __must_check clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks) { -- cgit v1.2.3 From 9bd5ef0bd8743700d9adffb6fbb1baa346575457 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 19 Jun 2019 11:39:26 +0200 Subject: clk: Add devm_clk_bulk_get_optional() function Add managed version of the clk_bulk_get_optional() helper function. Signed-off-by: Sylwester Nawrocki [sboyd@kernel.org: Mark __devm_clk_bulk_get() static] Signed-off-by: Stephen Boyd --- drivers/clk/clk-devres.c | 22 +++++++++++++++++++--- include/linux/clk.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index daa1fc8fba53..be160764911b 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -52,8 +52,8 @@ static void devm_clk_bulk_release(struct device *dev, void *res) clk_bulk_put(devres->num_clks, devres->clks); } -int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, - struct clk_bulk_data *clks) +static int __devm_clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks, bool optional) { struct clk_bulk_devres *devres; int ret; @@ -63,7 +63,10 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, if (!devres) return -ENOMEM; - ret = clk_bulk_get(dev, num_clks, clks); + if (optional) + ret = clk_bulk_get_optional(dev, num_clks, clks); + else + ret = clk_bulk_get(dev, num_clks, clks); if (!ret) { devres->clks = clks; devres->num_clks = num_clks; @@ -74,8 +77,21 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, return ret; } + +int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, + struct clk_bulk_data *clks) +{ + return __devm_clk_bulk_get(dev, num_clks, clks, false); +} EXPORT_SYMBOL_GPL(devm_clk_bulk_get); +int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, + struct clk_bulk_data *clks) +{ + return __devm_clk_bulk_get(dev, num_clks, clks, true); +} +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); + int __must_check devm_clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks) { diff --git a/include/linux/clk.h b/include/linux/clk.h index 1b50e7d1675c..5e7b2dd84965 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -359,6 +359,28 @@ int __must_check clk_bulk_get_optional(struct device *dev, int num_clks, */ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks); +/** + * devm_clk_bulk_get_optional - managed get multiple optional consumer clocks + * @dev: device for clock "consumer" + * @clks: pointer to the clk_bulk_data table of consumer + * + * Behaves the same as devm_clk_bulk_get() except where there is no clock + * producer. In this case, instead of returning -ENOENT, the function returns + * NULL for given clk. It is assumed all clocks in clk_bulk_data are optional. + * + * Returns 0 if all clocks specified in clk_bulk_data table are obtained + * successfully or for any clk there was no clk provider available, otherwise + * returns valid IS_ERR() condition containing errno. + * The implementation uses @dev and @clk_bulk_data.id to determine the + * clock consumer, and thereby the clock producer. + * The clock returned is stored in each @clk_bulk_data.clk field. + * + * Drivers must assume that the clock source is not enabled. + * + * clk_bulk_get should not be called from within interrupt context. + */ +int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, + struct clk_bulk_data *clks); /** * devm_clk_bulk_get_all - managed get multiple clk consumers * @dev: device for clock "consumer" @@ -760,6 +782,12 @@ static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clk return 0; } +static inline int __must_check devm_clk_bulk_get_optional(struct device *dev, + int num_clks, struct clk_bulk_data *clks) +{ + return 0; +} + static inline int __must_check devm_clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks) { -- cgit v1.2.3 From 3b5015c4d834a70233c4419b07375254e4675e0b Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 24 Jun 2019 16:47:10 -0500 Subject: clk: socfpga: stratix10: add additional clocks needed for the NAND IP The nand_clk is actually called the nand_x_clk and the parent is the l4_mp_clk, not the l4_main_clk. The nand_clk is a child of the nand_x_clk and has a fixed divider of 4. The same is true for the nand_ecc_clk. Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-s10.c | 6 +++++- include/dt-bindings/clock/stratix10-clock.h | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 8281dfbf38c2..609dd722675e 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -161,8 +161,12 @@ static const struct stratix10_gate_clock s10_gate_clks[] = { 8, 0, 0, 0, 0, 0, 0}, { STRATIX10_SPI_M_CLK, "spi_m_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, 9, 0, 0, 0, 0, 0, 0}, - { STRATIX10_NAND_CLK, "nand_clk", "l4_main_clk", NULL, 1, 0, 0xA4, + { STRATIX10_NAND_X_CLK, "nand_x_clk", "l4_mp_clk", NULL, 1, 0, 0xA4, 10, 0, 0, 0, 0, 0, 0}, + { STRATIX10_NAND_CLK, "nand_clk", "nand_x_clk", NULL, 1, 0, 0xA4, + 10, 0, 0, 0, 0, 0, 4}, + { STRATIX10_NAND_ECC_CLK, "nand_ecc_clk", "nand_x_clk", NULL, 1, 0, 0xA4, + 10, 0, 0, 0, 0, 0, 4}, }; static int s10_clk_register_c_perip(const struct stratix10_perip_c_clock *clks, diff --git a/include/dt-bindings/clock/stratix10-clock.h b/include/dt-bindings/clock/stratix10-clock.h index 0ac1c90a18bf..08b98e20b7cc 100644 --- a/include/dt-bindings/clock/stratix10-clock.h +++ b/include/dt-bindings/clock/stratix10-clock.h @@ -79,6 +79,8 @@ #define STRATIX10_USB_CLK 59 #define STRATIX10_SPI_M_CLK 60 #define STRATIX10_NAND_CLK 61 -#define STRATIX10_NUM_CLKS 62 +#define STRATIX10_NAND_X_CLK 62 +#define STRATIX10_NAND_ECC_CLK 63 +#define STRATIX10_NUM_CLKS 64 #endif /* __STRATIX10_CLOCK_H */ -- cgit v1.2.3