rockbox/firmware/target/arm/s3c2440/gigabeat-fx/sc606-meg-fx.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

245 lines
4.6 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 by Greg White
*
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "cpu.h"
#include <stdbool.h>
#include "kernel.h"
#include "system.h"
#include "logf.h"
#include "debug.h"
#include "string.h"
#define SLAVE_ADDRESS 0xCC
#define SDA_LO (GPHDAT &= ~(1 << 9))
#define SDA_HI (GPHDAT |= (1 << 9))
#define SDA_INPUT (GPHCON &= ~(3 << 18))
#define SDA_OUTPUT (GPHCON |= (1 << 18))
#define SDA (GPHDAT & (1 << 9))
#define SCL_LO (GPHDAT &= ~(1 << 10))
#define SCL_HI (GPHDAT |= (1 << 10))
#define SCL_INPUT (GPHCON &= ~(3 << 20))
#define SCL_OUTPUT (GPHCON |= (1 << 20))
#define SCL (GPHDAT & (1 << 10))
#define SCL_SDA_HI (GPHDAT |= (3 << 9))
/* The SC606 can clock at 400KHz: */
/* Clock period high is 600nS and low is 1300nS */
/* The high and low times are different enough to need different timings */
/* cycles delayed = 30 + 7 * loops */
/* 100MHz = 10nS per cycle: LO:1300nS=130:14 HI:600nS=60:9 */
/* 300MHz = 3.36nS per cycle: LO:1300nS=387:51 HI:600nS=179:21 */
#define DELAY_LO do{int x;for(x=51;x;x--);} while (0)
#define DELAY do{int x;for(x=35;x;x--);} while (0)
#define DELAY_HI do{int x;for(x=21;x;x--);} while (0)
static void sc606_i2c_start(void)
{
SCL_SDA_HI;
DELAY;
SDA_LO;
DELAY;
SCL_LO;
}
static void sc606_i2c_restart(void)
{
SCL_SDA_HI;
DELAY;
SDA_LO;
DELAY;
SCL_LO;
}
static void sc606_i2c_stop(void)
{
SDA_LO;
SCL_HI;
DELAY_HI;
SDA_HI;
}
static void sc606_i2c_ack(void)
{
SDA_LO;
SCL_HI;
DELAY_HI;
SCL_LO;
}
static int sc606_i2c_getack(void)
{
int ret;
/* Don't need a delay since follows a data bit with a delay on the end */
SDA_INPUT; /* And set to input */
DELAY;
SCL_HI;
ret = (SDA != 0); /* ack failed if SDA is not low */
DELAY_HI;
SCL_LO;
DELAY_LO;
SDA_HI;
SDA_OUTPUT;
DELAY_LO;
return ret;
}
static void sc606_i2c_outb(unsigned char byte)
{
int i;
/* clock out each bit, MSB first */
for (i = 0x80; i; i >>= 1)
{
if (i & byte)
{
SDA_HI;
}
else
{
SDA_LO;
}
DELAY;
SCL_HI;
DELAY_HI;
SCL_LO;
DELAY_LO;
}
SDA_HI;
}
static unsigned char sc606_i2c_inb(void)
{
int i;
unsigned char byte = 0;
SDA_INPUT; /* And set to input */
/* clock in each bit, MSB first */
for (i = 0x80; i; i >>= 1) {
SCL_HI;
if (SDA)
byte |= i;
SCL_LO;
}
SDA_OUTPUT;
sc606_i2c_ack();
return byte;
}
/* returns number of acks that were bad */
int sc606_write(unsigned char reg, unsigned char data)
{
int x;
sc606_i2c_start();
sc606_i2c_outb(SLAVE_ADDRESS);
x = sc606_i2c_getack();
sc606_i2c_outb(reg);
x += sc606_i2c_getack();
sc606_i2c_restart();
sc606_i2c_outb(SLAVE_ADDRESS);
x += sc606_i2c_getack();
sc606_i2c_outb(data);
x += sc606_i2c_getack();
sc606_i2c_stop();
return x;
}
int sc606_read(unsigned char reg, unsigned char* data)
{
int x;
sc606_i2c_start();
sc606_i2c_outb(SLAVE_ADDRESS);
x = sc606_i2c_getack();
sc606_i2c_outb(reg);
x += sc606_i2c_getack();
sc606_i2c_restart();
sc606_i2c_outb(SLAVE_ADDRESS | 1);
x += sc606_i2c_getack();
*data = sc606_i2c_inb();
sc606_i2c_stop();
return x;
}
void sc606_init(void)
{
volatile int i;
/* Set GPB2 (EN) to 1 */
GPBCON = (GPBCON & ~(3<<4)) | 1<<4;
/* Turn enable line on */
GPBDAT |= 1<<2;
/* OFF GPBDAT &= ~(1 << 2); */
/* About 400us - needs 350us */
for (i = 200; i; i--)
{
DELAY_LO;
}
/* Set GPH9 (SDA) and GPH10 (SCL) to 1 */
GPHUP &= ~(3<<9);
GPHCON = (GPHCON & ~(0xF<<18)) | 5<<18;
}