in spi-synquacer.c [602:737]
static int synquacer_spi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spi_master *master;
struct synquacer_spi *sspi;
int ret;
int rx_irq, tx_irq;
master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
sspi->dev = &pdev->dev;
init_completion(&sspi->transfer_done);
sspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sspi->regs)) {
ret = PTR_ERR(sspi->regs);
goto put_spi;
}
sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
&master->max_speed_hz); /* for ACPI */
if (dev_of_node(&pdev->dev)) {
if (device_property_match_string(&pdev->dev,
"clock-names", "iHCLK") >= 0) {
sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
} else if (device_property_match_string(&pdev->dev,
"clock-names", "iPCLK") >= 0) {
sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
} else {
dev_err(&pdev->dev, "specified wrong clock source\n");
ret = -EINVAL;
goto put_spi;
}
if (IS_ERR(sspi->clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk),
"clock not found\n");
goto put_spi;
}
ret = clk_prepare_enable(sspi->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock (%d)\n",
ret);
goto put_spi;
}
master->max_speed_hz = clk_get_rate(sspi->clk);
}
if (!master->max_speed_hz) {
dev_err(&pdev->dev, "missing clock source\n");
ret = -EINVAL;
goto disable_clk;
}
master->min_speed_hz = master->max_speed_hz / 254;
sspi->aces = device_property_read_bool(&pdev->dev,
"socionext,set-aces");
sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
rx_irq = platform_get_irq(pdev, 0);
if (rx_irq <= 0) {
ret = rx_irq;
goto disable_clk;
}
snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
dev_name(&pdev->dev));
ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
0, sspi->rx_irq_name, sspi);
if (ret) {
dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
goto disable_clk;
}
tx_irq = platform_get_irq(pdev, 1);
if (tx_irq <= 0) {
ret = tx_irq;
goto disable_clk;
}
snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
dev_name(&pdev->dev));
ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
0, sspi->tx_irq_name, sspi);
if (ret) {
dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
goto disable_clk;
}
master->dev.of_node = np;
master->dev.fwnode = pdev->dev.fwnode;
master->auto_runtime_pm = true;
master->bus_num = pdev->id;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
SPI_TX_QUAD | SPI_RX_QUAD;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
master->set_cs = synquacer_spi_set_cs;
master->transfer_one = synquacer_spi_transfer_one;
ret = synquacer_spi_enable(master);
if (ret)
goto disable_clk;
pm_runtime_set_active(sspi->dev);
pm_runtime_enable(sspi->dev);
ret = devm_spi_register_master(sspi->dev, master);
if (ret)
goto disable_pm;
return 0;
disable_pm:
pm_runtime_disable(sspi->dev);
disable_clk:
clk_disable_unprepare(sspi->clk);
put_spi:
spi_master_put(master);
return ret;
}