On Wed, Aug 19, 2015 at 10:39:16AM +0530, [email protected] wrote:
> +config SPI_XLP
> + tristate "Netlogic XLP SPI controller driver"
> + depends on CPU_XLP
Can we not have an || COMPILE_TEST here? There's no headers included
that look like a problem.
It also looks like you have tab/space damage here.
> +static int xlp_spi_setup(struct spi_device *spi)
> +{
> + struct xlp_spi_priv *xspi;
> + u32 fdiv, cfg;
> + int cs;
> +
> + if (!spi->bits_per_word)
> + spi->bits_per_word = 8;
The core will ensure that bits_per_word is always set, there is no need
to duplicate core functionality.
> + /*
> + * The value of fdiv must be between 4 and 65535.
> + */
> + fdiv = DIV_ROUND_UP(xspi->spi_clk, spi->max_speed_hz);
> + fdiv = fdiv < XLP_SPI_FDIV_MIN ? XLP_SPI_FDIV_MIN : fdiv;
> + fdiv = fdiv > XLP_SPI_FDIV_MAX ? XLP_SPI_FDIV_MAX : fdiv;
Please write if statements using the standard if construct, it's much
better for legibility.
> + while (rxfifo_cnt) {
> + rx_data = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_RXDATA_FIFO);
> + j = 0;
> + nbytes = xspi->rx_len > 4 ? 4 : xspi->rx_len;
This is another (probably more serious) example of the problems with the
ternery operator.
> + txfifo_cnt = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_FIFO_WCNT);
> + txfifo_cnt >>= XLP_SPI_TXFIFO_WCNT_SHIFT;
> + txfifo_cnt &= XLP_SPI_FIFO_WCNT_MASK;
This is a bit surprising - I'd expect a _MASK define to define the mask
for the register field so we'd mask then shift rather than shift then
mask.
> +static irqreturn_t xlp_spi_interrupt(int irq, void *dev_id)
> +{
> + struct xlp_spi_priv *xspi = dev_id;
> + u32 stat;
> +
> + stat = xlp_spi_reg_read(xspi, xspi->cs, XLP_SPI_STATUS);
> + if (xspi->tx_len) {
> + if (stat & XLP_SPI_TX_TH_OV)
> + xlp_spi_fill_txfifo(xspi);
> + if (stat & XLP_SPI_TX_UF)
> + xspi->txerrors++;
> + }
> + if (xspi->rx_len) {
> + if (stat & XLP_SPI_RX_TH_OV)
> + xlp_spi_read_rxfifo(xspi);
> + if (stat & XLP_SPI_RX_OF)
> + xspi->rxerrors++;
We should tell the user about errors more noticably to aid debugging -
I'd expect to see us printing an error message here.
> + }
> + /* ACK all interrupts */
> + xlp_spi_reg_write(xspi, xspi->cs, XLP_SPI_STATUS,
> + (stat & XLP_SPI_STAT_MASK));
This unconditionally acknowledges all interrupts even if we didn't
handle them.
> + if (stat & XLP_SPI_XFR_DONE)
> + complete(&xspi->done);
> +
> + return IRQ_HANDLED;
> +}
We're also unconditionally reporting that we handled an interrupt even
if we didn't which will break if the interrupt is ever shared and
prevent the kernel interrupt subsystem error handling working.
> + xlp_spi_send_cmd(xs, xfer_len, cmd_cont);
> + if (xs->tx_len)
> + xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
> + XLP_SPI_INTR_MASK);
> + else
> + xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN,
> + XLP_SPI_RXINTR_MASK);
So the device is single duplex?
> +static int xlp_spi_transfer_one(struct spi_master *master,
> + struct spi_message *msg)
> +{
This is called transfer_one() but it's actually a transfer_one_message()
operation. Though it looks like we should be able to convert it into a
transfer_one() operation and make greater use of core functionality.
> + if (t->transfer_list.next == &msg->transfers)
> + xspi->cmd_cont = 0;
> + else
> + xspi->cmd_cont = 1;
This is spi_tansfer_is_last() (and should've been using list_is_last()
anyway AFAICT).
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "can't get IOMEM resource\n");
> + return -ENODEV;
> + }
> + xspi->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(xspi->base))
> + return PTR_ERR(xspi->base);
Just pass the resource to devm_ioremap_resource(), it'll handle a lookup
failure for you.
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(&pdev->dev, "Failed to get IRQ\n");
> + return irq;
> + }
Print any error codes you get to help users trying to fix problems.
signature.asc
Description: Digital signature
