summaryrefslogtreecommitdiffstats
path: root/drivers/ata/ahci_da850.c
diff options
context:
space:
mode:
authorSerge Semin <Sergey.Semin@baikalelectronics.ru>2022-09-09 21:36:05 +0200
committerDamien Le Moal <damien.lemoal@opensource.wdc.com>2022-09-16 18:39:22 +0200
commite28b3abf8020a884bd3b7758ea8915365af8fadf (patch)
treec70cd32ee99aba3c76d6069051ac2079b4e6efb6 /drivers/ata/ahci_da850.c
parentata: libahci_platform: Convert to using platform devm-ioremap methods (diff)
downloadlinux-e28b3abf8020a884bd3b7758ea8915365af8fadf.tar.xz
linux-e28b3abf8020a884bd3b7758ea8915365af8fadf.zip
ata: libahci_platform: Convert to using devm bulk clocks API
In order to simplify the clock-related code there is a way to convert the current fixed clocks array into using the common bulk clocks kernel API with dynamic set of the clock handlers and device-managed clock-resource tracking. It's a bit tricky due to the complication coming from the requirement to support the platforms (da850, spear13xx) with the non-OF-based clock source, but still doable. Before this modification there are two methods have been used to get the clocks connected to an AHCI device: clk_get() - to get the very first clock in the list and of_clk_get() - to get the rest of them. Basically the platforms with non-OF-based clocks definition could specify only a single reference clock source. The platforms with OF-hw clocks have been luckier and could setup up to AHCI_MAX_CLKS clocks. Such semantic can be retained with using devm_clk_bulk_get_all() to retrieve the clocks defined via the DT firmware and devm_clk_get_optional() otherwise. In both cases using the device-managed version of the methods will cause the automatic resources deallocation on the AHCI device removal event. The only complicated part in the suggested approach is the explicit allocation and initialization of the clk_bulk_data structure instance for the non-OF reference clocks. It's required in order to use the Bulk Clocks API for the both denoted cases of the clocks definition. Note aside with the clock-related code reduction and natural simplification, there are several bonuses the suggested modification provides. First of all the limitation of having no greater than AHCI_MAX_CLKS clocks is now removed, since the devm_clk_bulk_get_all() method will allocate as many reference clocks data descriptors as there are clocks specified for the device. Secondly the clock names are auto-detected. So the LLDD (glue) drivers can make sure that the required clocks are specified just by checking the clock IDs in the clk_bulk_data array. Thirdly using the handy Bulk Clocks kernel API improves the clocks-handling code readability. And the last but not least this modification implements a true optional clocks support to the ahci_platform_get_resources() method. Indeed the previous clocks getting procedure just stopped getting the clocks on any errors (aside from non-critical -EPROBE_DEFER) in a way so the callee wasn't even informed about abnormal loop termination. The new implementation lacks of such problem. The ahci_platform_get_resources() will return an error code if the corresponding clocks getting method ends execution abnormally. Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Diffstat (limited to 'drivers/ata/ahci_da850.c')
-rw-r--r--drivers/ata/ahci_da850.c47
1 files changed, 19 insertions, 28 deletions
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
index 052c28e250aa..dc8a019b8340 100644
--- a/drivers/ata/ahci_da850.c
+++ b/drivers/ata/ahci_da850.c
@@ -163,7 +163,6 @@ static int ahci_da850_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
void __iomem *pwrdn_reg;
struct resource *res;
- struct clk *clk;
u32 mpy;
int rc;
@@ -172,36 +171,28 @@ static int ahci_da850_probe(struct platform_device *pdev)
return PTR_ERR(hpriv);
/*
- * Internally ahci_platform_get_resources() calls clk_get(dev, NULL)
- * when trying to obtain the functional clock. This SATA controller
- * uses two clocks for which we specify two connection ids. If we don't
- * have the functional clock at this point - call clk_get() again with
- * con_id = "fck".
+ * Internally ahci_platform_get_resources() calls the bulk clocks
+ * get method or falls back to using a single clk_get_optional().
+ * This AHCI SATA controller uses two clocks: functional clock
+ * with "fck" connection id and external reference clock with
+ * "refclk" id. If we haven't got all of them re-try the clocks
+ * getting procedure with the explicitly specified ids.
*/
- if (!hpriv->clks[0]) {
- clk = clk_get(dev, "fck");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- hpriv->clks[0] = clk;
- }
-
- /*
- * The second clock used by ahci-da850 is the external REFCLK. If we
- * didn't get it from ahci_platform_get_resources(), let's try to
- * specify the con_id in clk_get().
- */
- if (!hpriv->clks[1]) {
- clk = clk_get(dev, "refclk");
- if (IS_ERR(clk)) {
- dev_err(dev, "unable to obtain the reference clock");
- return -ENODEV;
- }
-
- hpriv->clks[1] = clk;
+ if (hpriv->n_clks < 2) {
+ hpriv->clks = devm_kcalloc(dev, 2, sizeof(*hpriv->clks), GFP_KERNEL);
+ if (!hpriv->clks)
+ return -ENOMEM;
+
+ hpriv->clks[0].id = "fck";
+ hpriv->clks[1].id = "refclk";
+ hpriv->n_clks = 2;
+
+ rc = devm_clk_bulk_get(dev, hpriv->n_clks, hpriv->clks);
+ if (rc)
+ return rc;
}
- mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1]));
+ mpy = ahci_da850_calculate_mpy(clk_get_rate(hpriv->clks[1].clk));
if (mpy == 0) {
dev_err(dev, "invalid REFCLK multiplier value: 0x%x", mpy);
return -EINVAL;