/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2009 by Maurus Cuelenaere * * based on linux/arch/mips/jz4740/i2c.c * * 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 "system.h" #include "jz4740.h" #include "logf.h" #include "i2c.h" /* * Jz4740 I2C routines. * * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. * Author: * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope 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. * */ /* I2C protocol */ #define I2C_READ 1 #define I2C_WRITE 0 #define TIMEOUT 1000 /* * I2C bus protocol basic routines */ static int i2c_put_data(unsigned char data) { unsigned int timeout = TIMEOUT*10; __i2c_write(data); __i2c_set_drf(); while (__i2c_check_drf() != 0); while (!__i2c_transmit_ended()); while (!__i2c_received_ack() && timeout) timeout--; if (timeout) return 0; else return -1; } #if 0 static int i2c_put_data_nack(unsigned char data) { unsigned int timeout = TIMEOUT*10; __i2c_write(data); __i2c_set_drf(); while (__i2c_check_drf() != 0); while (!__i2c_transmit_ended()); while (timeout--); return 0; } #endif static int i2c_get_data(unsigned char *data, int ack) { int timeout = TIMEOUT*10; if (!ack) __i2c_send_nack(); else __i2c_send_ack(); while (__i2c_check_drf() == 0 && timeout) timeout--; if (timeout) { if (!ack) __i2c_send_stop(); *data = __i2c_read(); __i2c_clear_drf(); return 0; } else return -1; } void i2c_setclk(unsigned int i2cclk) { __i2c_set_clk(__cpm_get_i2sclk(), i2cclk); } /* * I2C interface */ static void i2c_open(void) { __cpm_start_i2c(); i2c_setclk(10000); /* default 10 KHz */ __i2c_enable(); } static void i2c_close(void) { udelay(300); /* wait for STOP goes over. */ __i2c_disable(); __cpm_stop_i2c(); } int i2c_read(int device, unsigned char *buf, int count) { int cnt = count; int timeout = 5; device &= 0xFF; i2c_open(); L_try_again: if (timeout < 0) goto L_timeout; __i2c_send_nack(); /* Master does not send ACK, slave sends it */ __i2c_send_start(); if (i2c_put_data( (device << 1) | I2C_READ ) < 0) goto device_err; __i2c_send_ack(); /* Master sends ACK for continue reading */ while (cnt) { if (cnt == 1) { if (i2c_get_data(buf, 0) < 0) break; } else { if (i2c_get_data(buf, 1) < 0) break; } cnt--; buf++; } __i2c_send_stop(); i2c_close(); return count - cnt; device_err: timeout--; __i2c_send_stop(); goto L_try_again; L_timeout: __i2c_send_stop(); logf("Read I2C device 0x%2x failed.", device); i2c_close(); return -1; } int i2c_write(int device, const unsigned char *buf, int count) { int cnt = count; int timeout = 5; device &= 0xFF; i2c_open(); __i2c_send_nack(); /* Master does not send ACK, slave sends it */ W_try_again: if (timeout < 0) goto W_timeout; cnt = count; __i2c_send_start(); if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) goto device_err; #if 0 //CONFIG_JZ_TPANEL_ATA2508 if (address == 0xff) { while (cnt) { if (i2c_put_data_nack(*buf) < 0) break; cnt--; buf++; } } else #endif { while (cnt) { if (i2c_put_data(*buf) < 0) break; cnt--; buf++; } } __i2c_send_stop(); i2c_close(); return count - cnt; device_err: timeout--; __i2c_send_stop(); goto W_try_again; W_timeout: logf("Write I2C device 0x%2x failed.", device); __i2c_send_stop(); i2c_close(); return -1; } void i2c_init(void) { __gpio_as_i2c(); }