⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpc52xx_psc_spi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * MPC52xx SPC in SPI mode driver. * * Maintainer: Dragos Carp * * Copyright (C) 2006 TOPTICA Photonics AG. * * 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/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/interrupt.h>#if defined(CONFIG_PPC_MERGE)#include <asm/of_platform.h>#else#include <linux/platform_device.h>#endif#include <linux/workqueue.h>#include <linux/completion.h>#include <linux/io.h>#include <linux/delay.h>#include <linux/spi/spi.h>#include <linux/fsl_devices.h>#include <asm/mpc52xx.h>#include <asm/mpc52xx_psc.h>#define MCLK 20000000 /* PSC port MClk in hz */struct mpc52xx_psc_spi {	/* fsl_spi_platform data */	void (*activate_cs)(u8, u8);	void (*deactivate_cs)(u8, u8);	u32 sysclk;	/* driver internal data */	struct mpc52xx_psc __iomem *psc;	unsigned int irq;	u8 bits_per_word;	u8 busy;	struct workqueue_struct *workqueue;	struct work_struct work;	struct list_head queue;	spinlock_t lock;	struct completion done;};/* controller state */struct mpc52xx_psc_spi_cs {	int bits_per_word;	int speed_hz;};/* set clock freq, clock ramp, bits per work * if t is NULL then reset the values to the default values */static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,		struct spi_transfer *t){	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;	cs->speed_hz = (t && t->speed_hz)			? t->speed_hz : spi->max_speed_hz;	cs->bits_per_word = (t && t->bits_per_word)			? t->bits_per_word : spi->bits_per_word;	cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;	return 0;}static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi){	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);	struct mpc52xx_psc __iomem *psc = mps->psc;	u32 sicr;	u16 ccr;	sicr = in_be32(&psc->sicr);	/* Set clock phase and polarity */	if (spi->mode & SPI_CPHA)		sicr |= 0x00001000;	else		sicr &= ~0x00001000;	if (spi->mode & SPI_CPOL)		sicr |= 0x00002000;	else		sicr &= ~0x00002000;	if (spi->mode & SPI_LSB_FIRST)		sicr |= 0x10000000;	else		sicr &= ~0x10000000;	out_be32(&psc->sicr, sicr);	/* Set clock frequency and bits per word	 * Because psc->ccr is defined as 16bit register instead of 32bit	 * just set the lower byte of BitClkDiv	 */	ccr = in_be16(&psc->ccr);	ccr &= 0xFF00;	if (cs->speed_hz)		ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;	else /* by default SPI Clk 1MHz */		ccr |= (MCLK / 1000000 - 1) & 0xFF;	out_be16(&psc->ccr, ccr);	mps->bits_per_word = cs->bits_per_word;	if (mps->activate_cs)		mps->activate_cs(spi->chip_select,				(spi->mode & SPI_CS_HIGH) ? 1 : 0);}static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi){	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);	if (mps->deactivate_cs)		mps->deactivate_cs(spi->chip_select,				(spi->mode & SPI_CS_HIGH) ? 1 : 0);}#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)/* wake up when 80% fifo full */#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,						struct spi_transfer *t){	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);	struct mpc52xx_psc __iomem *psc = mps->psc;	unsigned rb = 0;	/* number of bytes receieved */	unsigned sb = 0;	/* number of bytes sent */	unsigned char *rx_buf = (unsigned char *)t->rx_buf;	unsigned char *tx_buf = (unsigned char *)t->tx_buf;	unsigned rfalarm;	unsigned send_at_once = MPC52xx_PSC_BUFSIZE;	unsigned recv_at_once;	unsigned bpw = mps->bits_per_word / 8;	if (!t->tx_buf && !t->rx_buf && t->len)		return -EINVAL;	/* enable transmiter/receiver */	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);	while (rb < t->len) {		if (t->len - rb > MPC52xx_PSC_BUFSIZE) {			rfalarm = MPC52xx_PSC_RFALARM;		} else {			send_at_once = t->len - sb;			rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);		}		dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);		if (tx_buf) {			for (; send_at_once; sb++, send_at_once--) {				/* set EOF flag */				if (mps->bits_per_word						&& (sb + 1) % bpw == 0)					out_8(&psc->ircr2, 0x01);				out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);			}		} else {			for (; send_at_once; sb++, send_at_once--) {				/* set EOF flag */				if (mps->bits_per_word						&& ((sb + 1) % bpw) == 0)					out_8(&psc->ircr2, 0x01);				out_8(&psc->mpc52xx_psc_buffer_8, 0);			}		}		/* enable interrupts and wait for wake up		 * if just one byte is expected the Rx FIFO genererates no		 * FFULL interrupt, so activate the RxRDY interrupt		 */		out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);		if (t->len - rb == 1) {			out_8(&psc->mode, 0);		} else {			out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);			out_be16(&psc->rfalarm, rfalarm);		}		out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);		wait_for_completion(&mps->done);		recv_at_once = in_be16(&psc->rfnum);		dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);		send_at_once = recv_at_once;		if (rx_buf) {			for (; recv_at_once; rb++, recv_at_once--)				rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);		} else {			for (; recv_at_once; rb++, recv_at_once--)				in_8(&psc->mpc52xx_psc_buffer_8);		}	}	/* disable transmiter/receiver */	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);	return 0;}static void mpc52xx_psc_spi_work(struct work_struct *work){	struct mpc52xx_psc_spi *mps =		container_of(work, struct mpc52xx_psc_spi, work);	spin_lock_irq(&mps->lock);	mps->busy = 1;	while (!list_empty(&mps->queue)) {		struct spi_message *m;		struct spi_device *spi;		struct spi_transfer *t = NULL;		unsigned cs_change;		int status;		m = container_of(mps->queue.next, struct spi_message, queue);		list_del_init(&m->queue);		spin_unlock_irq(&mps->lock);		spi = m->spi;		cs_change = 1;		status = 0;		list_for_each_entry (t, &m->transfers, transfer_list) {			if (t->bits_per_word || t->speed_hz) {				status = mpc52xx_psc_spi_transfer_setup(spi, t);				if (status < 0)					break;			}			if (cs_change)				mpc52xx_psc_spi_activate_cs(spi);			cs_change = t->cs_change;			status = mpc52xx_psc_spi_transfer_rxtx(spi, t);			if (status)				break;			m->actual_length += t->len;			if (t->delay_usecs)				udelay(t->delay_usecs);			if (cs_change)				mpc52xx_psc_spi_deactivate_cs(spi);		}		m->status = status;		m->complete(m->context);		if (status || !cs_change)			mpc52xx_psc_spi_deactivate_cs(spi);		mpc52xx_psc_spi_transfer_setup(spi, NULL);		spin_lock_irq(&mps->lock);	}	mps->busy = 0;	spin_unlock_irq(&mps->lock);}/* the spi->mode bits understood by this driver: */#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)static int mpc52xx_psc_spi_setup(struct spi_device *spi){	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;	unsigned long flags;	if (spi->bits_per_word%8)		return -EINVAL;	if (spi->mode & ~MODEBITS) {		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",			spi->mode & ~MODEBITS);		return -EINVAL;	}	if (!cs) {		cs = kzalloc(sizeof *cs, GFP_KERNEL);		if (!cs)			return -ENOMEM;		spi->controller_state = cs;	}	cs->bits_per_word = spi->bits_per_word;	cs->speed_hz = spi->max_speed_hz;	spin_lock_irqsave(&mps->lock, flags);	if (!mps->busy)		mpc52xx_psc_spi_deactivate_cs(spi);	spin_unlock_irqrestore(&mps->lock, flags);	return 0;}static int mpc52xx_psc_spi_transfer(struct spi_device *spi,		struct spi_message *m){	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);	unsigned long flags;	m->actual_length = 0;	m->status = -EINPROGRESS;	spin_lock_irqsave(&mps->lock, flags);	list_add_tail(&m->queue, &mps->queue);	queue_work(mps->workqueue, &mps->work);	spin_unlock_irqrestore(&mps->lock, flags);	return 0;}static void mpc52xx_psc_spi_cleanup(struct spi_device *spi){	kfree(spi->controller_state);}static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -