diff options
Diffstat (limited to 'drivers/spi/spi-orion.c')
| -rw-r--r-- | drivers/spi/spi-orion.c | 203 | 
1 files changed, 58 insertions, 145 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 9b0caddce50..b17c09cf0a0 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -36,12 +36,6 @@  #define ORION_SPI_CLK_PRESCALE_MASK	0x1F  struct orion_spi { -	struct work_struct	work; - -	/* Lock access to transfer list.	*/ -	spinlock_t		lock; - -	struct list_head	msg_queue;  	struct spi_master	*master;  	void __iomem		*base;  	unsigned int		max_speed; @@ -49,8 +43,6 @@ struct orion_spi {  	struct clk              *clk;  }; -static struct workqueue_struct *orion_spi_wq; -  static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)  {  	return orion_spi->base + reg; @@ -277,73 +269,78 @@ out:  } -static void orion_spi_work(struct work_struct *work) +static int orion_spi_transfer_one_message(struct spi_master *master, +					   struct spi_message *m)  { -	struct orion_spi *orion_spi = -		container_of(work, struct orion_spi, work); - -	spin_lock_irq(&orion_spi->lock); -	while (!list_empty(&orion_spi->msg_queue)) { -		struct spi_message *m; -		struct spi_device *spi; -		struct spi_transfer *t = NULL; -		int par_override = 0; -		int status = 0; -		int cs_active = 0; - -		m = container_of(orion_spi->msg_queue.next, struct spi_message, -				 queue); +	struct orion_spi *orion_spi = spi_master_get_devdata(master); +	struct spi_device *spi = m->spi; +	struct spi_transfer *t = NULL; +	int par_override = 0; +	int status = 0; +	int cs_active = 0; -		list_del_init(&m->queue); -		spin_unlock_irq(&orion_spi->lock); +	/* Load defaults */ +	status = orion_spi_setup_transfer(spi, NULL); -		spi = m->spi; +	if (status < 0) +		goto msg_done; -		/* Load defaults */ -		status = orion_spi_setup_transfer(spi, NULL); +	list_for_each_entry(t, &m->transfers, transfer_list) { +		/* make sure buffer length is even when working in 16 +		 * bit mode*/ +		if ((t->bits_per_word == 16) && (t->len & 1)) { +			dev_err(&spi->dev, +				"message rejected : " +				"odd data length %d while in 16 bit mode\n", +				t->len); +			status = -EIO; +			goto msg_done; +		} -		if (status < 0) +		if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { +			dev_err(&spi->dev, +				"message rejected : " +				"device min speed (%d Hz) exceeds " +				"required transfer speed (%d Hz)\n", +				orion_spi->min_speed, t->speed_hz); +			status = -EIO;  			goto msg_done; +		} -		list_for_each_entry(t, &m->transfers, transfer_list) { -			if (par_override || t->speed_hz || t->bits_per_word) { -				par_override = 1; -				status = orion_spi_setup_transfer(spi, t); -				if (status < 0) -					break; -				if (!t->speed_hz && !t->bits_per_word) -					par_override = 0; -			} +		if (par_override || t->speed_hz || t->bits_per_word) { +			par_override = 1; +			status = orion_spi_setup_transfer(spi, t); +			if (status < 0) +				break; +			if (!t->speed_hz && !t->bits_per_word) +				par_override = 0; +		} -			if (!cs_active) { -				orion_spi_set_cs(orion_spi, 1); -				cs_active = 1; -			} +		if (!cs_active) { +			orion_spi_set_cs(orion_spi, 1); +			cs_active = 1; +		} -			if (t->len) -				m->actual_length += -					orion_spi_write_read(spi, t); +		if (t->len) +			m->actual_length += orion_spi_write_read(spi, t); -			if (t->delay_usecs) -				udelay(t->delay_usecs); +		if (t->delay_usecs) +			udelay(t->delay_usecs); -			if (t->cs_change) { -				orion_spi_set_cs(orion_spi, 0); -				cs_active = 0; -			} +		if (t->cs_change) { +			orion_spi_set_cs(orion_spi, 0); +			cs_active = 0;  		} +	}  msg_done: -		if (cs_active) -			orion_spi_set_cs(orion_spi, 0); +	if (cs_active) +		orion_spi_set_cs(orion_spi, 0); -		m->status = status; -		m->complete(m->context); +	m->status = status; +	spi_finalize_current_message(master); -		spin_lock_irq(&orion_spi->lock); -	} - -	spin_unlock_irq(&orion_spi->lock); +	return 0;  }  static int __init orion_spi_reset(struct orion_spi *orion_spi) @@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi)  	return 0;  } -static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m) -{ -	struct orion_spi *orion_spi; -	struct spi_transfer *t = NULL; -	unsigned long flags; - -	m->actual_length = 0; -	m->status = 0; - -	/* reject invalid messages and transfers */ -	if (list_empty(&m->transfers) || !m->complete) -		return -EINVAL; - -	orion_spi = spi_master_get_devdata(spi->master); - -	list_for_each_entry(t, &m->transfers, transfer_list) { -		unsigned int bits_per_word = spi->bits_per_word; - -		if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { -			dev_err(&spi->dev, -				"message rejected : " -				"invalid transfer data buffers\n"); -			goto msg_rejected; -		} - -		if (t->bits_per_word) -			bits_per_word = t->bits_per_word; - -		if ((bits_per_word != 8) && (bits_per_word != 16)) { -			dev_err(&spi->dev, -				"message rejected : " -				"invalid transfer bits_per_word (%d bits)\n", -				bits_per_word); -			goto msg_rejected; -		} -		/*make sure buffer length is even when working in 16 bit mode*/ -		if ((t->bits_per_word == 16) && (t->len & 1)) { -			dev_err(&spi->dev, -				"message rejected : " -				"odd data length (%d) while in 16 bit mode\n", -				t->len); -			goto msg_rejected; -		} - -		if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { -			dev_err(&spi->dev, -				"message rejected : " -				"device min speed (%d Hz) exceeds " -				"required transfer speed (%d Hz)\n", -				orion_spi->min_speed, t->speed_hz); -			goto msg_rejected; -		} -	} - - -	spin_lock_irqsave(&orion_spi->lock, flags); -	list_add_tail(&m->queue, &orion_spi->msg_queue); -	queue_work(orion_spi_wq, &orion_spi->work); -	spin_unlock_irqrestore(&orion_spi->lock, flags); - -	return 0; -msg_rejected: -	/* Message rejected and not queued */ -	m->status = -EINVAL; -	if (m->complete) -		m->complete(m->context); -	return -EINVAL; -} -  static int __init orion_spi_probe(struct platform_device *pdev)  {  	struct spi_master *master; @@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)  	master->mode_bits = 0;  	master->setup = orion_spi_setup; -	master->transfer = orion_spi_transfer; +	master->transfer_one_message = orion_spi_transfer_one_message;  	master->num_chipselect = ORION_NUM_CHIPSELECTS;  	dev_set_drvdata(&pdev->dev, master); @@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev)  	}  	spi->base = ioremap(r->start, SZ_1K); -	INIT_WORK(&spi->work, orion_spi_work); - -	spin_lock_init(&spi->lock); -	INIT_LIST_HEAD(&spi->msg_queue); -  	if (orion_spi_reset(spi) < 0)  		goto out_rel_mem; @@ -536,14 +459,12 @@ out:  static int __exit orion_spi_remove(struct platform_device *pdev)  {  	struct spi_master *master; -	struct orion_spi *spi;  	struct resource *r; +	struct orion_spi *spi;  	master = dev_get_drvdata(&pdev->dev);  	spi = spi_master_get_devdata(master); -	cancel_work_sync(&spi->work); -  	clk_disable_unprepare(spi->clk);  	clk_put(spi->clk); @@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = {  static int __init orion_spi_init(void)  { -	orion_spi_wq = create_singlethread_workqueue( -				orion_spi_driver.driver.name); -	if (orion_spi_wq == NULL) -		return -ENOMEM; -  	return platform_driver_probe(&orion_spi_driver, orion_spi_probe);  }  module_init(orion_spi_init);  static void __exit orion_spi_exit(void)  { -	flush_workqueue(orion_spi_wq);  	platform_driver_unregister(&orion_spi_driver); - -	destroy_workqueue(orion_spi_wq);  }  module_exit(orion_spi_exit);  |