123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- // Copyright 2020 Cerno
- #include <linux/clk-provider.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/reset-controller.h>
- #include <linux/reset/reset-simple.h>
- #define DVP_HT_RPI_SW_INIT 0x04
- #define DVP_HT_RPI_MISC_CONFIG 0x08
- #define NR_CLOCKS 2
- #define NR_RESETS 6
- struct clk_dvp {
- struct clk_hw_onecell_data *data;
- struct reset_simple_data reset;
- };
- static const struct clk_parent_data clk_dvp_parent = {
- .index = 0,
- };
- static int clk_dvp_probe(struct platform_device *pdev)
- {
- struct clk_hw_onecell_data *data;
- struct clk_dvp *dvp;
- void __iomem *base;
- int ret;
- dvp = devm_kzalloc(&pdev->dev, sizeof(*dvp), GFP_KERNEL);
- if (!dvp)
- return -ENOMEM;
- platform_set_drvdata(pdev, dvp);
- dvp->data = devm_kzalloc(&pdev->dev,
- struct_size(dvp->data, hws, NR_CLOCKS),
- GFP_KERNEL);
- if (!dvp->data)
- return -ENOMEM;
- data = dvp->data;
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
- dvp->reset.rcdev.owner = THIS_MODULE;
- dvp->reset.rcdev.nr_resets = NR_RESETS;
- dvp->reset.rcdev.ops = &reset_simple_ops;
- dvp->reset.rcdev.of_node = pdev->dev.of_node;
- dvp->reset.membase = base + DVP_HT_RPI_SW_INIT;
- spin_lock_init(&dvp->reset.lock);
- ret = devm_reset_controller_register(&pdev->dev, &dvp->reset.rcdev);
- if (ret)
- return ret;
- data->hws[0] = clk_hw_register_gate_parent_data(&pdev->dev,
- "hdmi0-108MHz",
- &clk_dvp_parent, 0,
- base + DVP_HT_RPI_MISC_CONFIG, 3,
- CLK_GATE_SET_TO_DISABLE,
- &dvp->reset.lock);
- if (IS_ERR(data->hws[0]))
- return PTR_ERR(data->hws[0]);
- data->hws[1] = clk_hw_register_gate_parent_data(&pdev->dev,
- "hdmi1-108MHz",
- &clk_dvp_parent, 0,
- base + DVP_HT_RPI_MISC_CONFIG, 4,
- CLK_GATE_SET_TO_DISABLE,
- &dvp->reset.lock);
- if (IS_ERR(data->hws[1])) {
- ret = PTR_ERR(data->hws[1]);
- goto unregister_clk0;
- }
- data->num = NR_CLOCKS;
- ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
- data);
- if (ret)
- goto unregister_clk1;
- return 0;
- unregister_clk1:
- clk_hw_unregister_gate(data->hws[1]);
- unregister_clk0:
- clk_hw_unregister_gate(data->hws[0]);
- return ret;
- };
- static int clk_dvp_remove(struct platform_device *pdev)
- {
- struct clk_dvp *dvp = platform_get_drvdata(pdev);
- struct clk_hw_onecell_data *data = dvp->data;
- clk_hw_unregister_gate(data->hws[1]);
- clk_hw_unregister_gate(data->hws[0]);
- return 0;
- }
- static const struct of_device_id clk_dvp_dt_ids[] = {
- { .compatible = "brcm,brcm2711-dvp", },
- { /* sentinel */ }
- };
- MODULE_DEVICE_TABLE(of, clk_dvp_dt_ids);
- static struct platform_driver clk_dvp_driver = {
- .probe = clk_dvp_probe,
- .remove = clk_dvp_remove,
- .driver = {
- .name = "brcm2711-dvp",
- .of_match_table = clk_dvp_dt_ids,
- },
- };
- module_platform_driver(clk_dvp_driver);
- MODULE_AUTHOR("Maxime Ripard <[email protected]>");
- MODULE_DESCRIPTION("BCM2711 DVP clock driver");
- MODULE_LICENSE("GPL");
|