cregit-Linux how code gets into the kernel

Release 4.11 drivers/spi/spi-fsl-spi.c

Directory: drivers/spi
/*
 * Freescale SPI controller driver.
 *
 * Maintainer: Kumar Gala
 *
 * Copyright (C) 2006 Polycom, Inc.
 * Copyright 2010 Freescale Semiconductor, Inc.
 *
 * CPM SPI and QE buffer descriptors mode support:
 * Copyright (c) 2009  MontaVista Software, Inc.
 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * GRLIB support:
 * Copyright (c) 2012 Aeroflex Gaisler AB.
 * Author: Andreas Larsson <andreas@gaisler.com>
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>

#include "spi-fsl-lib.h"
#include "spi-fsl-cpm.h"
#include "spi-fsl-spi.h"


#define TYPE_FSL	0

#define TYPE_GRLIB	1


struct fsl_spi_match_data {
	
int type;
};


static struct fsl_spi_match_data of_fsl_spi_fsl_config = {
	.type = TYPE_FSL,
};


static struct fsl_spi_match_data of_fsl_spi_grlib_config = {
	.type = TYPE_GRLIB,
};


static const struct of_device_id of_fsl_spi_match[] = {
	{
		.compatible = "fsl,spi",
		.data = &of_fsl_spi_fsl_config,
        },
	{
		.compatible = "aeroflexgaisler,spictrl",
		.data = &of_fsl_spi_grlib_config,
        },
	{}
};
MODULE_DEVICE_TABLE(of, of_fsl_spi_match);


static int fsl_spi_get_type(struct device *dev) { const struct of_device_id *match; if (dev->of_node) { match = of_match_node(of_fsl_spi_match, dev->of_node); if (match && match->data) return ((struct fsl_spi_match_data *)match->data)->type; } return TYPE_FSL; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson61100.00%1100.00%
Total61100.00%1100.00%


static void fsl_spi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; struct fsl_spi_reg *reg_base = mspi->reg_base; __be32 __iomem *mode = &reg_base->mode; unsigned long flags; if (cs->hw_mode == mpc8xxx_spi_read_reg(mode)) return; /* Turn off IRQs locally to minimize time that SPI is disabled. */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE); /* When in CPM mode, we need to reinit tx and rx. */ if (mspi->flags & SPI_CPM_MODE) { fsl_spi_cpm_reinit_txrx(mspi); } mpc8xxx_spi_write_reg(mode, cs->hw_mode); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov9581.90%240.00%
Mingkai Hu119.48%120.00%
Joakim Tjernlund97.76%120.00%
Andreas Larsson10.86%120.00%
Total116100.00%5100.00%


static void fsl_spi_chipselect(struct spi_device *spi, int value) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_platform_data *pdata; bool pol = spi->mode & SPI_CS_HIGH; struct spi_mpc8xxx_cs *cs = spi->controller_state; pdata = spi->dev.parent->parent->platform_data; if (value == BITBANG_CS_INACTIVE) { if (pdata->cs_control) pdata->cs_control(spi, !pol); } if (value == BITBANG_CS_ACTIVE) { mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; fsl_spi_change_mode(spi); if (pdata->cs_control) pdata->cs_control(spi, pol); } }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala7148.97%114.29%
Anton Vorontsov3020.69%342.86%
Joakim Tjernlund3020.69%114.29%
Kenth Eriksson128.28%114.29%
Mingkai Hu21.38%114.29%
Total145100.00%7100.00%


static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift, int bits_per_word, int msb_first) { *rx_shift = 0; *tx_shift = 0; if (msb_first) { if (bits_per_word <= 8) { *rx_shift = 16; *tx_shift = 24; } else if (bits_per_word <= 16) { *rx_shift = 16; *tx_shift = 16; } } else { if (bits_per_word <= 8) *rx_shift = 8; } }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson87100.00%1100.00%
Total87100.00%1100.00%


