ipq806x: copy i2c, qup, and gsbi drivers from depthcharge
this is a preparation for porting these drivers to coreboot. the code will be modified by the following patches. BUG=chrome-os-partner:33647 BRANCH=ToT TEST=None Change-Id: I2baeed5b6130ace2515d6e28115f8d1008004976 Signed-off-by: Stefan Reinauer <reinauer@chromium.org> Original-Commit-Id: 7c03a186a599be9d274c6fcdea1906529cc117d7 Original-Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Original-Change-Id: I9f3428ef02d2ba15ae63c99b10fe0605dd595313 Original-Reviewed-on: https://chromium-review.googlesource.com/231461 Original-Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Original-Commit-Queue: Vadim Bendebury <vbendeb@chromium.org> Original-Tested-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: http://review.coreboot.org/9582 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
This commit is contained in:
parent
4488590fd2
commit
0594914dec
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the depthcharge project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include "drivers/gpio/ipq806x.h"
|
||||||
|
#include "ipq806x_gsbi.h"
|
||||||
|
|
||||||
|
//TODO: To be implemented as part of the iomap.
|
||||||
|
static int gsbi_base[] = {
|
||||||
|
0x12440000, /*GSBI1*/
|
||||||
|
0x12480000, /*GSBI2*/
|
||||||
|
0x16200000, /*GSBI3*/
|
||||||
|
0x16300000, /*GSBI4*/
|
||||||
|
0x1A200000, /*GSBI5*/
|
||||||
|
0x16500000, /*GSBI6*/
|
||||||
|
0x16600000 /*GSBI7*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QUP_APPS_ADDR(N, os) ((void *)((0x009029C8+os)+(32*(N-1))))
|
||||||
|
#define GSBI_HCLK_CTL(N) ((void *)(0x009029C0 + (32*(N-1))))
|
||||||
|
#define GSBI_RESET(N) ((void *)(0x009029DC + (32*(N-1))))
|
||||||
|
#define GSBI_CTL(N) ((void *)(gsbi_base[N-1]))
|
||||||
|
|
||||||
|
#define GSBI_APPS_MD_OFFSET 0x0
|
||||||
|
#define GSBI_APPS_NS_OFFSET 0x4
|
||||||
|
#define GSBI_APPS_MAX_OFFSET 0xff
|
||||||
|
|
||||||
|
#define GPIO_FUNC_I2C 0x1
|
||||||
|
|
||||||
|
gsbi_return_t gsbi_init(gsbi_id_t gsbi_id, gsbi_protocol_t protocol)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
unsigned qup_apps_ini[] = {
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xf80b43,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc095b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc015b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc005b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xA05,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0x185,
|
||||||
|
GSBI_APPS_MD_OFFSET, 0x100fb,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xA05,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc015b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc015b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc095b,
|
||||||
|
GSBI_APPS_NS_OFFSET, 0xfc0b5b,
|
||||||
|
GSBI_APPS_MAX_OFFSET, 0x0
|
||||||
|
};
|
||||||
|
|
||||||
|
gsbi_return_t ret = GSBI_SUCCESS;
|
||||||
|
|
||||||
|
writel(0, GSBI_RESET(gsbi_id));
|
||||||
|
|
||||||
|
switch (gsbi_id) {
|
||||||
|
case GSBI_ID_4: {
|
||||||
|
/* Configure GPIOs 13 - SCL, 12 - SDA, 2mA gpio_en */
|
||||||
|
gpio_tlmm_config_set(12, GPIO_FUNC_I2C,
|
||||||
|
GPIO_NO_PULL, GPIO_2MA, 1);
|
||||||
|
gpio_tlmm_config_set(13, GPIO_FUNC_I2C,
|
||||||
|
GPIO_NO_PULL, GPIO_2MA, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GSBI_ID_1: {
|
||||||
|
/* Configure GPIOs 54 - SCL, 53 - SDA, 2mA gpio_en */
|
||||||
|
gpio_tlmm_config_set(54, GPIO_FUNC_I2C,
|
||||||
|
GPIO_NO_PULL, GPIO_2MA, 1);
|
||||||
|
gpio_tlmm_config_set(53, GPIO_FUNC_I2C,
|
||||||
|
GPIO_NO_PULL, GPIO_2MA, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
ret = GSBI_UNSUPPORTED;
|
||||||
|
goto bail_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Select i2c protocol*/
|
||||||
|
writel((2 << 4), GSBI_CTL(gsbi_id));
|
||||||
|
|
||||||
|
//TODO: Make use of clock API when available instead of the hardcoding.
|
||||||
|
/* Clock set to 24Mhz */
|
||||||
|
for (i = 0; GSBI_APPS_MAX_OFFSET != qup_apps_ini[i]; i += 2)
|
||||||
|
writel(qup_apps_ini[i+1],
|
||||||
|
QUP_APPS_ADDR(gsbi_id, qup_apps_ini[i]));
|
||||||
|
|
||||||
|
writel(((1 << 6)|(1 << 4)), GSBI_HCLK_CTL(gsbi_id));
|
||||||
|
|
||||||
|
bail_out:
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the depthcharge project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GSBI_TYPES_H__
|
||||||
|
#define __GSBI_TYPES_H__
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GSBI_ID_1 = 1,
|
||||||
|
GSBI_ID_2,
|
||||||
|
GSBI_ID_3,
|
||||||
|
GSBI_ID_4,
|
||||||
|
GSBI_ID_5,
|
||||||
|
GSBI_ID_6,
|
||||||
|
GSBI_ID_7,
|
||||||
|
} gsbi_id_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GSBI_SUCCESS = 0,
|
||||||
|
GSBI_ID_ERROR,
|
||||||
|
GSBI_ERROR,
|
||||||
|
GSBI_UNSUPPORTED
|
||||||
|
} gsbi_return_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GSBI_PROTO_I2C_UIM = 1,
|
||||||
|
GSBI_PROTO_I2C_ONLY,
|
||||||
|
GSBI_PROTO_SPI_ONLY,
|
||||||
|
GSBI_PROTO_UART_FLOW_CTL,
|
||||||
|
GSBI_PROTO_UIM,
|
||||||
|
GSBI_PROTO_I2C_UART,
|
||||||
|
} gsbi_protocol_t;
|
||||||
|
|
||||||
|
gsbi_return_t gsbi_init(gsbi_id_t gsbi_id, gsbi_protocol_t protocol);
|
||||||
|
#endif
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the depthcharge project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <libpayload.h>
|
||||||
|
|
||||||
|
#include "base/container_of.h"
|
||||||
|
#include "drivers/bus/i2c/i2c.h"
|
||||||
|
#include "drivers/bus/i2c/ipq806x_qup.h"
|
||||||
|
#include "drivers/bus/i2c/ipq806x_gsbi.h"
|
||||||
|
#include "drivers/bus/i2c/ipq806x.h"
|
||||||
|
|
||||||
|
static int i2c_init(unsigned gsbi_id)
|
||||||
|
{
|
||||||
|
gsbi_return_t gsbi_ret = 0;
|
||||||
|
qup_return_t qup_ret = 0;
|
||||||
|
qup_config_t gsbi4_qup_config = {
|
||||||
|
QUP_MINICORE_I2C_MASTER,
|
||||||
|
100000,
|
||||||
|
24000000,
|
||||||
|
QUP_MODE_FIFO
|
||||||
|
};
|
||||||
|
|
||||||
|
gsbi_ret = gsbi_init(gsbi_id, GSBI_PROTO_I2C_ONLY);
|
||||||
|
if (GSBI_SUCCESS != gsbi_ret)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
qup_ret = qup_init(gsbi_id, &gsbi4_qup_config);
|
||||||
|
if (QUP_SUCCESS != qup_ret)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
qup_ret = qup_reset_i2c_master_status(gsbi_id);
|
||||||
|
if (QUP_SUCCESS != qup_ret)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_read(uint32_t gsbi_id, uint8_t slave,
|
||||||
|
uint8_t *data, int data_len)
|
||||||
|
{
|
||||||
|
qup_data_t obj;
|
||||||
|
qup_return_t qup_ret = 0;
|
||||||
|
|
||||||
|
memset(&obj, 0, sizeof(obj));
|
||||||
|
obj.protocol = QUP_MINICORE_I2C_MASTER;
|
||||||
|
obj.p.iic.addr = slave;
|
||||||
|
obj.p.iic.data_len = data_len;
|
||||||
|
obj.p.iic.data = data;
|
||||||
|
qup_ret = qup_recv_data(gsbi_id, &obj);
|
||||||
|
|
||||||
|
if (QUP_SUCCESS != qup_ret)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_write(uint32_t gsbi_id, uint8_t slave,
|
||||||
|
uint8_t *data, int data_len, uint8_t stop_seq)
|
||||||
|
{
|
||||||
|
qup_data_t obj;
|
||||||
|
qup_return_t qup_ret = 0;
|
||||||
|
|
||||||
|
memset(&obj, 0, sizeof(obj));
|
||||||
|
obj.protocol = QUP_MINICORE_I2C_MASTER;
|
||||||
|
obj.p.iic.addr = slave;
|
||||||
|
obj.p.iic.data_len = data_len;
|
||||||
|
obj.p.iic.data = data;
|
||||||
|
qup_ret = qup_send_data(gsbi_id, &obj, stop_seq);
|
||||||
|
|
||||||
|
if (QUP_SUCCESS != qup_ret)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_transfer(struct I2cOps *me, I2cSeg *segments, int seg_count)
|
||||||
|
{
|
||||||
|
Ipq806xI2c *bus = container_of(me, Ipq806xI2c, ops);
|
||||||
|
I2cSeg *seg = segments;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!bus->initialized)
|
||||||
|
if (0 != i2c_init(bus->gsbi_id))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (seg_count--) {
|
||||||
|
if (seg->read)
|
||||||
|
ret = i2c_read(bus->gsbi_id, seg->chip,
|
||||||
|
seg->buf, seg->len);
|
||||||
|
else
|
||||||
|
ret = i2c_write(bus->gsbi_id, seg->chip,
|
||||||
|
seg->buf, seg->len,
|
||||||
|
(seg_count ? 0 : 1));
|
||||||
|
seg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QUP_SUCCESS != ret) {
|
||||||
|
qup_set_state(bus->gsbi_id, QUP_STATE_RESET);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ipq806xI2c *new_ipq806x_i2c(unsigned gsbi_id)
|
||||||
|
{
|
||||||
|
Ipq806xI2c *bus = 0;
|
||||||
|
|
||||||
|
if (!i2c_init(gsbi_id)) {
|
||||||
|
bus = xzalloc(sizeof(*bus));
|
||||||
|
bus->gsbi_id = gsbi_id;
|
||||||
|
bus->initialized = 1;
|
||||||
|
bus->ops.transfer = &i2c_transfer;
|
||||||
|
}
|
||||||
|
return bus;
|
||||||
|
}
|
|
@ -0,0 +1,483 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the depthcharge project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <libpayload.h>
|
||||||
|
#include "ipq806x_qup.h"
|
||||||
|
|
||||||
|
//TODO: refactor the following array to iomap driver.
|
||||||
|
static unsigned gsbi_qup_base[] = {
|
||||||
|
0x12460000, /*gsbi 1*/
|
||||||
|
0x124A0000, /*gsbi 2*/
|
||||||
|
0x16280000, /*gsbi 3*/
|
||||||
|
0x16380000, /*gsbi 4*/
|
||||||
|
0x1A280000, /*gsbi 5*/
|
||||||
|
0x16580000, /*gsbi 6*/
|
||||||
|
0x16680000, /*gsbi 7*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QUP_ADDR(gsbi_num, reg) ((void *)((gsbi_qup_base[gsbi_num-1]) + (reg)))
|
||||||
|
#define MAX_DELAY_MS 100
|
||||||
|
|
||||||
|
static char *get_error_string(qup_return_t error)
|
||||||
|
{
|
||||||
|
char *msg;
|
||||||
|
switch (error) {
|
||||||
|
case QUP_ERR_BAD_PARAM:
|
||||||
|
msg = "bad parameter";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_STATE_SET:
|
||||||
|
msg = "setting state failed";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_TIMEOUT:
|
||||||
|
msg = "timeout";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_UNSUPPORTED:
|
||||||
|
msg = "unsupported";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_I2C_INVALID_SLAVE_ADDR:
|
||||||
|
msg = "invalid slave address";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_XFER_FAIL:
|
||||||
|
msg = "transfer failed";
|
||||||
|
break;
|
||||||
|
case QUP_ERR_UNDEFINED:
|
||||||
|
default:
|
||||||
|
msg = "undefined";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qup_return_t qup_i2c_master_status(gsbi_id_t gsbi_id)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_SUCCESS;
|
||||||
|
uint32_t reg_val = readl(QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS));
|
||||||
|
|
||||||
|
if (readl(QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS)))
|
||||||
|
ret = QUP_ERR_XFER_FAIL;
|
||||||
|
else if (reg_val & QUP_I2C_INVALID_READ_ADDR)
|
||||||
|
ret = QUP_ERR_I2C_INVALID_SLAVE_ADDR;
|
||||||
|
else if (reg_val & (QUP_I2C_FAILED_MASK |
|
||||||
|
QUP_I2C_ARB_LOST |
|
||||||
|
QUP_I2C_BUS_ERROR))
|
||||||
|
ret = QUP_ERR_XFER_FAIL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qup_return_t qup_wait_for_state(gsbi_id_t gsbi_id, unsigned wait_for)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_STATE_SET;
|
||||||
|
uint32_t val = 0;
|
||||||
|
uint32_t start_ts;
|
||||||
|
uint32_t d = MAX_DELAY_MS * timer_hz() / 1000;
|
||||||
|
uint8_t final_state = 0;
|
||||||
|
|
||||||
|
start_ts = timer_raw_value();
|
||||||
|
do {
|
||||||
|
val = readl(QUP_ADDR(gsbi_id, QUP_STATE));
|
||||||
|
final_state = ((val & (QUP_STATE_VALID_MASK|QUP_STATE_MASK))
|
||||||
|
== (QUP_STATE_VALID|wait_for));
|
||||||
|
} while ((!final_state) && (start_ts > (timer_raw_value() - d)));
|
||||||
|
|
||||||
|
if (final_state)
|
||||||
|
ret = QUP_SUCCESS;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qup_return_t qup_i2c_write(gsbi_id_t gsbi_id, uint8_t mode,
|
||||||
|
qup_data_t *p_tx_obj, uint8_t stop_seq)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
uint32_t start_ts;
|
||||||
|
uint32_t d = MAX_DELAY_MS * timer_hz() / 1000;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case QUP_MODE_FIFO: {
|
||||||
|
uint8_t addr = p_tx_obj->p.iic.addr;
|
||||||
|
uint8_t *data_ptr = p_tx_obj->p.iic.data;
|
||||||
|
unsigned data_len = p_tx_obj->p.iic.data_len;
|
||||||
|
unsigned idx = 0;
|
||||||
|
|
||||||
|
writel(0x7C, QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS));
|
||||||
|
writel(0x7C, QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS_EN));
|
||||||
|
qup_reset_i2c_master_status(gsbi_id);
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_RUN);
|
||||||
|
|
||||||
|
writel((QUP_I2C_START_SEQ | QUP_I2C_ADDR(addr)),
|
||||||
|
QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO));
|
||||||
|
|
||||||
|
while (data_len) {
|
||||||
|
if (data_len == 1 && stop_seq) {
|
||||||
|
writel((QUP_I2C_STOP_SEQ |
|
||||||
|
QUP_I2C_DATA(data_ptr[idx])),
|
||||||
|
QUP_ADDR(gsbi_id,
|
||||||
|
QUP_OUTPUT_FIFO));
|
||||||
|
} else {
|
||||||
|
writel((QUP_I2C_DATA_SEQ |
|
||||||
|
QUP_I2C_DATA(data_ptr[idx])),
|
||||||
|
QUP_ADDR(gsbi_id,
|
||||||
|
QUP_OUTPUT_FIFO));
|
||||||
|
}
|
||||||
|
data_len--;
|
||||||
|
idx++;
|
||||||
|
start_ts = timer_raw_value();
|
||||||
|
while (data_len && readl(QUP_ADDR(gsbi_id,
|
||||||
|
QUP_OPERATIONAL)) &
|
||||||
|
OUTPUT_FIFO_FULL) {
|
||||||
|
ret = qup_i2c_master_status(gsbi_id);
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
goto bailout;
|
||||||
|
if (start_ts < (timer_raw_value() - d)) {
|
||||||
|
ret = QUP_ERR_TIMEOUT;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Hardware sets the OUTPUT_SERVICE_FLAG flag to 1 when
|
||||||
|
OUTPUT_FIFO_NOT_EMPTY flag in the QUP_OPERATIONAL
|
||||||
|
register changes from 1 to 0, indicating that software
|
||||||
|
can write more data to the output FIFO. Software should
|
||||||
|
set OUTPUT_SERVICE_FLAG to 1 to clear it to 0, which
|
||||||
|
means that software knows to return to fill the output
|
||||||
|
FIFO with data.
|
||||||
|
*/
|
||||||
|
if (readl(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) &
|
||||||
|
OUTPUT_SERVICE_FLAG) {
|
||||||
|
writel(OUTPUT_SERVICE_FLAG,
|
||||||
|
QUP_ADDR(gsbi_id,
|
||||||
|
QUP_OPERATIONAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start_ts = timer_raw_value();
|
||||||
|
while (((readl(QUP_ADDR(gsbi_id, QUP_OPERATIONAL))) &
|
||||||
|
OUTPUT_FIFO_NOT_EMPTY)) {
|
||||||
|
ret = qup_i2c_master_status(gsbi_id);
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
goto bailout;
|
||||||
|
if (start_ts < (timer_raw_value() - d)) {
|
||||||
|
ret = QUP_ERR_TIMEOUT;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_PAUSE);
|
||||||
|
ret = QUP_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
if (QUP_SUCCESS != ret) {
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_RESET);
|
||||||
|
printf("%s() returns %s\n", __func__, get_error_string(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qup_return_t qup_i2c_read(gsbi_id_t gsbi_id, uint8_t mode,
|
||||||
|
qup_data_t *p_tx_obj)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
uint32_t start_ts;
|
||||||
|
uint32_t d = MAX_DELAY_MS * timer_hz() / 1000;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case QUP_MODE_FIFO: {
|
||||||
|
uint8_t addr = p_tx_obj->p.iic.addr;
|
||||||
|
uint8_t *data_ptr = p_tx_obj->p.iic.data;
|
||||||
|
unsigned data_len = p_tx_obj->p.iic.data_len;
|
||||||
|
unsigned idx = 0;
|
||||||
|
|
||||||
|
writel(0x7C, QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS));
|
||||||
|
writel(0x7C, QUP_ADDR(gsbi_id, QUP_ERROR_FLAGS_EN));
|
||||||
|
qup_reset_i2c_master_status(gsbi_id);
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_RUN);
|
||||||
|
|
||||||
|
writel((QUP_I2C_START_SEQ |
|
||||||
|
(QUP_I2C_ADDR(addr)|
|
||||||
|
QUP_I2C_SLAVE_READ)),
|
||||||
|
QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO));
|
||||||
|
|
||||||
|
writel((QUP_I2C_RECV_SEQ | data_len),
|
||||||
|
QUP_ADDR(gsbi_id, QUP_OUTPUT_FIFO));
|
||||||
|
|
||||||
|
start_ts = timer_raw_value();
|
||||||
|
while ((readl(QUP_ADDR(gsbi_id, QUP_OPERATIONAL)) &
|
||||||
|
OUTPUT_FIFO_NOT_EMPTY)) {
|
||||||
|
ret = qup_i2c_master_status(gsbi_id);
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
goto bailout;
|
||||||
|
if (start_ts < (timer_raw_value() - d)) {
|
||||||
|
ret = QUP_ERR_TIMEOUT;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(OUTPUT_SERVICE_FLAG,
|
||||||
|
QUP_ADDR(gsbi_id, QUP_OPERATIONAL));
|
||||||
|
|
||||||
|
while (data_len) {
|
||||||
|
unsigned data;
|
||||||
|
start_ts = timer_raw_value();
|
||||||
|
while ((!((readl(QUP_ADDR(gsbi_id, QUP_OPERATIONAL))) &
|
||||||
|
INPUT_SERVICE_FLAG))) {
|
||||||
|
ret = qup_i2c_master_status(gsbi_id);
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
goto bailout;
|
||||||
|
if (start_ts < (timer_raw_value() - d)) {
|
||||||
|
ret = QUP_ERR_TIMEOUT;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = readl(QUP_ADDR(gsbi_id, QUP_INPUT_FIFO));
|
||||||
|
|
||||||
|
/*Process tag and corresponding data value.
|
||||||
|
For I2C master mini-core, data in FIFO is composed of
|
||||||
|
16 bits and is divided into an 8-bit tag for the upper
|
||||||
|
bits and 8-bit data for the lower bits.
|
||||||
|
The 8-bit tag indicates whether the byte is the last
|
||||||
|
byte, or if a bus error happened during the receipt of
|
||||||
|
the byte.*/
|
||||||
|
if ((QUP_I2C_MI_TAG(data)) == QUP_I2C_MIDATA_SEQ) {
|
||||||
|
/* Tag: MIDATA = Master input data.*/
|
||||||
|
data_ptr[idx] = QUP_I2C_DATA(data);
|
||||||
|
idx++;
|
||||||
|
data_len--;
|
||||||
|
writel(INPUT_SERVICE_FLAG, QUP_ADDR(gsbi_id,
|
||||||
|
QUP_OPERATIONAL));
|
||||||
|
} else if (QUP_I2C_MI_TAG(data) ==
|
||||||
|
QUP_I2C_MISTOP_SEQ) {
|
||||||
|
/* Tag: MISTOP: Last byte of master input. */
|
||||||
|
data_ptr[idx] = QUP_I2C_DATA(data);
|
||||||
|
idx++;
|
||||||
|
data_len--;
|
||||||
|
goto recv_done;
|
||||||
|
} else {
|
||||||
|
/* Tag: MINACK: Invalid master input data.*/
|
||||||
|
goto recv_done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recv_done:
|
||||||
|
writel(INPUT_SERVICE_FLAG,
|
||||||
|
QUP_ADDR(gsbi_id, QUP_OPERATIONAL));
|
||||||
|
p_tx_obj->p.iic.data_len = idx;
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_PAUSE);
|
||||||
|
ret = QUP_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
if (QUP_SUCCESS != ret) {
|
||||||
|
qup_set_state(gsbi_id, QUP_STATE_RESET);
|
||||||
|
printf("%s() returns %s\n", __func__, get_error_string(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_return_t qup_init(gsbi_id_t gsbi_id, qup_config_t *config_ptr)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
uint32_t reg_val;
|
||||||
|
|
||||||
|
/* Reset the QUP core.*/
|
||||||
|
writel(0x1, QUP_ADDR(gsbi_id, QUP_SW_RESET));
|
||||||
|
|
||||||
|
/*Wait till the reset takes effect */
|
||||||
|
ret = qup_wait_for_state(gsbi_id, QUP_STATE_RESET);
|
||||||
|
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*Reset the config*/
|
||||||
|
writel(0, QUP_ADDR(gsbi_id, QUP_CONFIG));
|
||||||
|
|
||||||
|
/*Program the config register*/
|
||||||
|
/*Set N value*/
|
||||||
|
reg_val = 0x0F;
|
||||||
|
/*Set protocol*/
|
||||||
|
switch (config_ptr->protocol) {
|
||||||
|
case QUP_MINICORE_I2C_MASTER: {
|
||||||
|
reg_val |= ((config_ptr->protocol &
|
||||||
|
QUP_MINI_CORE_PROTO_MASK) <<
|
||||||
|
QUP_MINI_CORE_PROTO_SHFT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writel(reg_val, QUP_ADDR(gsbi_id, QUP_CONFIG));
|
||||||
|
|
||||||
|
/*Reset i2c clk cntl register*/
|
||||||
|
writel(0, QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL));
|
||||||
|
|
||||||
|
/*Set QUP IO Mode*/
|
||||||
|
switch (config_ptr->mode) {
|
||||||
|
case QUP_MODE_FIFO: {
|
||||||
|
reg_val = QUP_OUTPUT_BIT_SHIFT_EN |
|
||||||
|
((config_ptr->mode & QUP_MODE_MASK) <<
|
||||||
|
QUP_OUTPUT_MODE_SHFT) |
|
||||||
|
((config_ptr->mode & QUP_MODE_MASK) <<
|
||||||
|
QUP_INPUT_MODE_SHFT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writel(reg_val, QUP_ADDR(gsbi_id, QUP_IO_MODES));
|
||||||
|
|
||||||
|
/*Set i2c clk cntl*/
|
||||||
|
reg_val = (QUP_DIVIDER_MIN_VAL << QUP_HS_DIVIDER_SHFT);
|
||||||
|
reg_val |= ((((config_ptr->src_frequency / config_ptr->clk_frequency)
|
||||||
|
/ 2) - QUP_DIVIDER_MIN_VAL) &
|
||||||
|
QUP_FS_DIVIDER_MASK);
|
||||||
|
writel(reg_val, QUP_ADDR(gsbi_id, QUP_I2C_MASTER_CLK_CTL));
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
if (QUP_SUCCESS != ret)
|
||||||
|
printf("%s() returns %s\n", __func__, get_error_string(ret));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_return_t qup_set_state(gsbi_id_t gsbi_id, uint32_t state)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
unsigned curr_state = readl(QUP_ADDR(gsbi_id, QUP_STATE));
|
||||||
|
|
||||||
|
if ((state >= QUP_STATE_RESET && state <= QUP_STATE_PAUSE)
|
||||||
|
&& (curr_state & QUP_STATE_VALID_MASK)) {
|
||||||
|
/*
|
||||||
|
* For PAUSE_STATE to RESET_STATE transition,
|
||||||
|
* two writes of 10[binary]) are required for the
|
||||||
|
* transition to complete.
|
||||||
|
*/
|
||||||
|
if (QUP_STATE_PAUSE == curr_state &&
|
||||||
|
QUP_STATE_RESET == state) {
|
||||||
|
writel(0x2, QUP_ADDR(gsbi_id, QUP_STATE));
|
||||||
|
writel(0x2, QUP_ADDR(gsbi_id, QUP_STATE));
|
||||||
|
} else {
|
||||||
|
writel(state, QUP_ADDR(gsbi_id, QUP_STATE));
|
||||||
|
}
|
||||||
|
ret = qup_wait_for_state(gsbi_id, state);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_return_t qup_reset_i2c_master_status(gsbi_id_t gsbi_id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Writing a one clears the status bits.
|
||||||
|
* Bit31-25, Bit1 and Bit0 are reserved.
|
||||||
|
*/
|
||||||
|
//TODO: Define each status bit. OR all status bits in a single macro.
|
||||||
|
writel(0x3FFFFFC, QUP_ADDR(gsbi_id, QUP_I2C_MASTER_STATUS));
|
||||||
|
return QUP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_return_t qup_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj,
|
||||||
|
uint8_t stop_seq)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
|
||||||
|
if (p_tx_obj->protocol == ((readl(QUP_ADDR(gsbi_id, QUP_CONFIG)) >>
|
||||||
|
QUP_MINI_CORE_PROTO_SHFT) &
|
||||||
|
QUP_MINI_CORE_PROTO_MASK)) {
|
||||||
|
switch (p_tx_obj->protocol) {
|
||||||
|
case QUP_MINICORE_I2C_MASTER: {
|
||||||
|
uint8_t mode = (readl(QUP_ADDR(gsbi_id,
|
||||||
|
QUP_IO_MODES)) >>
|
||||||
|
QUP_OUTPUT_MODE_SHFT) &
|
||||||
|
QUP_MODE_MASK;
|
||||||
|
ret = qup_i2c_write(gsbi_id, mode, p_tx_obj, stop_seq);
|
||||||
|
if (0) {
|
||||||
|
int i;
|
||||||
|
printf("i2c tx bus %d device %2.2x:",
|
||||||
|
gsbi_id, p_tx_obj->p.iic.addr);
|
||||||
|
for (i = 0; i < p_tx_obj->p.iic.data_len; i++)
|
||||||
|
printf(" %2.2x",
|
||||||
|
p_tx_obj->p.iic.data[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qup_return_t qup_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_rx_obj)
|
||||||
|
{
|
||||||
|
qup_return_t ret = QUP_ERR_UNDEFINED;
|
||||||
|
if (p_rx_obj->protocol == ((readl(QUP_ADDR(gsbi_id, QUP_CONFIG)) >>
|
||||||
|
QUP_MINI_CORE_PROTO_SHFT) &
|
||||||
|
QUP_MINI_CORE_PROTO_MASK)) {
|
||||||
|
switch (p_rx_obj->protocol) {
|
||||||
|
case QUP_MINICORE_I2C_MASTER: {
|
||||||
|
uint8_t mode = (readl(QUP_ADDR(gsbi_id,
|
||||||
|
QUP_IO_MODES)) >>
|
||||||
|
QUP_INPUT_MODE_SHFT) &
|
||||||
|
QUP_MODE_MASK;
|
||||||
|
ret = qup_i2c_read(gsbi_id, mode, p_rx_obj);
|
||||||
|
if (0) {
|
||||||
|
int i;
|
||||||
|
printf("i2c rxed on bus %d device %2.2x:",
|
||||||
|
gsbi_id, p_rx_obj->p.iic.addr);
|
||||||
|
for (i = 0; i < p_rx_obj->p.iic.data_len; i++)
|
||||||
|
printf(" %2.2x",
|
||||||
|
p_rx_obj->p.iic.data[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ret = QUP_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the depthcharge project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __QUP_H__
|
||||||
|
#define __QUP_H__
|
||||||
|
#include "ipq806x_gsbi.h"
|
||||||
|
|
||||||
|
/* QUP block registers */
|
||||||
|
#define QUP_CONFIG 0x0
|
||||||
|
#define QUP_STATE 0x4
|
||||||
|
#define QUP_IO_MODES 0x8
|
||||||
|
#define QUP_SW_RESET 0xc
|
||||||
|
#define QUP_TIME_OUT 0x10
|
||||||
|
#define QUP_TIME_OUT_CURRENT 0x14
|
||||||
|
#define QUP_OPERATIONAL 0x18
|
||||||
|
#define QUP_ERROR_FLAGS 0x1c
|
||||||
|
#define QUP_ERROR_FLAGS_EN 0x20
|
||||||
|
#define QUP_TEST_CTRL 0x24
|
||||||
|
#define QUP_MX_OUTPUT_COUNT 0x100
|
||||||
|
#define QUP_MX_OUTPUT_CNT_CURRENT 0x104
|
||||||
|
#define QUP_OUTPUT_DEBUG 0x108
|
||||||
|
#define QUP_OUTPUT_FIFO_WORD_CNT 0x10c
|
||||||
|
#define QUP_OUTPUT_FIFO 0x110
|
||||||
|
#define QUP_MX_WRITE_COUNT 0x150
|
||||||
|
#define QUP_WRITE_CNT_CURRENT 0x154
|
||||||
|
#define QUP_MX_INPUT_COUNT 0x200
|
||||||
|
#define QUP_READ_COUNT 0x208
|
||||||
|
#define QUP_MX_READ_CNT_CURRENT 0x20c
|
||||||
|
#define QUP_INPUT_DEBUG 0x210
|
||||||
|
#define QUP_INPUT_FIFO_WORD_CNT 0x214
|
||||||
|
#define QUP_INPUT_FIFO 0x218
|
||||||
|
#define QUP_I2C_MASTER_CLK_CTL 0x400
|
||||||
|
#define QUP_I2C_MASTER_STATUS 0x404
|
||||||
|
|
||||||
|
#define OUTPUT_FIFO_FULL (1<<6)
|
||||||
|
#define INPUT_FIFO_NOT_EMPTY (1<<5)
|
||||||
|
#define OUTPUT_FIFO_NOT_EMPTY (1<<4)
|
||||||
|
#define INPUT_SERVICE_FLAG (1<<9)
|
||||||
|
#define OUTPUT_SERVICE_FLAG (1<<8)
|
||||||
|
#define QUP_OUTPUT_BIT_SHIFT_EN (1<<16)
|
||||||
|
|
||||||
|
#define QUP_MODE_MASK (0x03)
|
||||||
|
#define QUP_OUTPUT_MODE_SHFT (10)
|
||||||
|
#define QUP_INPUT_MODE_SHFT (12)
|
||||||
|
|
||||||
|
#define QUP_FS_DIVIDER_MASK (0xFF)
|
||||||
|
|
||||||
|
#define QUP_MINI_CORE_PROTO_SHFT (8)
|
||||||
|
#define QUP_MINI_CORE_PROTO_MASK (0x0F)
|
||||||
|
|
||||||
|
/* Mini-core states */
|
||||||
|
#define QUP_STATE_RESET 0x0
|
||||||
|
#define QUP_STATE_RUN 0x1
|
||||||
|
#define QUP_STATE_PAUSE 0x3
|
||||||
|
#define QUP_STATE_VALID (1<<2)
|
||||||
|
#define QUP_STATE_MASK 0x3
|
||||||
|
#define QUP_STATE_VALID_MASK (1<<2)
|
||||||
|
|
||||||
|
/* Tags for output FIFO */
|
||||||
|
#define QUP_I2C_1CLK_NOOP_SEQ 0x1 /*MSB 8-bit NOP, LSB 8-bits 1 clk.*/
|
||||||
|
#define QUP_I2C_START_SEQ (0x1 << 8)
|
||||||
|
#define QUP_I2C_DATA_SEQ (0x2 << 8)
|
||||||
|
#define QUP_I2C_STOP_SEQ (0x3 << 8)
|
||||||
|
#define QUP_I2C_RECV_SEQ (0x4 << 8)
|
||||||
|
|
||||||
|
/* Tags for input FIFO */
|
||||||
|
#define QUP_I2C_MIDATA_SEQ (0x5 << 8)
|
||||||
|
#define QUP_I2C_MISTOP_SEQ (0x6 << 8)
|
||||||
|
#define QUP_I2C_MINACK_SEQ (0x7 << 8)
|
||||||
|
|
||||||
|
#define QUP_I2C_ADDR(x) ((x & 0xFF) << 1)
|
||||||
|
#define QUP_I2C_DATA(x) (x & 0xFF)
|
||||||
|
#define QUP_I2C_MI_TAG(x) (x & 0xFF00)
|
||||||
|
#define QUP_I2C_SLAVE_READ (0x1)
|
||||||
|
|
||||||
|
/*Bit vals for I2C_MASTER_CLK_CTL register */
|
||||||
|
#define QUP_HS_DIVIDER_SHFT (8)
|
||||||
|
#define QUP_DIVIDER_MIN_VAL (0x3)
|
||||||
|
|
||||||
|
/* Bit masks for I2C_MASTER_STATUS register */
|
||||||
|
#define QUP_I2C_INVALID_READ_SEQ (1 << 25)
|
||||||
|
#define QUP_I2C_INVALID_READ_ADDR (1 << 24)
|
||||||
|
#define QUP_I2C_INVALID_TAG (1 << 23)
|
||||||
|
#define QUP_I2C_FAILED_MASK (0x3 << 6)
|
||||||
|
#define QUP_I2C_ARB_LOST (1 << 4)
|
||||||
|
#define QUP_I2C_BUS_ERROR (1 << 2)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
QUP_SUCCESS = 0,
|
||||||
|
QUP_ERR_BAD_PARAM,
|
||||||
|
QUP_ERR_STATE_SET,
|
||||||
|
QUP_ERR_TIMEOUT,
|
||||||
|
QUP_ERR_UNSUPPORTED,
|
||||||
|
QUP_ERR_I2C_INVALID_SLAVE_ADDR,
|
||||||
|
QUP_ERR_XFER_FAIL,
|
||||||
|
QUP_ERR_UNDEFINED,
|
||||||
|
} qup_return_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
QUP_MINICORE_SPI = 1,
|
||||||
|
QUP_MINICORE_I2C_MASTER,
|
||||||
|
QUP_MINICORE_I2C_SLAVE
|
||||||
|
} qup_protocol_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
QUP_MODE_FIFO = 0,
|
||||||
|
QUP_MODE_BLOCK,
|
||||||
|
QUP_MODE_DATAMOVER,
|
||||||
|
} qup_mode_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
qup_protocol_t protocol;
|
||||||
|
unsigned clk_frequency;
|
||||||
|
unsigned src_frequency;
|
||||||
|
qup_mode_t mode;
|
||||||
|
} qup_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
qup_protocol_t protocol;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t addr;
|
||||||
|
uint8_t *data;
|
||||||
|
unsigned data_len;
|
||||||
|
} iic;
|
||||||
|
struct {
|
||||||
|
void *in;
|
||||||
|
void *out;
|
||||||
|
unsigned size;
|
||||||
|
} spi;
|
||||||
|
} p;
|
||||||
|
} qup_data_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize GSBI QUP block for FIFO I2C transfers.
|
||||||
|
* gsbi_id[IN]: GSBI for which QUP is to be initialized.
|
||||||
|
* config_ptr[IN]: configurations parameters for the QUP.
|
||||||
|
*
|
||||||
|
* return: QUP_SUCCESS, if initialization succeeds.
|
||||||
|
*/
|
||||||
|
qup_return_t qup_init(gsbi_id_t gsbi_id, qup_config_t *config_ptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set QUP state to run, pause, reset.
|
||||||
|
* gsbi_id[IN]: GSBI block for which QUP state is to be set.
|
||||||
|
* state[IN]: New state to transition to.
|
||||||
|
*
|
||||||
|
* return: QUP_SUCCESS, if state transition succeeds.
|
||||||
|
*/
|
||||||
|
qup_return_t qup_set_state(gsbi_id_t gsbi_id, uint32_t state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the status bits set during an i2c transfer.
|
||||||
|
* gsbi_id[IN]: GSBI block for which i2c status bits are to be cleared.
|
||||||
|
*
|
||||||
|
* return: QUP_SUCCESS, if status bits are cleared successfully.
|
||||||
|
*/
|
||||||
|
qup_return_t qup_reset_i2c_master_status(gsbi_id_t gsbi_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send data to the peripheral on the bus.
|
||||||
|
* gsbi_id[IN]: GSBI block for which data is to be sent.
|
||||||
|
* p_tx_obj[IN]: Data to be sent to the slave on the bus.
|
||||||
|
* stop_seq[IN]: When set to non-zero QUP engine sends i2c stop sequnce.
|
||||||
|
*
|
||||||
|
* return: QUP_SUCCESS, when data is sent successfully to the peripheral.
|
||||||
|
*/
|
||||||
|
qup_return_t qup_send_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj,
|
||||||
|
uint8_t stop_seq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive data from peripheral on the bus.
|
||||||
|
* gsbi_id[IN]: GSBI block from which data is to be received.
|
||||||
|
* p_tx_obj[IN]: length of data to be received, slave address.
|
||||||
|
* [OUT]: buffer filled with data from slave.
|
||||||
|
*
|
||||||
|
* return: QUP_SUCCESS, when data is received successfully.
|
||||||
|
*/
|
||||||
|
qup_return_t qup_recv_data(gsbi_id_t gsbi_id, qup_data_t *p_tx_obj);
|
||||||
|
|
||||||
|
#endif //__QUP_H__
|
Loading…
Reference in New Issue