diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/rtc/ds1306.c | 67 | ||||
| -rw-r--r-- | drivers/rtc/mc13783-rtc.c | 43 | ||||
| -rw-r--r-- | drivers/spi/mpc8xxx_spi.c | 54 | ||||
| -rw-r--r-- | drivers/spi/mxc_spi.c | 88 | 
4 files changed, 191 insertions, 61 deletions
| diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c index 1c8ac7f29..29854fc7c 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -62,13 +62,6 @@  #define	RTC_USER_RAM_BASE	0x20 -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; -  static unsigned int bin2bcd (unsigned int n);  static unsigned char bcd2bin (unsigned char c); @@ -305,11 +298,29 @@ void rtc_reset (void)  static unsigned char rtc_read (unsigned char reg);  static void rtc_write (unsigned char reg, unsigned char val); +static struct spi_slave *slave; +  /* read clock time from DS1306 and return it in *tmp */  int rtc_get (struct rtc_time *tmp)  {  	unsigned char sec, min, hour, mday, wday, mon, year; +	/* +	 * Assuming Vcc = 2.0V (lowest speed) +	 * +	 * REVISIT: If we add an rtc_init() function we can do this +	 * step just once. +	 */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	sec = rtc_read (RTC_SECONDS);  	min = rtc_read (RTC_MINUTES);  	hour = rtc_read (RTC_HOURS); @@ -318,6 +329,8 @@ int rtc_get (struct rtc_time *tmp)  	mon = rtc_read (RTC_MONTH);  	year = rtc_read (RTC_YEAR); +	spi_release_bus(slave); +  	debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "  	       "hr: %02x min: %02x sec: %02x\n",  	       year, mon, mday, wday, hour, min, sec); @@ -360,6 +373,17 @@ int rtc_get (struct rtc_time *tmp)  /* set clock time from *tmp in DS1306 RTC */  void rtc_set (struct rtc_time *tmp)  { +	/* Assuming Vcc = 2.0V (lowest speed) */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	debug ("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",  	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,  	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec); @@ -371,6 +395,8 @@ void rtc_set (struct rtc_time *tmp)  	rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday));  	rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon));  	rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000)); + +	spi_release_bus(slave);  }  /* ------------------------------------------------------------------------- */ @@ -378,6 +404,17 @@ void rtc_set (struct rtc_time *tmp)  /* reset the DS1306 */  void rtc_reset (void)  { +	/* Assuming Vcc = 2.0V (lowest speed) */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	/* clear the control register */  	rtc_write (RTC_CONTROL, 0x00);	/* 1st step: reset WP */  	rtc_write (RTC_CONTROL, 0x00);	/* 2nd step: reset 1Hz, AIE1, AIE0 */ @@ -391,22 +428,18 @@ void rtc_reset (void)  	rtc_write (RTC_HOURS_ALARM1, 0x00);  	rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00);  	rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00); + +	spi_release_bus(slave);  }  /* ------------------------------------------------------------------------- */  static unsigned char rtc_read (unsigned char reg)  { -	unsigned char dout[2];	/* SPI Output Data Bytes */ -	unsigned char din[2];	/* SPI Input Data Bytes */ - -	dout[0] = reg; +	int ret; -	if (spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din) != 0) { -		return 0; -	} else { -		return din[1]; -	} +	ret = spi_w8r8(slave, reg); +	return ret < 0 ? 0 : ret;  }  /* ------------------------------------------------------------------------- */ @@ -419,7 +452,7 @@ static void rtc_write (unsigned char reg, unsigned char val)  	dout[0] = 0x80 | reg;  	dout[1] = val; -	spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din); +	spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);  }  #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c index 35b1b8b25..b6e15014b 100644 --- a/drivers/rtc/mc13783-rtc.c +++ b/drivers/rtc/mc13783-rtc.c @@ -24,34 +24,50 @@  #include <rtc.h>  #include <spi.h> +static struct spi_slave *slave; +  int rtc_get(struct rtc_time *rtc)  {  	u32 day1, day2, time;  	u32 reg;  	int err, tim, i = 0; -	spi_select(1, 0, SPI_MODE_2 | SPI_CS_HIGH); +	if (!slave) { +		/* FIXME: Verify the max SCK rate */ +		slave = spi_setup_slave(1, 0, 1000000, +				SPI_MODE_2 | SPI_CS_HIGH); +		if (!slave) +			return -1; +	} + +	if (spi_claim_bus(slave)) +		return -1;  	do {  		reg = 0x2c000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day1); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day1, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  		reg = 0x28000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&time); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  		reg = 0x2c000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day2); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day2, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  	} while (day1 != day2 && i++ < 3); +	spi_release_bus(slave); +  	tim = day1 * 86400 + time;  	to_tm(tim, rtc); @@ -65,16 +81,31 @@ void rtc_set(struct rtc_time *rtc)  {  	u32 time, day, reg; +	if (!slave) { +		/* FIXME: Verify the max SCK rate */ +		slave = spi_setup_slave(1, 0, 1000000, +				SPI_MODE_2 | SPI_CS_HIGH); +		if (!slave) +			return; +	} +  	time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,  		      rtc->tm_hour, rtc->tm_min, rtc->tm_sec);  	day = time / 86400;  	time %= 86400; +	if (spi_claim_bus(slave)) +		return; +  	reg = 0x2c000000 | day | 0x80000000; -	spi_xfer(0, 32, (uchar *)®, (uchar *)&day); +	spi_xfer(slave, 32, (uchar *)®, (uchar *)&day, +			SPI_XFER_BEGIN | SPI_XFER_END);  	reg = 0x28000000 | time | 0x80000000; -	spi_xfer(0, 32, (uchar *)®, (uchar *)&time); +	spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, +			SPI_XFER_BEGIN | SPI_XFER_END); + +	spi_release_bus(slave);  }  void rtc_reset(void) diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 2fe838c45..136fb5005 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -24,6 +24,7 @@  #include <common.h>  #if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) +#include <malloc.h>  #include <spi.h>  #include <asm/mpc8xxx_spi.h> @@ -37,6 +38,34 @@  #define SPI_TIMEOUT	1000 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	struct spi_slave *slave; + +	if (!spi_cs_is_valid(bus, cs)) +		return NULL; + +	slave = malloc(sizeof(struct spi_slave)); +	if (!slave) +		return NULL; + +	slave->bus = bus; +	slave->cs = cs; + +	/* +	 * TODO: Some of the code in spi_init() should probably move +	 * here, or into spi_claim_bus() below. +	 */ + +	return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	free(slave); +} +  void spi_init(void)  {  	volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; @@ -53,7 +82,18 @@ void spi_init(void)  	spi->com = 0;		/* LST bit doesn't do anything, so disregard */  } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_claim_bus(struct spi_slave *slave) +{ +	return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +		void *din, unsigned long flags)  {  	volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;  	unsigned int tmpdout, tmpdin, event; @@ -61,11 +101,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  	int tm, isRead = 0;  	unsigned char charSize = 32; -	debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", -	      (int)chipsel, *(uint *) dout, *(uint *) din, bitlen); +	debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", +	      slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); -	if (chipsel != NULL) -		(*chipsel) (1);	/* select the target chip */ +	if (flags & SPI_XFER_BEGIN) +		spi_cs_activate(slave);  	spi->event = 0xffffffff;	/* Clear all SPI events */ @@ -135,8 +175,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin);  	} -	if (chipsel != NULL) -		(*chipsel) (0);	/* deselect the target chip */ +	if (flags & SPI_XFER_END) +		spi_cs_deactivate(slave);  	return 0;  } diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index c166ec502..5957ada3a 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -19,6 +19,7 @@   */  #include <common.h> +#include <malloc.h>  #include <spi.h>  #include <asm/io.h> @@ -61,17 +62,18 @@ static unsigned long spi_bases[] = {  	0x53f84000,  }; -static unsigned long spi_base; -  #endif -spi_chipsel_type spi_chipsel[] = { -	(spi_chipsel_type)0, -	(spi_chipsel_type)1, -	(spi_chipsel_type)2, -	(spi_chipsel_type)3, +struct mxc_spi_slave { +	struct spi_slave slave; +	unsigned long	base; +	u32		ctrl_reg;  }; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) +{ +	return container_of(slave, struct mxc_spi_slave, slave); +}  static inline u32 reg_read(unsigned long addr)  { @@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val)  	*(volatile unsigned long*)addr = val;  } -static u32 spi_xchg_single(u32 data, int bitlen) +static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)  { - -	unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); +	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); +	unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL);  	if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {  		cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |  			MXC_CSPICTRL_BITCOUNT(bitlen - 1); -		reg_write(spi_base + MXC_CSPICTRL, cfg_reg); +		reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);  	} -	reg_write(spi_base + MXC_CSPITXDATA, data); +	reg_write(mxcs->base + MXC_CSPITXDATA, data);  	cfg_reg |= MXC_CSPICTRL_XCH; -	reg_write(spi_base + MXC_CSPICTRL, cfg_reg); +	reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); -	while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) +	while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)  		; -	return reg_read(spi_base + MXC_CSPIRXDATA); +	return reg_read(mxcs->base + MXC_CSPIRXDATA);  } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +		void *din, unsigned long flags)  {  	int n_blks = (bitlen + 31) / 32;  	u32 *out_l, *in_l; @@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		return 1;  	} -	if (!spi_base) -		spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); -  	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;  	     i < n_blks;  	     i++, in_l++, out_l++, bitlen -= 32) -		*in_l = spi_xchg_single(*out_l, bitlen); +		*in_l = spi_xchg_single(slave, *out_l, bitlen);  	return 0;  } @@ -132,17 +132,17 @@ void spi_init(void)  {  } -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +			unsigned int max_hz, unsigned int mode)  {  	unsigned int ctrl_reg; +	struct mxc_spi_slave *mxcs;  	if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || -	    dev > 3) -		return 1; - -	spi_base = spi_bases[bus]; +	    cs > 3) +		return NULL; -	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | +	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) |  		MXC_CSPICTRL_BITCOUNT(31) |  		MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */  		MXC_CSPICTRL_EN | @@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode)  	if (mode & SPI_CS_HIGH)  		ctrl_reg |= MXC_CSPICTRL_SSPOL; -	reg_write(spi_base + MXC_CSPIRESET, 1); +	mxcs = malloc(sizeof(struct mxc_spi_slave)); +	if (!mxcs) +		return NULL; + +	mxcs->slave.bus = bus; +	mxcs->slave.cs = cs; +	mxcs->base = spi_bases[bus]; +	mxcs->ctrl_reg = ctrl_reg; + +	return &mxcs->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + +	reg_write(mxcs->base + MXC_CSPIRESET, 1);  	udelay(1); -	reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); -	reg_write(spi_base + MXC_CSPIPERIOD, +	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); +	reg_write(mxcs->base + MXC_CSPIPERIOD,  		  MXC_CSPIPERIOD_32KHZ); -	reg_write(spi_base + MXC_CSPIINT, 0); +	reg_write(mxcs->base + MXC_CSPIINT, 0);  	return 0;  } + +void spi_release_bus(struct spi_slave *slave) +{ +	/* TODO: Shut the controller down */ +} |