static void fsl_spi_grlib_set_shifts(u32 *rx_shift, u32 *tx_shift, int bits_per_word, int msb_first) { *rx_shift = 0; *tx_shift = 0; if (bits_per_word <= 16) { if (msb_first) { *rx_shift = 16; /* LSB in bit 16 */ *tx_shift = 32 - bits_per_word; /* MSB in bit 31 */ } else { *rx_shift = 16 - bits_per_word; /* MSB in bit 15 */ } } }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson69100.00%1100.00%
Total69100.00%1100.00%


static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, struct mpc8xxx_spi *mpc8xxx_spi, int bits_per_word) { cs->rx_shift = 0; cs->tx_shift = 0; if (bits_per_word <= 8) { cs->get_rx = mpc8xxx_spi_rx_buf_u8; cs->get_tx = mpc8xxx_spi_tx_buf_u8; } else if (bits_per_word <= 16) { cs->get_rx = mpc8xxx_spi_rx_buf_u16; cs->get_tx = mpc8xxx_spi_tx_buf_u16; } else if (bits_per_word <= 32) { cs->get_rx = mpc8xxx_spi_rx_buf_u32; cs->get_tx = mpc8xxx_spi_tx_buf_u32; } else return -EINVAL; if (mpc8xxx_spi->set_shifts) mpc8xxx_spi->set_shifts(&cs->rx_shift, &cs->tx_shift, bits_per_word, !(spi->mode & SPI_LSB_FIRST)); mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; return bits_per_word; }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala7443.53%112.50%
Joakim Tjernlund5331.18%337.50%
Anton Vorontsov2414.12%337.50%
Andreas Larsson1911.18%112.50%
Total170100.00%8100.00%


static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, int bits_per_word) { /* QE uses Little Endian for words > 8 * so transform all words > 8 into 8 bits * Unfortnatly that doesn't work for LSB so * reject these for now */ /* Note: 32 bits word, LSB works iff * tfcr/rfcr is set to CPMFCR_GBL */ if (spi->mode & SPI_LSB_FIRST && bits_per_word > 8) return -EINVAL; if (bits_per_word > 8) return 8; /* pretend its 8 bits */ return bits_per_word; }

Contributors

PersonTokensPropCommitsCommitProp
Joakim Tjernlund50100.00%1100.00%
Total50100.00%1100.00%


static int fsl_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi; int bits_per_word = 0; u8 pm; u32 hz = 0; struct spi_mpc8xxx_cs *cs = spi->controller_state; mpc8xxx_spi = spi_master_get_devdata(spi->master); if (t) { bits_per_word = t->bits_per_word; hz = t->speed_hz; } /* spi_transfer level calls that work per-word */ if (!bits_per_word) bits_per_word = spi->bits_per_word; if (!hz) hz = spi->max_speed_hz; if (!(mpc8xxx_spi->flags & SPI_CPM_MODE)) bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi, mpc8xxx_spi, bits_per_word); else if (mpc8xxx_spi->flags & SPI_QE) bits_per_word = mspi_apply_qe_mode_quirks(cs, spi, bits_per_word); if (bits_per_word < 0) return bits_per_word; if (bits_per_word == 32) bits_per_word = 0; else bits_per_word = bits_per_word - 1; /* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16 | SPMODE_PM(0xF)); cs->hw_mode |= SPMODE_LEN(bits_per_word); if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= SPMODE_DIV16; pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. Will use %d Hz instead.\n", dev_name(&spi->dev), hz, mpc8xxx_spi->spibrg / 1024); if (pm > 16) pm = 16; } else { pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; } if (pm) pm--; cs->hw_mode |= SPMODE_PM(pm); fsl_spi_change_mode(spi); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Joakim Tjernlund19663.23%214.29%
Kumar Gala4213.55%17.14%
Anton Vorontsov3210.32%535.71%
Ernst Schwab123.87%17.14%
David Brownell103.23%17.14%
Mingkai Hu82.58%17.14%
Peter Korsgaard61.94%17.14%
Chen Gong30.97%17.14%
SF Markus Elfring10.32%17.14%
Total310100.00%14100.00%


static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, unsigned int len) { u32 word; struct fsl_spi_reg *reg_base = mspi->reg_base; mspi->count = len; /* enable rx ints */ mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE); /* transmit word */ word = mspi->get_tx(mspi); mpc8xxx_spi_write_reg(&reg_base->transmit, word); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson3041.67%116.67%
Anton Vorontsov1013.89%116.67%
Christophe Leroy1013.89%116.67%
Mingkai Hu912.50%116.67%
Kumar Gala79.72%116.67%
Joakim Tjernlund68.33%116.67%
Total72100.00%6100.00%


