/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006 by Linus Nielsen Feltzing * * 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 #include #include "debug.h" #include "logf.h" #include "generic_i2c.h" int i2c_num_ifs = 0; struct i2c_interface *i2c_if[5]; static void i2c_start(struct i2c_interface *iface) { iface->sda_hi(); iface->scl_hi(); iface->sda_lo(); iface->delay_hd_sta(); iface->scl_lo(); } static void i2c_stop(struct i2c_interface *iface) { iface->sda_lo(); iface->scl_hi(); iface->delay_su_sto(); iface->sda_hi(); } static void i2c_ack(struct i2c_interface *iface, bool ack) { iface->scl_lo(); if ( ack ) iface->sda_lo(); else iface->sda_hi(); iface->delay_su_dat(); iface->scl_hi(); iface->delay_thigh(); iface->scl_lo(); } static int i2c_getack(struct i2c_interface *iface) { int ret = 1; iface->sda_input(); iface->delay_su_dat(); iface->scl_hi(); if (iface->sda()) ret = 0; /* ack failed */ iface->delay_thigh(); iface->scl_lo(); iface->sda_hi(); iface->sda_output(); iface->delay_hd_dat(); return ret; } static unsigned char i2c_inb(struct i2c_interface *iface, bool ack) { int i; unsigned char byte = 0; /* clock in each bit, MSB first */ for ( i=0x80; i; i>>=1 ) { iface->sda_input(); iface->scl_hi(); iface->delay_thigh(); if (iface->sda()) byte |= i; iface->scl_lo(); iface->delay_hd_dat(); iface->sda_output(); } i2c_ack(iface, ack); return byte; } static void i2c_outb(struct i2c_interface *iface, unsigned char byte) { int i; /* clock out each bit, MSB first */ for (i=0x80; i; i>>=1) { if (i & byte) iface->sda_hi(); else iface->sda_lo(); iface->delay_su_dat(); iface->scl_hi(); iface->delay_thigh(); iface->scl_lo(); iface->delay_hd_dat(); } iface->sda_hi(); } static struct i2c_interface *find_if(int address) { int i; for(i = 0;i < i2c_num_ifs;i++) { if(i2c_if[i]->address == address) return i2c_if[i]; } return NULL; } int i2c_write_data(int bus_address, int address, const unsigned char* buf, int count) { int i; int ret = 0; struct i2c_interface *iface = find_if(bus_address); if(!iface) return -1; i2c_start(iface); i2c_outb(iface, iface->address & 0xfe); if (i2c_getack(iface)) { i2c_outb(iface, address); if (i2c_getack(iface)) { for(i = 0;i < count;i++) { i2c_outb(iface, buf[i]); if (!i2c_getack(iface)) { ret = -3; break; } } } else { ret = -2; } } else { logf("i2c_write_data() - no ack\n"); ret = -1; } i2c_stop(iface); return ret; } int i2c_read_data(int bus_address, int address, unsigned char* buf, int count) { int i; int ret = 0; struct i2c_interface *iface = find_if(bus_address); if(!iface) return -1; i2c_start(iface); i2c_outb(iface, iface->address & 0xfe); if (i2c_getack(iface)) { i2c_outb(iface, address); if (i2c_getack(iface)) { i2c_start(iface); i2c_outb(iface, iface->address | 1); if (i2c_getack(iface)) { for(i = 0;i < count-1;i++) buf[i] = i2c_inb(iface, true); buf[i] = i2c_inb(iface, false); } else { ret = -3; } } else { ret = -2; } } else { ret = -1; } i2c_stop(iface); return ret; } void i2c_add_node(struct i2c_interface *iface) { i2c_if[i2c_num_ifs++] = iface; }