first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <drivers/iic.h>
|
||||
#include <platform.h>
|
||||
#include <platform/int.h>
|
||||
#include <platform/clocks.h>
|
||||
#include <platform/timer.h>
|
||||
#include <platform/gpio.h>
|
||||
#include <platform/gpiodef.h>
|
||||
#include <platform/soc/pmgr.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <platform/soc/hwisr.h>
|
||||
#include <sys.h>
|
||||
#include <sys/menu.h>
|
||||
#include <sys/task.h>
|
||||
|
||||
#include "iic.h"
|
||||
|
||||
#ifndef IICS_MASK
|
||||
#define IICS_MASK ((1 << IICS_COUNT) - 1)
|
||||
#endif
|
||||
|
||||
static struct iic_device *get_iic_device(int port);
|
||||
static void iic_setup(struct iic_device *dev);
|
||||
static void iic_set_clock(struct iic_device *dev, u_int32_t period);
|
||||
static void iic_reset_bus(struct iic_device *dev);
|
||||
|
||||
void iic_init(void)
|
||||
{
|
||||
int iic;
|
||||
|
||||
dprintf(DEBUG_INFO, "iic_init()\n");
|
||||
|
||||
for (iic = 0; iic < IICS_COUNT; iic++) {
|
||||
if (!((1 << iic) & IICS_MASK))
|
||||
continue;
|
||||
iic_setup(get_iic_device(iic));
|
||||
}
|
||||
}
|
||||
|
||||
void iic_set_filter(int iic, uint32_t value) {
|
||||
rFILTER(iic) = value;
|
||||
}
|
||||
|
||||
void iic_set_frequency(int iic, u_int32_t frequency)
|
||||
{
|
||||
struct iic_device *dev;
|
||||
u_int32_t period = 1000000000/frequency;
|
||||
|
||||
dev = get_iic_device(iic);
|
||||
if (dev == 0) return;
|
||||
|
||||
iic_set_clock(dev, period);
|
||||
}
|
||||
|
||||
int iic_read(int iic, u_int8_t address, const void *send_data, size_t send_len, void *data, size_t len, iic_fmt_t fmt)
|
||||
{
|
||||
struct iic_device *dev = get_iic_device(iic);
|
||||
u_int8_t *dptr = (u_int8_t *)send_data;
|
||||
u_int32_t dat, to_send;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev) return -1;
|
||||
if (!(IICS_MASK & (1 << iic))) return -1;
|
||||
if (len < 1) return 0;
|
||||
|
||||
while (dev->busy) task_yield();
|
||||
dev->busy = true;
|
||||
|
||||
/* Possibilities:
|
||||
- no sub-address + N bytes
|
||||
- sub-address + N bytes
|
||||
- sub-address + N bytes combined (restarted read)
|
||||
*/
|
||||
|
||||
rSMSTA(iic) = kS5L8940XIICSMSTAxen | kS5L8940XIICSMSTAmtn;
|
||||
|
||||
to_send = send_len;
|
||||
if (send_len) {
|
||||
to_send++;
|
||||
enter_critical_section();
|
||||
dat = (kS5L8940XIICMTXFIFOWrite |
|
||||
kS5L8940XIICMTXFIFOStart |
|
||||
kS5L8940XIICMTXFIFOData(address&~1));
|
||||
rMTXFIFO(iic) = dat;
|
||||
while (send_len--) {
|
||||
dat = kS5L8940XIICMTXFIFOData(*dptr);
|
||||
if ((fmt == IIC_NORMAL) && (send_len == 0))
|
||||
dat |= kS5L8940XIICMTXFIFOStop;
|
||||
rMTXFIFO(iic) = dat;
|
||||
dptr++;
|
||||
}
|
||||
exit_critical_section();
|
||||
}
|
||||
dptr = data;
|
||||
enter_critical_section();
|
||||
rMTXFIFO(iic) = dat = (kS5L8940XIICMTXFIFOStart |
|
||||
kS5L8940XIICMTXFIFOData(address|1));
|
||||
rMTXFIFO(iic) = dat = (kS5L8940XIICMTXFIFORead | kS5L8940XIICMTXFIFOStop |
|
||||
kS5L8940XIICMTXFIFOData(len));
|
||||
exit_critical_section();
|
||||
while (len--) {
|
||||
while ((dat = rMRXFIFO(iic)) & kS5L8940XIICMRXFIFOEmpty) {
|
||||
if (rSMSTA(iic) & kS5L8940XIICSMSTAmtn) {
|
||||
dprintf(DEBUG_INFO, "iic_read(%d) NAK\n", iic);
|
||||
rCTL(iic) = rCTL(iic) | kS5L8940XIICCTLMTR; /* clear the FIFO first */
|
||||
rSMSTA(iic) = kS5L8940XIICSMSTAmtn; /* now blast the NAK bit */
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
*dptr++ = kS5L8940XIICMRXFIFOData(dat);
|
||||
}
|
||||
|
||||
out:
|
||||
dev->busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iic_write(int iic, u_int8_t address, const void *data, size_t len)
|
||||
{
|
||||
struct iic_device *dev = get_iic_device(iic);
|
||||
const u_int8_t *dptr = data;
|
||||
u_int32_t dat;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev) return -1;
|
||||
if (!(IICS_MASK & (1 << iic))) return -1;
|
||||
|
||||
/* Don't support "quick command" */
|
||||
if (len < 1) return -1;
|
||||
|
||||
while (dev->busy) task_yield();
|
||||
dev->busy = true;
|
||||
|
||||
rSMSTA(iic) = kS5L8940XIICSMSTAxen | kS5L8940XIICSMSTAmtn;
|
||||
|
||||
address &= ~1;
|
||||
enter_critical_section();
|
||||
rMTXFIFO(iic) = (kS5L8940XIICMTXFIFOWrite | kS5L8940XIICMTXFIFOStart |
|
||||
kS5L8940XIICMTXFIFOData(address));
|
||||
/* XXX bust out early if NAK observed? */
|
||||
while (len--) {
|
||||
dat = kS5L8940XIICMTXFIFOData(*dptr);
|
||||
if (len == 0)
|
||||
dat |= kS5L8940XIICMTXFIFOStop;
|
||||
rMTXFIFO(iic) = dat;
|
||||
dptr++;
|
||||
}
|
||||
exit_critical_section();
|
||||
/* Spin til the transaction is ended or standard 1-second timeout */
|
||||
SPIN_W_TMO_WHILE(!(rSMSTA(iic) & kS5L8940XIICSMSTAxen));
|
||||
/* Check for a NAK and clean up if necessary */
|
||||
if (rSMSTA(iic) & kS5L8940XIICSMSTAmtn) {
|
||||
dprintf(DEBUG_INFO, "iic_write(%d) NAK\n", iic);
|
||||
rCTL(iic) = rCTL(iic) | kS5L8940XIICCTLMTR; /* clear the FIFO first */
|
||||
rSMSTA(iic) = kS5L8940XIICSMSTAmtn; /* now blast the NAK bit */
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
dev->busy = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool iic_probe(int iic, u_int8_t address)
|
||||
{
|
||||
/* might be nice to implement this */
|
||||
return false;
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
static struct iic_device _iic_device[] = {
|
||||
#if IICS_COUNT > 0
|
||||
{
|
||||
.bus = 0,
|
||||
.clk = CLK_I2C0,
|
||||
.irq = INT_IIC0,
|
||||
.gpio_scl = GPIO_IIC0_SCL,
|
||||
.gpio_sda = GPIO_IIC0_SDA,
|
||||
},
|
||||
#endif
|
||||
#if IICS_COUNT > 1
|
||||
{
|
||||
.bus = 1,
|
||||
.clk = CLK_I2C1,
|
||||
.irq = INT_IIC1,
|
||||
.gpio_scl = GPIO_IIC1_SCL,
|
||||
.gpio_sda = GPIO_IIC1_SDA,
|
||||
},
|
||||
#endif
|
||||
#if IICS_COUNT > 2
|
||||
{
|
||||
.bus = 2,
|
||||
.clk = CLK_I2C2,
|
||||
.irq = INT_IIC2,
|
||||
.gpio_scl = GPIO_IIC2_SCL,
|
||||
.gpio_sda = GPIO_IIC2_SDA,
|
||||
},
|
||||
#endif
|
||||
#if IICS_COUNT > 3
|
||||
{
|
||||
.bus = 3,
|
||||
.clk = CLK_I2C3,
|
||||
.irq = INT_IIC3,
|
||||
.gpio_scl = GPIO_IIC3_SCL,
|
||||
.gpio_sda = GPIO_IIC3_SDA,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct iic_device *get_iic_device(int port)
|
||||
{
|
||||
if (!((1 << port) & IICS_MASK)) return 0;
|
||||
|
||||
return &_iic_device[port];
|
||||
}
|
||||
|
||||
static void iic_setup(struct iic_device *dev)
|
||||
{
|
||||
if (dev == 0) return;
|
||||
|
||||
/* make sure the clock is enabled for iic */
|
||||
clock_gate(dev->clk, true);
|
||||
|
||||
/* Set for 400KHz */
|
||||
iic_set_clock(dev, 2500);
|
||||
|
||||
iic_reset_bus(dev);
|
||||
|
||||
rSMSTA(dev->bus) = 0xffffffff;
|
||||
rIMASK(dev->bus) = 0;
|
||||
}
|
||||
|
||||
static void iic_set_clock(struct iic_device *dev, u_int32_t period)
|
||||
{
|
||||
u_int32_t source;
|
||||
u_int32_t target_Hz;
|
||||
unsigned div;
|
||||
|
||||
/* Obey the minimum supported by the block */
|
||||
div = kS5L8940XIICMIXDIV;
|
||||
/* There's a built-in divide by 16 */
|
||||
source = (clock_get_frequency(dev->clk)) >> 4;
|
||||
target_Hz = 1000000000 / period;
|
||||
while (source > (target_Hz * div))
|
||||
div++;
|
||||
rCTL(dev->bus) = kS5L8940XIICCTLCLK(div) | kS5L8940XIICCTLUJM;
|
||||
dprintf(DEBUG_INFO, "iic_set_clock(%d) = %d\n", dev->bus, div);
|
||||
}
|
||||
|
||||
static void iic_reset_bus(struct iic_device *dev)
|
||||
{
|
||||
u_int32_t cnt;
|
||||
|
||||
// Write 00 so all devices will complete any partial transaction
|
||||
// SDA starts low and goes high after the loop
|
||||
// SCL start and ends the loop high
|
||||
// The first and last iterations of the loop produce the
|
||||
// start and stop conditions
|
||||
|
||||
gpio_configure(dev->gpio_sda, GPIO_CFG_OUT_0);
|
||||
|
||||
for (cnt = 0; cnt < (2 * 9 + 1); cnt++) {
|
||||
gpio_configure(dev->gpio_scl, (cnt & 1) ? GPIO_CFG_OUT_0 : GPIO_CFG_IN);
|
||||
spin(5);
|
||||
}
|
||||
|
||||
gpio_configure(dev->gpio_scl, GPIO_CFG_FUNC0);
|
||||
gpio_configure(dev->gpio_sda, GPIO_CFG_FUNC0);
|
||||
|
||||
rCTL(dev->bus) = rCTL(dev->bus) | kS5L8940XIICCTLMRR | kS5L8940XIICCTLMTR;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __APPLE_IIC_H
|
||||
#define __APPLE_IIC_H
|
||||
|
||||
#include <platform/gpio.h>
|
||||
#include <platform/soc/hwregbase.h>
|
||||
|
||||
#define rMTXFIFO(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x00))
|
||||
#define rMRXFIFO(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x04))
|
||||
#define rMCNT(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x08))
|
||||
#define rXFSTA(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x0C))
|
||||
#define rSMSTA(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x14))
|
||||
#define rIMASK(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x18))
|
||||
#define rCTL(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x1C))
|
||||
#define rVERSION(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x28))
|
||||
#define rFILTER(_i) (*(volatile u_int32_t *)(IIC_BASE_ADDR + ((_i) * IIC_SPACING) + 0x38))
|
||||
|
||||
#define kS5L8940XIICMTXFIFOWrite (0 << 10)
|
||||
#define kS5L8940XIICMTXFIFORead (1 << 10)
|
||||
#define kS5L8940XIICMTXFIFOStop (1 << 9)
|
||||
#define kS5L8940XIICMTXFIFOStart (1 << 8)
|
||||
#define kS5L8940XIICMTXFIFOData(_d) (((_d) & 0xff) << 0)
|
||||
|
||||
#define kS5L8940XIICMRXFIFOEmpty (1 << 8)
|
||||
#define kS5L8940XIICMRXFIFOData(_v) (((_v) >> 0) & 0xff)
|
||||
|
||||
#define kS5L8940XIICMCNTRxCnt(_v) (((_v) >> 8) & 0xff)
|
||||
#define kS5L8940XIICMCNTTxCnt(_v) (((_v) >> 0) & 0xff)
|
||||
|
||||
#define kS5L8940XIICXFSTAmst(_v) (((_v) >> 28) & 0xf)
|
||||
#define kS5L8940XIIC_IDLE 0
|
||||
#define kS5L8940XIICXFSTAxfifo(_v) (((_v) >> 21) & 0x3)
|
||||
#define kS5L8940XIICXFSTAxcnt(_v) (((_v) >> 0) & 0xfffff)
|
||||
|
||||
#define kS5L8940XIICSMSTAxip (1 << 28)
|
||||
#define kS5L8940XIICSMSTAxen (1 << 27)
|
||||
#define kS5L8940XIICSMSTAujf (1 << 26)
|
||||
#define kS5L8940XIICSMSTAjmd (1 << 25)
|
||||
#define kS5L8940XIICSMSTAjam (1 << 24)
|
||||
#define kS5L8940XIICSMSTAmto (1 << 23)
|
||||
#define kS5L8940XIICSMSTAmtn (1 << 21)
|
||||
#define kS5L8940XIICSMSTAmrf (1 << 20)
|
||||
#define kS5L8940XIICSMSTAmrne (1 << 19)
|
||||
#define kS5L8940XIICSMSTAmtr (1 << 18)
|
||||
#define kS5L8940XIICSMSTAmtf (1 << 17)
|
||||
#define kS5L8940XIICSMSTAmte (1 << 16)
|
||||
#define kS5L8940XIICSMSTAtom (1 << 6)
|
||||
|
||||
#define kS5L8940XIICCTLMRR (1 << 10)
|
||||
#define kS5L8940XIICCTLMTR (1 << 9)
|
||||
#define kS5L8940XIICCTLUJM (1 << 8)
|
||||
#define kS5L8940XIICCTLCLK(_c) (((_c) & 0xff) << 0)
|
||||
|
||||
#define kS5L8940XIICMIXDIV 4
|
||||
|
||||
struct iic_device {
|
||||
int bus;
|
||||
int clk;
|
||||
int irq;
|
||||
bool busy;
|
||||
gpio_t gpio_scl;
|
||||
gpio_t gpio_sda;
|
||||
};
|
||||
|
||||
#endif /* ! __APPLE_IIC_H */
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_HW_IIC=1
|
||||
|
||||
MODULES += \
|
||||
drivers/iic
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/iic.o
|
||||
Reference in new issue
Block a user