static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, bool is_dma_mapped) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_reg *reg_base; unsigned int len = t->len; u8 bits_per_word; int ret; reg_base = mpc8xxx_spi->reg_base; bits_per_word = spi->bits_per_word; if (t->bits_per_word) bits_per_word = t->bits_per_word; if (bits_per_word > 8) { /* invalid length? */ if (len & 1) return -EINVAL; len /= 2; } if (bits_per_word > 16) { /* invalid length? */ if (len & 1) return -EINVAL; len /= 2; } mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; reinit_completion(&mpc8xxx_spi->done); if (mpc8xxx_spi->flags & SPI_CPM_MODE) ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); else ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len); if (ret) return ret; wait_for_completion(&mpc8xxx_spi->done); /* disable rx ints */ mpc8xxx_spi_write_reg(&reg_base->mask, 0); if (mpc8xxx_spi->flags & SPI_CPM_MODE) fsl_spi_cpm_bufs_complete(mpc8xxx_spi); return mpc8xxx_spi->count; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson11150.68%112.50%
Joakim Tjernlund6027.40%225.00%
Anton Vorontsov3817.35%337.50%
Mingkai Hu83.65%112.50%
Wolfram Sang20.91%112.50%
Total219100.00%8100.00%


static int fsl_spi_do_one_msg(struct spi_master *master, struct spi_message *m) { struct spi_device *spi = m->spi; struct spi_transfer *t, *first; unsigned int cs_change; const int nsecs = 50; int status; /* Don't allow changes if CS is active */ first = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); list_for_each_entry(t, &m->transfers, transfer_list) { if ((first->bits_per_word != t->bits_per_word) || (first->speed_hz != t->speed_hz)) { dev_err(&spi->dev, "bits_per_word/speed_hz should be same for the same SPI transfer\n"); return -EINVAL; } } cs_change = 1; status = -EINVAL; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->bits_per_word || t->speed_hz) { if (cs_change) status = fsl_spi_setup_transfer(spi, t); if (status < 0) break; } if (cs_change) { fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE); ndelay(nsecs); } cs_change = t->cs_change; if (t->len) status = fsl_spi_bufs(spi, t, m->is_dma_mapped); if (status) { status = -EMSGSIZE; break; } m->actual_length += t->len; if (t->delay_usecs) udelay(t->delay_usecs); if (cs_change) { ndelay(nsecs); fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); ndelay(nsecs); } } m->status = status; spi_finalize_current_message(master); if (status || !cs_change) { ndelay(nsecs); fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); } fsl_spi_setup_transfer(spi, NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson15952.65%112.50%
Stefan Roese7023.18%112.50%
Anton Vorontsov5217.22%225.00%
Heiner Kallweit113.64%112.50%
Joakim Tjernlund51.66%112.50%
Fabio Estevam41.32%112.50%
Mingkai Hu10.33%112.50%
Total302100.00%8100.00%


static int fsl_spi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_spi_reg *reg_base; int retval; u32 hw_mode; struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); if (!spi->max_speed_hz) return -EINVAL; if (!cs) { cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi_set_ctldata(spi, cs); } mpc8xxx_spi = spi_master_get_devdata(spi->master); reg_base = mpc8xxx_spi->reg_base; hw_mode = cs->hw_mode; /* Save original settings */ cs->hw_mode = mpc8xxx_spi_read_reg(&reg_base->mode); /* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH | SPMODE_REV | SPMODE_LOOP); if (spi->mode & SPI_CPHA) cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK; if (spi->mode & SPI_CPOL) cs->hw_mode |= SPMODE_CI_INACTIVEHIGH; if (!(spi->mode & SPI_LSB_FIRST)) cs->hw_mode |= SPMODE_REV; if (spi->mode & SPI_LOOP) cs->hw_mode |= SPMODE_LOOP; retval = fsl_spi_setup_transfer(spi, NULL); if (retval < 0) { cs->hw_mode = hw_mode; /* Restore settings */ return retval; } if (mpc8xxx_spi->type == TYPE_GRLIB) { if (gpio_is_valid(spi->cs_gpio)) { int desel; retval = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); if (retval) return retval; desel = !(spi->mode & SPI_CS_HIGH); retval = gpio_direction_output(spi->cs_gpio, desel); if (retval) { gpio_free(spi->cs_gpio); return retval; } } else if (spi->cs_gpio != -ENOENT) { if (spi->cs_gpio < 0) return spi->cs_gpio; return -EINVAL; } /* When spi->cs_gpio == -ENOENT, a hole in the phandle list * indicates to use native chipselect if present, or allow for * an always selected chip */ } /* Initialize chipselect - might be active for SPI_CS_HIGH mode */ fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson24169.45%330.00%
Joakim Tjernlund4713.54%110.00%
Anton Vorontsov3610.37%220.00%
Axel Lin113.17%220.00%
Kumar Gala61.73%110.00%
Mingkai Hu61.73%110.00%
Total347100.00%10100.00%


