Commit e3093091 authored by wdenk's avatar wdenk

Initial revision

parent a2cecab6
/*
* (C) Copyright 2002
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* SPI Read/Write Utilities
*/
#include <common.h>
#include <command.h>
#include <spi.h>
#include <cmd_spi.h>
#if (CONFIG_COMMANDS & CFG_CMD_SPI)
#define MAX_SPI_BYTES 32 /* max number of bytes we can handle */
/*
* External table of chip select functions (see the appropriate board
* support for the actual definition of the table).
*/
extern spi_chipsel_type spi_chipsel[];
/*
* Values from last command.
*/
static int device;
static int bitlen;
static uchar dout[MAX_SPI_BYTES];
static uchar din[MAX_SPI_BYTES];
/*
* SPI read/write
*
* Syntax:
* spi {dev} {num_bits} {dout}
* {dev} is the device number for controlling chip select (see TBD)
* {num_bits} is the number of bits to send & receive (base 10)
* {dout} is a hexadecimal string of data to send
* The command prints out the hexadecimal string received via SPI.
*/
int do_spi (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
{
char *cp = 0;
uchar tmp;
int j;
int rcode = 0;
/*
* We use the last specified parameters, unless new ones are
* entered.
*/
if ((flag & CMD_FLAG_REPEAT) == 0)
{
if (argc >= 2)
device = simple_strtoul(argv[1], NULL, 10);
if (argc >= 3)
bitlen = simple_strtoul(argv[2], NULL, 10);
if (argc >= 4)
cp = argv[3];
for(j = 0; *cp; j++, cp++) {
tmp = *cp - '0';
if(tmp > 9)
tmp -= ('A' - '0') - 10;
if(tmp > 15)
tmp -= ('a' - 'A');
if(tmp > 15) {
printf("Conversion error on %c, bailing out.\n", *cp);
break;
}
if((j % 2) == 0)
dout[j / 2] = (tmp << 4);
else
dout[j / 2] |= tmp;
}
}
printf("spi_chipsel[%d] = %08X\n", device, (uint)spi_chipsel[device]);
if(spi_xfer(spi_chipsel[device], bitlen, dout, din) != 0) {
printf("Error with the SPI transaction.\n");
rcode = 1;
} else {
cp = din;
for(j = 0; j < ((bitlen + 7) / 8); j++) {
printf("%02X", *cp++);
}
printf("\n");
}
return rcode;
}
#endif /* CFG_CMD_SPI */
/*
* (C) Copyright 2002
* Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
*
* Influenced by code from:
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <spi.h>
#if defined(CONFIG_SOFT_SPI)
#define DEBUG_SPI
/*-----------------------------------------------------------------------
* Definitions
*/
#ifdef DEBUG_SPI
#define PRINTD(fmt,args...) printf (fmt ,##args)
#else
#define PRINTD(fmt,args...)
#endif
/*=====================================================================*/
/* Public Functions */
/*=====================================================================*/
/*-----------------------------------------------------------------------
* Initialization
*/
void spi_init (void)
{
#ifdef SPI_INIT
volatile immap_t *immr = (immap_t *)CFG_IMMR;
SPI_INIT;
#endif
}
/*-----------------------------------------------------------------------
* SPI transfer
*
* This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
* "bitlen" bits in the SPI MISO port. That's just the way SPI works.
*
* The source of the outgoing bits is the "dout" parameter and the
* destination of the input bits is the "din" parameter. Note that "dout"
* and "din" can point to the same memory location, in which case the
* input data overwrites the output data (since both are buffered by
* temporary variables, this is OK).
*
* If the chipsel() function is not NULL, it is called with a parameter
* of '1' (chip select active) at the start of the transfer and again with
* a parameter of '0' at the end of the transfer.
*
* If the chipsel() function _is_ NULL, it the responsibility of the
* caller to make the appropriate chip select active before calling
* spi_xfer() and making it inactive after spi_xfer() returns.
*/
int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
uchar tmpdin = 0;
uchar tmpdout = 0;
int j;
PRINTD("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n",
(int)chipsel, *(uint *)dout, *(uint *)din, bitlen);
if(chipsel != NULL) {
(*chipsel)(1); /* select the target chip */
}
for(j = 0; j < bitlen; j++) {
/*
* Check if it is time to work on a new byte.
*/
if((j % 8) == 0) {
tmpdout = *dout++;
if(j != 0) {
*din++ = tmpdin;
}
tmpdin = 0;
}
SPI_SCL(0);
SPI_SDA(tmpdout & 0x80);
SPI_DELAY;
SPI_SCL(1);
SPI_DELAY;
tmpdin <<= 1;
tmpdin |= SPI_READ;
tmpdout <<= 1;
}
/*
* If the number of bits isn't a multiple of 8, shift the last
* bits over to left-justify them. Then store the last byte
* read in.
*/
if((bitlen % 8) != 0)
tmpdin <<= 8 - (bitlen % 8);
*din++ = tmpdin;
SPI_SCL(0); /* SPI wants the clock left low for idle */
if(chipsel != NULL) {
(*chipsel)(0); /* deselect the target chip */
}
return(0);
}
#endif /* CONFIG_SOFT_SPI */
/*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <status_led.h>
/*
* The purpose of this code is to signal the operational status of a
* target which usually boots over the network; while running in
* PCBoot, a status LED is blinking. As soon as a valid BOOTP reply
* message has been received, the LED is turned off. The Linux
* kernel, once it is running, will start blinking the LED again,
* with another frequency.
*/
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_STATUS_LED
typedef struct {
ulong mask;
int state;
int period;
int cnt;
} led_dev_t;
led_dev_t led_dev[] = {
{ STATUS_LED_BIT,
STATUS_LED_STATE,
STATUS_LED_PERIOD,
0,
},
#if defined(STATUS_LED_BIT1)
{ STATUS_LED_BIT1,
STATUS_LED_STATE1,
STATUS_LED_PERIOD1,
0,
},
#endif
#if defined(STATUS_LED_BIT2)
{ STATUS_LED_BIT2,
STATUS_LED_STATE2,
STATUS_LED_PERIOD2,
0,
},
#endif
};
#define MAX_LED_DEV (sizeof(led_dev)/sizeof(led_dev_t))
static int status_led_init_done = 0;
static void status_led_init (void)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
int i;
for (i=0; i<MAX_LED_DEV; ++i) {
led_dev_t *ld = &led_dev[i];
immr->STATUS_LED_PAR &= ~(ld->mask);
#ifdef STATUS_LED_ODR
immr->STATUS_LED_ODR &= ~(ld->mask);
#endif
#if (STATUS_LED_ACTIVE == 0)
if (ld->state == STATUS_LED_ON)
immr->STATUS_LED_DAT &= ~(ld->mask);
else
immr->STATUS_LED_DAT |= ld->mask ;
#else
if (ld->state == STATUS_LED_ON)
immr->STATUS_LED_DAT |= ld->mask ;
else
immr->STATUS_LED_DAT &= ~(ld->mask);
#endif
immr->STATUS_LED_DIR |= ld->mask ;
}
status_led_init_done = 1;
}
void status_led_tick (ulong timestamp)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
int i;
if (!status_led_init_done)
status_led_init();
for (i=0; i<MAX_LED_DEV; ++i) {
led_dev_t *ld = &led_dev[i];
if (ld->state != STATUS_LED_BLINKING)
continue;
if (++(ld->cnt) >= ld->period) {
immr->STATUS_LED_DAT ^= ld->mask;
ld->cnt -= ld->period;
}
}
}
void status_led_set (int led, int state)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
led_dev_t *ld;
if (led < 0 || led >= MAX_LED_DEV)
return;
if (!status_led_init_done)
status_led_init();
ld = &led_dev[led];
switch (state) {
default:
return;
case STATUS_LED_BLINKING:
ld->cnt = 0; /* always start with full period */
/* fall through */ /* always start with LED _ON_ */
case STATUS_LED_ON:
#if (STATUS_LED_ACTIVE == 0)
immr->STATUS_LED_DAT &= ~(ld->mask);
#else
immr->STATUS_LED_DAT |= ld->mask ;
#endif
break;
case STATUS_LED_OFF:
#if (STATUS_LED_ACTIVE == 0)
immr->STATUS_LED_DAT |= ld->mask ;
#else
immr->STATUS_LED_DAT &= ~(ld->mask);
#endif
break;
}
ld->state = state;
}
#endif /* CONFIG_STATUS_LED */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment