diff options
Diffstat (limited to 'drivers/clk/clk-max77686.c')
| -rw-r--r-- | drivers/clk/clk-max77686.c | 97 | 
1 files changed, 60 insertions, 37 deletions
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 9f57bc37cd6..3d7e8dd8fd5 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -66,7 +66,7 @@ static void max77686_clk_unprepare(struct clk_hw *hw)  		MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);  } -static int max77686_clk_is_enabled(struct clk_hw *hw) +static int max77686_clk_is_prepared(struct clk_hw *hw)  {  	struct max77686_clk *max77686 = to_max77686_clk(hw);  	int ret; @@ -81,10 +81,17 @@ static int max77686_clk_is_enabled(struct clk_hw *hw)  	return val & max77686->mask;  } +static unsigned long max77686_recalc_rate(struct clk_hw *hw, +					  unsigned long parent_rate) +{ +	return 32768; +} +  static struct clk_ops max77686_clk_ops = {  	.prepare	= max77686_clk_prepare,  	.unprepare	= max77686_clk_unprepare, -	.is_enabled	= max77686_clk_is_enabled, +	.is_prepared	= max77686_clk_is_prepared, +	.recalc_rate	= max77686_recalc_rate,  };  static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { @@ -105,38 +112,38 @@ static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {  	},  }; -static int max77686_clk_register(struct device *dev, +static struct clk *max77686_clk_register(struct device *dev,  				struct max77686_clk *max77686)  {  	struct clk *clk;  	struct clk_hw *hw = &max77686->hw;  	clk = clk_register(dev, hw); -  	if (IS_ERR(clk)) -		return -ENOMEM; +		return clk;  	max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);  	if (!max77686->lookup) -		return -ENOMEM; +		return ERR_PTR(-ENOMEM);  	max77686->lookup->con_id = hw->init->name;  	max77686->lookup->clk = clk;  	clkdev_add(max77686->lookup); -	return 0; +	return clk;  }  static int max77686_clk_probe(struct platform_device *pdev)  {  	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); -	struct max77686_clk **max77686_clks; +	struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM]; +	struct clk **clocks;  	int i, ret; -	max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *) +	clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *)  					* MAX77686_CLKS_NUM, GFP_KERNEL); -	if (!max77686_clks) +	if (!clocks)  		return -ENOMEM;  	for (i = 0; i < MAX77686_CLKS_NUM; i++) { @@ -151,47 +158,63 @@ static int max77686_clk_probe(struct platform_device *pdev)  		max77686_clks[i]->mask = 1 << i;  		max77686_clks[i]->hw.init = &max77686_clks_init[i]; -		ret = max77686_clk_register(&pdev->dev, max77686_clks[i]); +		clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]); +		if (IS_ERR(clocks[i])) { +			ret = PTR_ERR(clocks[i]); +			dev_err(&pdev->dev, "failed to register %s\n", +				max77686_clks[i]->hw.init->name); +			goto err_clocks; +		} +	} + +	platform_set_drvdata(pdev, clocks); + +	if (iodev->dev->of_node) { +		struct clk_onecell_data *of_data; + +		of_data = devm_kzalloc(&pdev->dev, +					sizeof(*of_data), GFP_KERNEL); +		if (!of_data) { +			ret = -ENOMEM; +			goto err_clocks; +		} + +		of_data->clks = clocks; +		of_data->clk_num = MAX77686_CLKS_NUM; +		ret = of_clk_add_provider(iodev->dev->of_node, +					of_clk_src_onecell_get, of_data);  		if (ret) { -			switch (i) { -			case MAX77686_CLK_AP: -				dev_err(&pdev->dev, "Fail to register CLK_AP\n"); -				goto err_clk_ap; -				break; -			case MAX77686_CLK_CP: -				dev_err(&pdev->dev, "Fail to register CLK_CP\n"); -				goto err_clk_cp; -				break; -			case MAX77686_CLK_PMIC: -				dev_err(&pdev->dev, "Fail to register CLK_PMIC\n"); -				goto err_clk_pmic; -			} +			dev_err(&pdev->dev, "failed to register OF clock provider\n"); +			goto err_clocks;  		}  	} -	platform_set_drvdata(pdev, max77686_clks); +	return 0; -	goto out; +err_clocks: +	for (--i; i >= 0; --i) { +		clkdev_drop(max77686_clks[i]->lookup); +		clk_unregister(max77686_clks[i]->hw.clk); +	} -err_clk_pmic: -	clkdev_drop(max77686_clks[MAX77686_CLK_CP]->lookup); -	kfree(max77686_clks[MAX77686_CLK_CP]->hw.clk); -err_clk_cp: -	clkdev_drop(max77686_clks[MAX77686_CLK_AP]->lookup); -	kfree(max77686_clks[MAX77686_CLK_AP]->hw.clk); -err_clk_ap: -out:  	return ret;  }  static int max77686_clk_remove(struct platform_device *pdev)  { -	struct max77686_clk **max77686_clks = platform_get_drvdata(pdev); +	struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); +	struct clk **clocks = platform_get_drvdata(pdev);  	int i; +	if (iodev->dev->of_node) +		of_clk_del_provider(iodev->dev->of_node); +  	for (i = 0; i < MAX77686_CLKS_NUM; i++) { -		clkdev_drop(max77686_clks[i]->lookup); -		kfree(max77686_clks[i]->hw.clk); +		struct clk_hw *hw = __clk_get_hw(clocks[i]); +		struct max77686_clk *max77686 = to_max77686_clk(hw); + +		clkdev_drop(max77686->lookup); +		clk_unregister(clocks[i]);  	}  	return 0;  }  | 