static void fsl_spi_cleanup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio)) gpio_free(spi->cs_gpio); kfree(cs); spi_set_ctldata(spi, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson4567.16%150.00%
Axel Lin2232.84%150.00%
Total67100.00%2100.00%


static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { struct fsl_spi_reg *reg_base = mspi->reg_base; /* We need handle RX first */ if (events & SPIE_NE) { u32 rx_data = mpc8xxx_spi_read_reg(&reg_base->receive); if (mspi->rx) mspi->get_rx(rx_data, mspi); } if ((events & SPIE_NF) == 0) /* spin until TX is done */ while (((events = mpc8xxx_spi_read_reg(&reg_base->event)) & SPIE_NF) == 0) cpu_relax(); /* Clear the events */ mpc8xxx_spi_write_reg(&reg_base->event, events); mspi->count -= 1; if (mspi->count) { u32 word = mspi->get_tx(mspi); mpc8xxx_spi_write_reg(&reg_base->transmit, word); } else { complete(&mspi->done); } }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson9463.51%133.33%
Anton Vorontsov4228.38%133.33%
Kumar Gala128.11%133.33%
Total148100.00%3100.00%


static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) { struct mpc8xxx_spi *mspi = context_data; irqreturn_t ret = IRQ_NONE; u32 events; struct fsl_spi_reg *reg_base = mspi->reg_base; /* Get interrupt events(tx/rx) */ events = mpc8xxx_spi_read_reg(&reg_base->event); if (events) ret = IRQ_HANDLED; dev_dbg(mspi->dev, "%s: events %x\n", __func__, events); if (mspi->flags & SPI_CPM_MODE) fsl_spi_cpm_irq(mspi, events); else fsl_spi_cpu_irq(mspi, events); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson6265.26%125.00%
Joakim Tjernlund1818.95%125.00%
Anton Vorontsov1212.63%125.00%
Jeff Harris33.16%125.00%
Total95100.00%4100.00%


static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; u32 slvsel; u16 cs = spi->chip_select; if (gpio_is_valid(spi->cs_gpio)) { gpio_set_value(spi->cs_gpio, on); } else if (cs < mpc8xxx_spi->native_chipselects) { slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel); slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs)); mpc8xxx_spi_write_reg(&reg_base->slvsel, slvsel); } }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson121100.00%2100.00%
Total121100.00%2100.00%


