blob: 9bae822a8e3e33a3329c7007534ed19a7b4b0215 [file] [log] [blame]
Daisuke Nojiri05949142014-11-21 15:33:26 -08001/*
2 * This file is part of the depthcharge project.
3 *
4 * Copyright (C) 2014 The Linux Foundation. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <assert.h>
31#include <libpayload.h>
32
33#include "base/container_of.h"
34#include "drivers/bus/i2c/i2c.h"
35#include "drivers/bus/i2c/ipq806x_qup.h"
36#include "drivers/bus/i2c/ipq806x_gsbi.h"
37#include "drivers/bus/i2c/ipq806x.h"
38
39static int i2c_init(unsigned gsbi_id)
40{
41 gsbi_return_t gsbi_ret = 0;
42 qup_return_t qup_ret = 0;
43 qup_config_t gsbi4_qup_config = {
44 QUP_MINICORE_I2C_MASTER,
45 100000,
46 24000000,
47 QUP_MODE_FIFO
48 };
49
50 gsbi_ret = gsbi_init(gsbi_id, GSBI_PROTO_I2C_ONLY);
51 if (GSBI_SUCCESS != gsbi_ret)
52 return 1;
53
54 qup_ret = qup_init(gsbi_id, &gsbi4_qup_config);
55 if (QUP_SUCCESS != qup_ret)
56 return 1;
57
58 qup_ret = qup_reset_i2c_master_status(gsbi_id);
59 if (QUP_SUCCESS != qup_ret)
60 return 1;
61
62 return 0;
63}
64
65static int i2c_read(uint32_t gsbi_id, uint8_t slave,
66 uint8_t *data, int data_len)
67{
68 qup_data_t obj;
69 qup_return_t qup_ret = 0;
70
71 memset(&obj, 0, sizeof(obj));
72 obj.protocol = QUP_MINICORE_I2C_MASTER;
73 obj.p.iic.addr = slave;
74 obj.p.iic.data_len = data_len;
75 obj.p.iic.data = data;
76 qup_ret = qup_recv_data(gsbi_id, &obj);
77
78 if (QUP_SUCCESS != qup_ret)
79 return 1;
80 else
81 return 0;
82}
83
84static int i2c_write(uint32_t gsbi_id, uint8_t slave,
85 uint8_t *data, int data_len, uint8_t stop_seq)
86{
87 qup_data_t obj;
88 qup_return_t qup_ret = 0;
89
90 memset(&obj, 0, sizeof(obj));
91 obj.protocol = QUP_MINICORE_I2C_MASTER;
92 obj.p.iic.addr = slave;
93 obj.p.iic.data_len = data_len;
94 obj.p.iic.data = data;
95 qup_ret = qup_send_data(gsbi_id, &obj, stop_seq);
96
97 if (QUP_SUCCESS != qup_ret)
98 return 1;
99 else
100 return 0;
101}
102
103static int i2c_transfer(struct I2cOps *me, I2cSeg *segments, int seg_count)
104{
105 Ipq806xI2c *bus = container_of(me, Ipq806xI2c, ops);
106 I2cSeg *seg = segments;
107 int ret = 0;
108
109 if (!bus->initialized)
110 if (0 != i2c_init(bus->gsbi_id))
111 return 1;
112
113 while (seg_count--) {
114 if (seg->read)
115 ret = i2c_read(bus->gsbi_id, seg->chip,
116 seg->buf, seg->len);
117 else
118 ret = i2c_write(bus->gsbi_id, seg->chip,
119 seg->buf, seg->len,
120 (seg_count ? 0 : 1));
121 seg++;
122 }
123
124 if (QUP_SUCCESS != ret) {
125 qup_set_state(bus->gsbi_id, QUP_STATE_RESET);
126 return 1;
127 }
128
129 return 0;
130}
131
132Ipq806xI2c *new_ipq806x_i2c(unsigned gsbi_id)
133{
134 Ipq806xI2c *bus = 0;
135
136 if (!i2c_init(gsbi_id)) {
137 bus = xzalloc(sizeof(*bus));
138 bus->gsbi_id = gsbi_id;
139 bus->initialized = 1;
140 bus->ops.transfer = &i2c_transfer;
141 }
142 return bus;
143}