return &raspberrypi_clk_pllb_arm.hw;
}
+static long raspberrypi_fw_dumb_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /*
+ * The firmware will do the rounding but that isn't part of
+ * the interface with the firmware, so we just do our best
+ * here.
+ */
+ return rate;
+}
+
+static const struct clk_ops raspberrypi_firmware_clk_ops = {
+ .is_prepared = raspberrypi_fw_is_prepared,
+ .recalc_rate = raspberrypi_fw_get_rate,
+ .round_rate = raspberrypi_fw_dumb_round_rate,
+ .set_rate = raspberrypi_fw_set_rate,
+};
+
+static struct clk_hw *raspberrypi_clk_register(struct raspberrypi_clk *rpi,
+ unsigned int parent,
+ unsigned int id)
+{
+ struct raspberrypi_clk_data *data;
+ struct clk_init_data init = {};
+ int ret;
+
+ if (id == RPI_FIRMWARE_ARM_CLK_ID) {
+ struct clk_hw *hw;
+
+ hw = raspberrypi_register_pllb(rpi);
+ if (IS_ERR(hw)) {
+ dev_err(rpi->dev, "Failed to initialize pllb, %ld\n",
+ PTR_ERR(hw));
+ return hw;
+ }
+
+ return raspberrypi_register_pllb_arm(rpi);
+ }
+
+ data = devm_kzalloc(rpi->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+ data->rpi = rpi;
+ data->id = id;
+
+ init.name = devm_kasprintf(rpi->dev, GFP_KERNEL, "fw-clk-%u", id);
+ init.ops = &raspberrypi_firmware_clk_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+
+ data->hw.init = &init;
+
+ ret = devm_clk_hw_register(rpi->dev, &data->hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &data->hw;
+}
+
+static int raspberrypi_discover_clocks(struct raspberrypi_clk *rpi,
+ struct clk_hw_onecell_data *data)
+{
+ struct rpi_firmware_get_clocks_response *clks;
+ int ret;
+
+ clks = devm_kcalloc(rpi->dev, sizeof(*clks), NUM_FW_CLKS, GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ ret = rpi_firmware_property(rpi->firmware, RPI_FIRMWARE_GET_CLOCKS,
+ clks, sizeof(*clks) * NUM_FW_CLKS);
+ if (ret)
+ return ret;
+
+ while (clks->id) {
+ struct clk_hw *hw;
+
+ hw = raspberrypi_clk_register(rpi, clks->parent, clks->id);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ data->hws[clks->id] = hw;
+ data->num = clks->id + 1;
+ clks++;
+ }
+
+ return 0;
+}
+
static int raspberrypi_clk_probe(struct platform_device *pdev)
{
struct clk_hw_onecell_data *clk_data;
struct device *dev = &pdev->dev;
struct rpi_firmware *firmware;
struct raspberrypi_clk *rpi;
- struct clk_hw *hw;
int ret;
firmware_node = of_parse_phandle(dev->of_node, "raspberrypi,firmware", 0);
if (!clk_data)
return -ENOMEM;
- hw = raspberrypi_register_pllb(rpi);
- if (IS_ERR(hw)) {
- dev_err(dev, "Failed to initialize pllb, %ld\n", PTR_ERR(hw));
- return PTR_ERR(hw);
- }
-
- hw = raspberrypi_register_pllb_arm(rpi);
- if (IS_ERR(hw))
- return PTR_ERR(hw);
- clk_data->hws[RPI_FIRMWARE_ARM_CLK_ID] = hw;
- clk_data->num = RPI_FIRMWARE_ARM_CLK_ID + 1;
+ ret = raspberrypi_discover_clocks(rpi, clk_data);
+ if (ret)
+ return ret;
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clk_data);