static void fsl_spi_grlib_probe(struct device *dev) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; int mbits; u32 capabilities; capabilities = mpc8xxx_spi_read_reg(&reg_base->cap); mpc8xxx_spi->set_shifts = fsl_spi_grlib_set_shifts; mbits = SPCAP_MAXWLEN(capabilities); if (mbits) mpc8xxx_spi->max_bits_per_word = mbits + 1; mpc8xxx_spi->native_chipselects = 0; if (SPCAP_SSEN(capabilities)) { mpc8xxx_spi->native_chipselects = SPCAP_SSSZ(capabilities); mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff); } master->num_chipselect = mpc8xxx_spi->native_chipselects; pdata->cs_control = fsl_spi_grlib_cs_control; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson13697.84%266.67%
Jingoo Han32.16%133.33%
Total139100.00%3100.00%


static struct spi_master * fsl_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_spi_reg *reg_base; u32 regval; int ret = 0; master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); if (master == NULL) { ret = -ENOMEM; goto err; } dev_set_drvdata(dev, master); mpc8xxx_spi_probe(dev, mem, irq); master->setup = fsl_spi_setup; master->cleanup = fsl_spi_cleanup; master->transfer_one_message = fsl_spi_do_one_msg; mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi->max_bits_per_word = 32; mpc8xxx_spi->type = fsl_spi_get_type(dev); ret = fsl_spi_cpm_init(mpc8xxx_spi); if (ret) goto err_cpm_init; mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); if (IS_ERR(mpc8xxx_spi->reg_base)) { ret = PTR_ERR(mpc8xxx_spi->reg_base); goto err_probe; } if (mpc8xxx_spi->type == TYPE_GRLIB) fsl_spi_grlib_probe(dev); master->bits_per_word_mask = (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) & SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word); if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts; if (mpc8xxx_spi->set_shifts) /* 8 bits per word and MSB first */ mpc8xxx_spi->set_shifts(&mpc8xxx_spi->rx_shift, &mpc8xxx_spi->tx_shift, 8, 1); /* Register for SPI Interrupt */ ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq, 0, "fsl_spi", mpc8xxx_spi); if (ret != 0) goto err_probe; reg_base = mpc8xxx_spi->reg_base; /* SPI controller initializations */ mpc8xxx_spi_write_reg(&reg_base->mode, 0); mpc8xxx_spi_write_reg(&reg_base->mask, 0); mpc8xxx_spi_write_reg(&reg_base->command, 0); mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff); /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; if (mpc8xxx_spi->max_bits_per_word < 8) { regval &= ~SPMODE_LEN(0xF); regval |= SPMODE_LEN(mpc8xxx_spi->max_bits_per_word - 1); } if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) regval |= SPMODE_OP; mpc8xxx_spi_write_reg(&reg_base->mode, regval); ret = devm_spi_register_master(dev, master); if (ret < 0) goto err_probe; dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base, mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); return master; err_probe: fsl_spi_cpm_free(mpc8xxx_spi); err_cpm_init: spi_master_put(master); err: return ERR_PTR(ret); }

Contributors

PersonTokensPropCommitsCommitProp
Kumar Gala15332.62%14.76%
Andreas Larsson10722.81%523.81%
Anton Vorontsov6614.07%419.05%
Mingkai Hu449.38%14.76%
Joakim Tjernlund398.32%29.52%
Axel Lin367.68%29.52%
Heiner Kallweit183.84%29.52%
Jingoo Han30.64%14.76%
Anatolij Gustschin10.21%14.76%
Kay Sievers10.21%14.76%
David Brownell10.21%14.76%
Total469100.00%21100.00%


