1/*
2 * Copyright (c) 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
8 */
9#include "i2c.h"
10#include "twl6030.h"
11
12// I2C slave address for id1 reads and writes is 0x48
13#define ID1_I2C_ADDR 0x48
14
15
16inline uint8_t _ti_twl6030_id1_read_8(void *d, size_t off)
17{
18    errval_t err;
19
20    struct i2c_msg msg[2];
21
22    uint8_t reg = off & 0xff;
23    uint8_t result = 0;
24
25    TWL_DEBUG("id1_read_8(reg=0x%"PRIx8")\n", reg);
26
27    /* set register to read from */
28    msg[0].slave = ID1_I2C_ADDR;
29    msg[0].flags = I2C_WR | I2C_NOSTOP;
30    msg[0].length = 1;
31    msg[0].buf = ®
32
33    /* read data back */
34    msg[1].slave = ID1_I2C_ADDR;
35    msg[1].flags = I2C_RD;
36    msg[1].length = 1;
37    msg[1].buf = &result;
38
39    err = ti_i2c_transfer(I2C_HC, msg, 2);
40
41    if (err_is_fail(err)) {
42        TWL_DEBUG("ti_i2c_transfer: %"PRIuERRV"\n", err);
43        return 0;
44    }
45
46    return result;
47}
48
49inline void _ti_twl6030_id1_write_8(void *d, size_t off, uint8_t regval)
50{
51    struct i2c_msg msg;
52    errval_t err;
53
54    uint8_t addr = off & 0xff;
55    uint8_t msgbuf[2];
56
57    msgbuf[0] = addr;
58    msgbuf[1] = regval;
59
60    msg.slave = ID1_I2C_ADDR;
61    msg.flags = I2C_WR;
62    msg.length = 2;
63    msg.buf = msgbuf;
64
65    err = ti_i2c_transfer(I2C_HC, &msg, 1);
66
67    if (err_is_fail(err)) {
68        TWL_DEBUG("ti_i2c_transfer failed in mackerel: %"PRIuERRV"\n", err);
69    }
70
71    return;
72}
73
74void ti_twl6030_init(struct twl6030_driver_state* st)
75{
76    TWL_DEBUG("%s:%d\n", __FUNCTION__, __LINE__);
77    ti_i2c_init(st, I2C_HC);
78}
79
80void ti_twl6030_vmmc_pr(ti_twl6030_t twl)
81{
82#define PBS (8*1024)
83static char PRBUF[PBS];
84#define PRBUFL PRBUF, (PBS-1)
85
86    ti_twl6030_pr(PRBUFL, &twl);
87    TWL_DEBUG("%s\n", PRBUF);
88}
89
90static ti_twl6030_vsel_t millis_to_vsel(int millis)
91{
92    switch (millis) {
93    case 0:
94        return ti_twl6030_v0v0;
95    case 1000:
96        return ti_twl6030_v1v0;
97    case 1100:
98        return ti_twl6030_v1v1;
99    case 1200:
100        return ti_twl6030_v1v2;
101    case 1300:
102        return ti_twl6030_v1v3;
103    case 1400:
104        return ti_twl6030_v1v4;
105    case 1500:
106        return ti_twl6030_v1v5;
107    case 1600:
108        return ti_twl6030_v1v6;
109    case 1700:
110        return ti_twl6030_v1v7;
111    case 1800:
112        return ti_twl6030_v1v8;
113    case 1900:
114        return ti_twl6030_v1v9;
115    case 2000:
116        return ti_twl6030_v2v0;
117    case 2100:
118        return ti_twl6030_v2v1;
119    case 2200:
120        return ti_twl6030_v2v2;
121    case 2300:
122        return ti_twl6030_v2v3;
123    case 2400:
124        return ti_twl6030_v2v4;
125    case 2500:
126        return ti_twl6030_v2v5;
127    case 2600:
128        return ti_twl6030_v2v6;
129    case 2700:
130        return ti_twl6030_v2v7;
131    case 2750:
132        return ti_twl6030_v2v75;
133    case 2800:
134        return ti_twl6030_v2v8;
135    case 2900:
136        return ti_twl6030_v2v9;
137    case 3000:
138        return ti_twl6030_v3v0;
139    case 3100:
140        return ti_twl6030_v3v1;
141    case 3200:
142        return ti_twl6030_v3v2;
143    case 3300:
144        return ti_twl6030_v3v3;
145    default:
146        TWL_DEBUG("voltage (%d) not available, returning 0.0V\n", millis);
147        return ti_twl6030_v0v0;
148    }
149}
150
151
152void ti_twl6030_vmmc_off(ti_twl6030_t twl)
153{
154    // turn off
155    ti_twl6030_cfg_state_w_t st = ti_twl6030_cfg_state_w_default;
156    st = ti_twl6030_cfg_state_w_grp_app_insert(st, 0x1);
157    st = ti_twl6030_cfg_state_w_grp_con_insert(st, 0x1);
158    st = ti_twl6030_cfg_state_w_grp_mod_insert(st, 0x1);
159    st = ti_twl6030_cfg_state_w_state_insert(st, 0x0);
160
161    ti_twl6030_vmmc_cfg_state_w_rawwr(&twl, st);
162}
163
164void ti_twl6030_vmmc_on(ti_twl6030_t twl)
165{
166    // turn on
167    ti_twl6030_cfg_state_w_t st = ti_twl6030_cfg_state_w_default;
168    st = ti_twl6030_cfg_state_w_grp_app_insert(st, 0x1);
169    st = ti_twl6030_cfg_state_w_grp_con_insert(st, 0x1);
170    st = ti_twl6030_cfg_state_w_grp_mod_insert(st, 0x1);
171    st = ti_twl6030_cfg_state_w_state_insert(st, 0x1);
172    ti_twl6030_vmmc_cfg_state_w_wr(&twl, st);
173}
174
175static volatile uint32_t dummy = 0;
176static void wait_msec(long msec)
177{
178    int i = 0, sum = 0;
179    long end = (1200000 * msec / 8);
180
181    // Cannot use volatile variables in loop
182    while (++i < end)  {
183        sum += i + end;
184    }
185
186    dummy += sum;
187}
188
189
190errval_t ti_twl6030_set_vmmc_vsel(ti_twl6030_t twl, int millis)
191{
192    TWL_DEBUG("ti_twl6030_vmmc_vsel\n");
193    //ti_twl6030_mmcctrl_vmmc_auto_off_wrf(&twl, 0x0);
194    ti_twl6030_mmcctrl_sw_fc_wrf(&twl, 0x1);
195
196    ti_twl6030_vmmc_off(twl);
197    wait_msec(10);
198
199    ti_twl6030_vsel_t vsel = millis_to_vsel(millis);
200    ti_twl6030_vmmc_cfg_voltage_vsel_wrf(&twl, vsel);
201
202    ti_twl6030_vmmc_on(twl);
203    //ti_twl6030_mmcctrl_vmmc_auto_off_wrf(&twl, 0x0);
204
205    ti_twl6030_vmmc_pr(twl);
206
207
208    return SYS_ERR_OK;
209}
210