forked from Miroirs/x49gp
302 lines
5.9 KiB
C
302 lines
5.9 KiB
C
/* $Id: s3c2410_spi.c,v 1.4 2008/12/11 12:18:17 ecd Exp $
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <errno.h>
|
|
|
|
#include <x49gp.h>
|
|
#include <s3c2410.h>
|
|
#include <s3c2410_intc.h>
|
|
|
|
|
|
typedef struct {
|
|
uint32_t spicon0;
|
|
uint32_t spista0;
|
|
uint32_t sppin0;
|
|
uint32_t sppre0;
|
|
uint32_t sptdat0;
|
|
uint32_t sprdat0;
|
|
uint32_t spicon1;
|
|
uint32_t spista1;
|
|
uint32_t sppin1;
|
|
uint32_t sppre1;
|
|
uint32_t sptdat1;
|
|
uint32_t sprdat1;
|
|
|
|
unsigned int nr_regs;
|
|
s3c2410_offset_t *regs;
|
|
|
|
x49gp_t *x49gp;
|
|
} s3c2410_spi_t;
|
|
|
|
static int
|
|
s3c2410_spi_data_init(s3c2410_spi_t *spi)
|
|
{
|
|
s3c2410_offset_t regs[] =
|
|
{
|
|
S3C2410_OFFSET(SPI, SPICON0, 0x00000000, spi->spicon0),
|
|
S3C2410_OFFSET(SPI, SPISTA0, 0x00000000, spi->spista0),
|
|
S3C2410_OFFSET(SPI, SPPIN0, 0x00000000, spi->sppin0),
|
|
S3C2410_OFFSET(SPI, SPPRE0, 0x00000000, spi->sppre0),
|
|
S3C2410_OFFSET(SPI, SPTDAT0, 0x00000000, spi->sptdat0),
|
|
S3C2410_OFFSET(SPI, SPRDAT0, 0x00000000, spi->sprdat0),
|
|
S3C2410_OFFSET(SPI, SPICON1, 0x00000000, spi->spicon1),
|
|
S3C2410_OFFSET(SPI, SPISTA1, 0x00000000, spi->spista1),
|
|
S3C2410_OFFSET(SPI, SPPIN1, 0x00000000, spi->sppin1),
|
|
S3C2410_OFFSET(SPI, SPPRE1, 0x00000000, spi->sppre1),
|
|
S3C2410_OFFSET(SPI, SPTDAT1, 0x00000000, spi->sptdat1),
|
|
S3C2410_OFFSET(SPI, SPRDAT1, 0x00000000, spi->sprdat1),
|
|
};
|
|
|
|
memset(spi, 0, sizeof(s3c2410_spi_t));
|
|
|
|
spi->regs = malloc(sizeof(regs));
|
|
if (NULL == spi->regs) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(spi->regs, regs, sizeof(regs));
|
|
spi->nr_regs = sizeof(regs) / sizeof(regs[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t
|
|
s3c2410_spi_read(void *opaque, target_phys_addr_t offset)
|
|
{
|
|
s3c2410_spi_t *spi = opaque;
|
|
s3c2410_offset_t *reg;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_SPI_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(spi, offset)) {
|
|
return ~(0);
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(spi, offset);
|
|
|
|
#ifdef DEBUG_S3C2410_SPI
|
|
printf("read %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-spi", S3C2410_SPI_BASE,
|
|
reg->name, (unsigned long) offset, *(reg->datap));
|
|
#endif
|
|
|
|
switch (offset) {
|
|
case S3C2410_SPI_SPRDAT0:
|
|
spi->spista0 &= ~(1);
|
|
break;
|
|
|
|
case S3C2410_SPI_SPRDAT1:
|
|
spi->spista1 &= ~(1);
|
|
break;
|
|
}
|
|
|
|
return *(reg->datap);
|
|
}
|
|
|
|
void
|
|
s3c2410_spi_write(void *opaque, target_phys_addr_t offset, uint32_t data)
|
|
{
|
|
s3c2410_spi_t *spi = opaque;
|
|
x49gp_t *x49gp = spi->x49gp;
|
|
s3c2410_offset_t *reg;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_SPI_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(spi, offset)) {
|
|
return;
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(spi, offset);
|
|
|
|
#ifdef DEBUG_S3C2410_SPI
|
|
printf("write %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-spi", S3C2410_SPI_BASE,
|
|
reg->name, (unsigned long) offset, data);
|
|
#endif
|
|
|
|
*(reg->datap) = data;
|
|
|
|
switch (offset) {
|
|
case S3C2410_SPI_SPTDAT0:
|
|
spi->spista0 |= 1;
|
|
s3c2410_intc_assert(x49gp, INT_SPI0, 0);
|
|
break;
|
|
|
|
case S3C2410_SPI_SPTDAT1:
|
|
spi->spista1 |= 1;
|
|
s3c2410_intc_assert(x49gp, INT_SPI1, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
s3c2410_spi_load(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_spi_t *spi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int error = 0;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < spi->nr_regs; i++) {
|
|
reg = &spi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
if (x49gp_module_get_u32(module, key, reg->name,
|
|
reg->reset, reg->datap))
|
|
error = -EAGAIN;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
s3c2410_spi_save(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_spi_t *spi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < spi->nr_regs; i++) {
|
|
reg = &spi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_spi_reset(x49gp_module_t *module, x49gp_reset_t reset)
|
|
{
|
|
s3c2410_spi_t *spi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < spi->nr_regs; i++) {
|
|
reg = &spi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
*(reg->datap) = reg->reset;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CPUReadMemoryFunc *s3c2410_spi_readfn[] =
|
|
{
|
|
s3c2410_spi_read,
|
|
s3c2410_spi_read,
|
|
s3c2410_spi_read
|
|
};
|
|
|
|
static CPUWriteMemoryFunc *s3c2410_spi_writefn[] =
|
|
{
|
|
s3c2410_spi_write,
|
|
s3c2410_spi_write,
|
|
s3c2410_spi_write
|
|
};
|
|
|
|
static int
|
|
s3c2410_spi_init(x49gp_module_t *module)
|
|
{
|
|
s3c2410_spi_t *spi;
|
|
int iotype;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
spi = malloc(sizeof(s3c2410_spi_t));
|
|
if (NULL == spi) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
if (s3c2410_spi_data_init(spi)) {
|
|
free(spi);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
module->user_data = spi;
|
|
spi->x49gp = module->x49gp;
|
|
|
|
#ifdef QEMU_OLD
|
|
iotype = cpu_register_io_memory(0, s3c2410_spi_readfn,
|
|
s3c2410_spi_writefn, spi);
|
|
#else
|
|
iotype = cpu_register_io_memory(s3c2410_spi_readfn,
|
|
s3c2410_spi_writefn, spi);
|
|
#endif
|
|
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
|
|
cpu_register_physical_memory(S3C2410_SPI_BASE, S3C2410_MAP_SIZE, iotype);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_spi_exit(x49gp_module_t *module)
|
|
{
|
|
s3c2410_spi_t *spi;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
if (module->user_data) {
|
|
spi = module->user_data;
|
|
if (spi->regs)
|
|
free(spi->regs);
|
|
free(spi);
|
|
}
|
|
|
|
x49gp_module_unregister(module);
|
|
free(module);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
x49gp_s3c2410_spi_init(x49gp_t *x49gp)
|
|
{
|
|
x49gp_module_t *module;
|
|
|
|
if (x49gp_module_init(x49gp, "s3c2410-spi",
|
|
s3c2410_spi_init,
|
|
s3c2410_spi_exit,
|
|
s3c2410_spi_reset,
|
|
s3c2410_spi_load,
|
|
s3c2410_spi_save,
|
|
NULL, &module)) {
|
|
return -1;
|
|
}
|
|
|
|
return x49gp_module_register(module);
|
|
}
|