static void fsl_spi_cs_control(struct spi_device *spi, bool on) { struct device *dev = spi->dev.parent->parent; struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; bool alow = pinfo->alow_flags[cs]; gpio_set_value(gpio, on ^ alow); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov6274.70%233.33%
Jingoo Han1113.25%116.67%
Kumar Gala78.43%116.67%
Herton Ronaldo Krzesinski22.41%116.67%
Mingkai Hu11.20%116.67%
Total83100.00%6100.00%


static int of_fsl_spi_get_chipselects(struct device *dev) { struct device_node *np = dev->of_node; struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); int ngpios; int i = 0; int ret; ngpios = of_gpio_count(np); if (ngpios <= 0) { /* * SPI w/o chip-select line. One SPI device is still permitted * though. */ pdata->max_chipselect = 1; return 0; } pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), GFP_KERNEL); if (!pinfo->gpios) return -ENOMEM; memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags), GFP_KERNEL); if (!pinfo->alow_flags) { ret = -ENOMEM; goto err_alloc_flags; } for (; i < ngpios; i++) { int gpio; enum of_gpio_flags flags; gpio = of_get_gpio_flags(np, i, &flags); if (!gpio_is_valid(gpio)) { dev_err(dev, "invalid gpio #%d: %d\n", i, gpio); ret = gpio; goto err_loop; } ret = gpio_request(gpio, dev_name(dev)); if (ret) { dev_err(dev, "can't request gpio #%d: %d\n", i, ret); goto err_loop; } pinfo->gpios[i] = gpio; pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW; ret = gpio_direction_output(pinfo->gpios[i], pinfo->alow_flags[i]); if (ret) { dev_err(dev, "can't set output direction for gpio #%d: %d\n", i, ret); goto err_loop; } } pdata->max_chipselect = ngpios; pdata->cs_control = fsl_spi_cs_control; return 0; err_loop: while (i >= 0) { if (gpio_is_valid(pinfo->gpios[i])) gpio_free(pinfo->gpios[i]); i--; } kfree(pinfo->alow_flags); pinfo->alow_flags = NULL; err_alloc_flags: kfree(pinfo->gpios); pinfo->gpios = NULL; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov37795.93%327.27%
SF Markus Elfring51.27%327.27%
Jingoo Han30.76%19.09%
Grant C. Likely30.76%218.18%
Roel Kluin30.76%19.09%
Mingkai Hu20.51%19.09%
Total393100.00%11100.00%


