void enable_FM_mux_clk_aud(struct s610_radio *radio);
void disable_clk_gating(struct s610_radio *radio);
+static int fm_clk_get(struct s610_radio *radio);
+static int fm_clk_prepare(struct s610_radio *radio);
+static int fm_clk_enable(struct s610_radio *radio);
+static void fm_clk_unprepare(struct s610_radio *radio);
+static void fm_clk_disable(struct s610_radio *radio);
+static void fm_clk_put(struct s610_radio *radio);
+
signed int exynos_get_fm_open_status(void);
signed int shared_fm_open_cnt;
ret = -ENOMEM;
goto alloc_err1;
}
-
- clk = devm_clk_get(&pdev->dev, "qch_fm");
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "failed to get clock\n");
- ret = PTR_ERR(clk);
+
+ radio->dev = dev;
+ radio->pdev = pdev;
+ gradio = radio;
+
+ ret = fm_clk_get(radio);
+ if (ret)
goto alloc_err2;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to prepare enable clock\n");
+ fm_clk_prepare(radio);
+ if (ret)
goto alloc_err2;
- }
- ret = clk_enable(clk);
+ fm_clk_enable(radio);
if (ret) {
- dev_err(&pdev->dev, "failed to enable clock\n");
+ fm_clk_unprepare(radio);
goto alloc_err2;
}
- radio->clk = clk;
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
radio->irq = resource->start;
#endif /* RDS_POLLING_ENABLE */
- radio->dev = dev;
- radio->pdev = pdev;
- gradio = radio;
-
#ifdef USE_FM_LNA_ENABLE
elna_gpio = of_get_named_gpio(dnode, "elna_gpio", 0);
if (!gpio_is_valid(elna_gpio)) {
alloc_err3:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- clk_disable(radio->clk);
- clk_unregister(clk);
+
+ fm_clk_disable(radio);
+ fm_clk_unprepare(radio);
alloc_err2:
kfree(radio->low);
struct s610_radio *radio = platform_get_drvdata(pdev);
if (radio) {
- clk_disable(radio->clk);
- clk_unregister(radio->clk);
- clk_put(radio->clk);
+ fm_clk_disable(radio);
+ fm_clk_unprepare(radio);
+ fm_clk_put(radio);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
return 0;
}
-#define AUD_PLL_RATE_HZ_BYPASS (26000000)
-#define AUD_PLL_RATE_HZ_FOR_48000 (1179648040)
-static int fm_radio_clk_enable(struct s610_radio *radio)
+static int fm_clk_get(struct s610_radio *radio)
{
- unsigned long ret = 0;
+ struct device *dev = radio->dev;
+ struct clk *clk;
+ int clk_count;
+ int ret, i;
- if (radio->clk) {
- ret = clk_enable(radio->clk);
- if (ret)
+ clk_count = of_property_count_strings(dev->of_node, "clock-names");
+ if (IS_ERR_VALUE((unsigned long)clk_count)) {
+ dev_err(dev, "invalid clk list in %s node", dev->of_node->name);
+ return -EINVAL;
+ }
+
+ radio->clk_ids = (const char **)devm_kmalloc(dev,
+ (clk_count + 1) * sizeof(const char *),
+ GFP_KERNEL);
+ if (!radio->clk_ids) {
+ dev_err(dev, "failed to alloc for clock ids");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < clk_count; i++) {
+ ret = of_property_read_string_index(dev->of_node, "clock-names",
+ i, &radio->clk_ids[i]);
+ if (ret) {
+ dev_err(dev, "failed to read clocks name %d from %s node\n",
+ i, dev->of_node->name);
return ret;
- } else {
- dev_err(radio->v4l2dev.dev,
- "%s: fm radio clk_enable failed\n", __func__);
- ret = -EIO;
+ }
+ }
+ radio->clk_ids[clk_count] = NULL;
+
+ radio->clocks = (struct clk **) devm_kmalloc(dev,
+ clk_count * sizeof(struct clk *), GFP_KERNEL);
+ if (!radio->clocks) {
+ dev_err(dev, "%s: couldn't alloc\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; radio->clk_ids[i] != NULL; i++) {
+ clk = devm_clk_get(dev, radio->clk_ids[i]);
+ if (IS_ERR_OR_NULL(clk))
+ goto err;
+
+ radio->clocks[i] = clk;
+ }
+ radio->clocks[i] = NULL;
+
+ return 0;
+
+err:
+ dev_err(dev, "couldn't get %s clock\n", radio->clk_ids[i]);
+ return -EINVAL;
+}
+
+static int fm_clk_prepare(struct s610_radio *radio)
+{
+ int i;
+ int ret;
+
+ for (i = 0; radio->clocks[i] != NULL; i++) {
+ ret = clk_prepare(radio->clocks[i]);
+ if (ret)
+ goto err;
}
- dev_info(radio->dev, "FM clock: %lu\n", clk_get_rate(radio->clk));
+ return 0;
+
+err:
+ dev_err(radio->dev, "couldn't prepare clock[%d]\n", i);
+
+ /* roll back */
+ for (i = i - 1; i >= 0; i--)
+ clk_unprepare(radio->clocks[i]);
return ret;
}
-static void fm_radio_clk_disable(struct s610_radio *radio)
+static int fm_clk_enable(struct s610_radio *radio)
{
- if (radio->clk) {
- clk_disable(radio->clk);
- } else {
- dev_err(radio->v4l2dev.dev,
- "%s: fm radio clk_disable failed\n", __func__);
+ int i;
+ int ret;
+
+ for (i = 0; radio->clocks[i] != NULL; i++) {
+ ret = clk_enable(radio->clocks[i]);
+ if (ret)
+ goto err;
+
+ dev_info(radio->dev, "clock %s%t: %lu\n", radio->clk_ids[i], clk_get_rate(radio->clocks[i]));
+
+ if (!strcmp(radio->clk_ids[i], "clk_aud_fm")) {
+ if (clk_get_rate(radio->clocks[i]) != 40000) {
+ ret = clk_set_rate(radio->clocks[i], 40000);
+ if (IS_ERR_VALUE((unsigned long)ret))
+ dev_info(radio->dev,
+ "setting clock clk_aud_fm to 40KHz is failed: %lu\n", ret);
+ dev_info(radio->dev, "FM clock clk_aud_fm: %lu\n",
+ clk_get_rate(radio->clocks[i]));
+ }
+ }
}
+
+ return 0;
+
+err:
+ dev_err(radio->dev, "couldn't enable clock[%d]\n", i);
+
+ /* roll back */
+ for (i = i - 1; i >= 0; i--)
+ clk_disable(radio->clocks[i]);
+
+ return ret;
+}
+
+static void fm_clk_unprepare(struct s610_radio *radio)
+{
+ int i;
+
+ for (i = 0; radio->clocks[i] != NULL; i++)
+ clk_unprepare(radio->clocks[i]);
+}
+
+static void fm_clk_disable(struct s610_radio *radio)
+{
+ int i;
+
+ for (i = 0; radio->clocks[i] != NULL; i++)
+ clk_disable(radio->clocks[i]);
+}
+
+static void fm_clk_put(struct s610_radio *radio)
+{
+ int i;
+
+ for (i = 0; radio->clocks[i] != NULL; i++)
+ clk_put(radio->clocks[i]);
+
}
#ifdef CONFIG_PM
FUNC_ENTRY(radio);
- fm_radio_clk_disable(radio);
+ fm_clk_disable(radio);
return 0;
}
FUNC_ENTRY(radio);
- ret = fm_radio_clk_enable(radio);
- if (ret) {
- dev_err(dev, "%s: clk_enable failed\n", __func__);
- return ret;
- }
+ fm_clk_enable(radio);
return 0;
}