in busses/i2c-sun6i-p2wi.c [183:314]
static int p2wi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *childnp;
unsigned long parent_clk_freq;
u32 clk_freq = I2C_MAX_STANDARD_MODE_FREQ;
struct p2wi *p2wi;
u32 slave_addr;
int clk_div;
int irq;
int ret;
of_property_read_u32(np, "clock-frequency", &clk_freq);
if (clk_freq > P2WI_MAX_FREQ) {
dev_err(dev,
"required clock-frequency (%u Hz) is too high (max = 6MHz)",
clk_freq);
return -EINVAL;
}
if (of_get_child_count(np) > 1) {
dev_err(dev, "P2WI only supports one slave device\n");
return -EINVAL;
}
p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);
if (!p2wi)
return -ENOMEM;
p2wi->slave_addr = -1;
/*
* Authorize a p2wi node without any children to be able to use an
* i2c-dev from userpace.
* In this case the slave_addr is set to -1 and won't be checked when
* launching a P2WI transfer.
*/
childnp = of_get_next_available_child(np, NULL);
if (childnp) {
ret = of_property_read_u32(childnp, "reg", &slave_addr);
if (ret) {
dev_err(dev, "invalid slave address on node %pOF\n",
childnp);
return -EINVAL;
}
p2wi->slave_addr = slave_addr;
}
p2wi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(p2wi->regs))
return PTR_ERR(p2wi->regs);
strscpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
p2wi->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p2wi->clk)) {
ret = PTR_ERR(p2wi->clk);
dev_err(dev, "failed to retrieve clk: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(p2wi->clk);
if (ret) {
dev_err(dev, "failed to enable clk: %d\n", ret);
return ret;
}
parent_clk_freq = clk_get_rate(p2wi->clk);
p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(p2wi->rstc)) {
ret = PTR_ERR(p2wi->rstc);
dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
goto err_clk_disable;
}
ret = reset_control_deassert(p2wi->rstc);
if (ret) {
dev_err(dev, "failed to deassert reset line: %d\n", ret);
goto err_clk_disable;
}
init_completion(&p2wi->complete);
p2wi->adapter.dev.parent = dev;
p2wi->adapter.algo = &p2wi_algo;
p2wi->adapter.owner = THIS_MODULE;
p2wi->adapter.dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, p2wi);
i2c_set_adapdata(&p2wi->adapter, p2wi);
ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);
if (ret) {
dev_err(dev, "can't register interrupt handler irq%d: %d\n",
irq, ret);
goto err_reset_assert;
}
writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL);
clk_div = parent_clk_freq / clk_freq;
if (!clk_div) {
dev_warn(dev,
"clock-frequency is too high, setting it to %lu Hz\n",
parent_clk_freq);
clk_div = 1;
} else if (clk_div > P2WI_CCR_MAX_CLK_DIV) {
dev_warn(dev,
"clock-frequency is too low, setting it to %lu Hz\n",
parent_clk_freq / P2WI_CCR_MAX_CLK_DIV);
clk_div = P2WI_CCR_MAX_CLK_DIV;
}
writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div),
p2wi->regs + P2WI_CCR);
ret = i2c_add_adapter(&p2wi->adapter);
if (!ret)
return 0;
err_reset_assert:
reset_control_assert(p2wi->rstc);
err_clk_disable:
clk_disable_unprepare(p2wi->clk);
return ret;
}