static int meson_spicc_clk_init()

in spi-meson-spicc.c [523:655]


static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
{
	struct device *dev = &spicc->pdev->dev;
	struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div;
	struct clk_divider *pow2_div, *enh_div;
	struct clk_mux *mux;
	struct clk_init_data init;
	struct clk *clk;
	struct clk_parent_data parent_data[2];
	char name[64];

	memset(&init, 0, sizeof(init));
	memset(&parent_data, 0, sizeof(parent_data));

	init.parent_data = parent_data;

	/* algorithm for pow2 div: rate = freq / 4 / (2 ^ N) */

	pow2_fixed_div = devm_kzalloc(dev, sizeof(*pow2_fixed_div), GFP_KERNEL);
	if (!pow2_fixed_div)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev));
	init.name = name;
	init.ops = &clk_fixed_factor_ops;
	init.flags = 0;
	if (spicc->data->has_pclk)
		parent_data[0].hw = __clk_get_hw(spicc->pclk);
	else
		parent_data[0].hw = __clk_get_hw(spicc->core);
	init.num_parents = 1;

	pow2_fixed_div->mult = 1,
	pow2_fixed_div->div = 4,
	pow2_fixed_div->hw.init = &init;

	clk = devm_clk_register(dev, &pow2_fixed_div->hw);
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);

	pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL);
	if (!pow2_div)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
	init.name = name;
	init.ops = &clk_divider_ops;
	init.flags = CLK_SET_RATE_PARENT;
	parent_data[0].hw = &pow2_fixed_div->hw;
	init.num_parents = 1;

	pow2_div->shift = 16,
	pow2_div->width = 3,
	pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO,
	pow2_div->reg = spicc->base + SPICC_CONREG;
	pow2_div->hw.init = &init;

	clk = devm_clk_register(dev, &pow2_div->hw);
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);

	if (!spicc->data->has_enhance_clk_div) {
		spicc->clk = clk;
		return 0;
	}

	/* algorithm for enh div: rate = freq / 2 / (N + 1) */

	enh_fixed_div = devm_kzalloc(dev, sizeof(*enh_fixed_div), GFP_KERNEL);
	if (!enh_fixed_div)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev));
	init.name = name;
	init.ops = &clk_fixed_factor_ops;
	init.flags = 0;
	if (spicc->data->has_pclk)
		parent_data[0].hw = __clk_get_hw(spicc->pclk);
	else
		parent_data[0].hw = __clk_get_hw(spicc->core);
	init.num_parents = 1;

	enh_fixed_div->mult = 1,
	enh_fixed_div->div = 2,
	enh_fixed_div->hw.init = &init;

	clk = devm_clk_register(dev, &enh_fixed_div->hw);
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);

	enh_div = devm_kzalloc(dev, sizeof(*enh_div), GFP_KERNEL);
	if (!enh_div)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#enh_div", dev_name(dev));
	init.name = name;
	init.ops = &clk_divider_ops;
	init.flags = CLK_SET_RATE_PARENT;
	parent_data[0].hw = &enh_fixed_div->hw;
	init.num_parents = 1;

	enh_div->shift	= 16,
	enh_div->width	= 8,
	enh_div->reg = spicc->base + SPICC_ENH_CTL0;
	enh_div->hw.init = &init;

	clk = devm_clk_register(dev, &enh_div->hw);
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);

	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
	if (!mux)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
	init.name = name;
	init.ops = &clk_mux_ops;
	parent_data[0].hw = &pow2_div->hw;
	parent_data[1].hw = &enh_div->hw;
	init.num_parents = 2;
	init.flags = CLK_SET_RATE_PARENT;

	mux->mask = 0x1,
	mux->shift = 24,
	mux->reg = spicc->base + SPICC_ENH_CTL0;
	mux->hw.init = &init;

	spicc->clk = devm_clk_register(dev, &mux->hw);
	if (WARN_ON(IS_ERR(spicc->clk)))
		return PTR_ERR(spicc->clk);

	return 0;
}