static int of_fsl_spi_free_chipselects(struct device *dev) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); int i; if (!pinfo->gpios) return 0; for (i = 0; i < pdata->max_chipselect; i++) { if (gpio_is_valid(pinfo->gpios[i])) gpio_free(pinfo->gpios[i]); } kfree(pinfo->gpios); kfree(pinfo->alow_flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov9696.00%250.00%
Jingoo Han33.00%125.00%
Mingkai Hu11.00%125.00%
Total100100.00%4100.00%


static int of_fsl_spi_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct device_node *np = ofdev->dev.of_node; struct spi_master *master; struct resource mem; int irq, type; int ret = -ENOMEM; ret = of_mpc8xxx_spi_probe(ofdev); if (ret) return ret; type = fsl_spi_get_type(&ofdev->dev); if (type == TYPE_FSL) { ret = of_fsl_spi_get_chipselects(dev); if (ret) goto err; } ret = of_address_to_resource(np, 0, &mem); if (ret) goto err; irq = irq_of_parse_and_map(np, 0); if (!irq) { ret = -EINVAL; goto err; } master = fsl_spi_probe(dev, &mem, irq); if (IS_ERR(master)) { ret = PTR_ERR(master); goto err; } return 0; err: if (type == TYPE_FSL) of_fsl_spi_free_chipselects(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov14877.49%116.67%
Andreas Larsson3015.71%233.33%
Mingkai Hu94.71%116.67%
Grant C. Likely42.09%233.33%
Total191100.00%6100.00%


static int of_fsl_spi_remove(struct platform_device *ofdev) { struct spi_master *master = platform_get_drvdata(ofdev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); fsl_spi_cpm_free(mpc8xxx_spi); if (mpc8xxx_spi->type == TYPE_FSL) of_fsl_spi_free_chipselects(&ofdev->dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson2545.45%116.67%
Anton Vorontsov2443.64%116.67%
Mingkai Hu23.64%116.67%
Heiner Kallweit23.64%116.67%
Grant C. Likely11.82%116.67%
Jingoo Han11.82%116.67%
Total55100.00%6100.00%

static struct platform_driver of_fsl_spi_driver = { .driver = { .name = "fsl_spi", .of_match_table = of_fsl_spi_match, }, .probe = of_fsl_spi_probe, .remove = of_fsl_spi_remove, }; #ifdef CONFIG_MPC832x_RDB /* * XXX XXX XXX * This is "legacy" platform driver, was used by the MPC8323E-RDB boards * only. The driver should go away soon, since newer MPC8323E-RDB's device * tree can work with OpenFirmware driver. But for now we support old trees * as well. */
static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) { struct resource *mem; int irq; struct spi_master *master; if (!dev_get_platdata(&pdev->dev)) return -EINVAL; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL; irq = platform_get_irq(pdev, 0); if (irq <= 0) return -EINVAL; master = fsl_spi_probe(&pdev->dev, mem, irq); return PTR_ERR_OR_ZERO(master); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov9091.84%233.33%
Jingoo Han44.08%116.67%
Uwe Kleine-König22.04%116.67%
Rusty Russell11.02%116.67%
Mingkai Hu11.02%116.67%
Total98100.00%6100.00%


static int plat_mpc8xxx_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); fsl_spi_cpm_free(mpc8xxx_spi); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Heiner Kallweit2461.54%133.33%
Anton Vorontsov1538.46%266.67%
Total39100.00%3100.00%

MODULE_ALIAS("platform:mpc8xxx_spi"); static struct platform_driver mpc8xxx_spi_driver = { .probe = plat_mpc8xxx_spi_probe, .remove = plat_mpc8xxx_spi_remove, .driver = { .name = "mpc8xxx_spi", }, }; static bool legacy_driver_failed;
static void __init legacy_driver_register(void) { legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov17100.00%2100.00%
Total17100.00%2100.00%


static void __exit legacy_driver_unregister(void) { if (legacy_driver_failed) return; platform_driver_unregister(&mpc8xxx_spi_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov20100.00%2100.00%
Total20100.00%2100.00%

#else
static void __init legacy_driver_register(void) {}

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov8100.00%1100.00%
Total8100.00%1100.00%


static void __exit legacy_driver_unregister(void) {}

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov8100.00%1100.00%
Total8100.00%1100.00%

#endif /* CONFIG_MPC832x_RDB */
static int __init fsl_spi_init(void) { legacy_driver_register(); return platform_driver_register(&of_fsl_spi_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov1684.21%133.33%
Mingkai Hu210.53%133.33%
Grant C. Likely15.26%133.33%
Total19100.00%3100.00%

module_init(fsl_spi_init);
static void __exit fsl_spi_exit(void) { platform_driver_unregister(&of_fsl_spi_driver); legacy_driver_unregister(); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Vorontsov1372.22%125.00%
Kumar Gala211.11%125.00%
Mingkai Hu211.11%125.00%
Grant C. Likely15.56%125.00%
Total18100.00%4100.00%

module_exit(fsl_spi_exit); MODULE_AUTHOR("Kumar Gala"); MODULE_DESCRIPTION("Simple Freescale SPI Driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Andreas Larsson148434.60%711.11%
Anton Vorontsov141833.06%1320.63%
Joakim Tjernlund51311.96%46.35%
Kumar Gala4159.68%11.59%
Mingkai Hu1222.84%11.59%
Stefan Roese701.63%11.59%
Axel Lin691.61%46.35%
Heiner Kallweit551.28%34.76%
Jingoo Han290.68%34.76%
Grant C. Likely180.42%69.52%
Xiubo Li170.40%11.59%
Kenth Eriksson120.28%11.59%
Ernst Schwab120.28%11.59%
David Brownell110.26%23.17%
Christophe Leroy100.23%11.59%
SF Markus Elfring60.14%34.76%
Peter Korsgaard60.14%11.59%
Fabio Estevam40.09%11.59%
Roel Kluin30.07%11.59%
Jeff Harris30.07%11.59%
Chen Gong30.07%11.59%
Uwe Kleine-König20.05%11.59%
Wolfram Sang20.05%11.59%
Herton Ronaldo Krzesinski20.05%11.59%
Anatolij Gustschin10.02%11.59%
Kay Sievers10.02%11.59%
Rusty Russell10.02%11.59%
Total4289100.00%63100.00%
Directory: drivers/spi
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.