1 /* Driver for Analog Baseband Circuit (TWL3025) */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <calypso/irq.h>
31 #include <calypso/tsp.h>
32 #include <calypso/tpu.h>
33 #include <abb/twl3025.h>
36 #define REG_PAGE(n) (n >> 7)
37 #define REG_ADDR(n) (n & 0x3f)
39 #define TWL3025_DEV_IDX 0 /* On the SPI bus */
40 #define TWL3025_TSP_DEV_IDX 0 /* On the TSP bus */
45 static struct twl3025 twl3025_state;
47 /* Switch the register page of the TWL3025 */
48 static void twl3025_switch_page(uint8_t page)
51 twl3025_reg_write(PAGEREG, 1 << 0);
53 twl3025_reg_write(PAGEREG, 1 << 1);
55 twl3025_state.page = page;
58 static void handle_charger(void)
61 printd("handle_charger();");
63 status = twl3025_reg_read(VRPCSTS);
64 // printd("\nvrpcsts: 0x%02x", status);
67 printd(" inserted\n");
72 // twl3025_dump_madc();
75 static void handle_adc_done(void)
77 printd("handle_adc_done();");
80 static void twl3025_irq(enum irq_nr nr)
83 printd("twl3025_irq: 0x%02x\n",nr);
85 case IRQ_EXTERNAL: // charger in/out, pwrbtn, adc done
86 src = twl3025_reg_read(ITSTATREG);
87 // printd("itstatreg 0x%02x\n", src);
93 case IRQ_EXTERNAL_FIQ: // vcc <2.8V emergency power off
94 puts("\nBROWNOUT!1!");
102 void twl3025_init(void)
105 twl3025_switch_page(0);
107 twl3025_reg_write(AFCCTLADD, 0x01); /* AFCCK(1:0) must not be zero! */
108 twl3025_unit_enable(TWL3025_UNIT_AFC, 1);
110 irq_register_handler(IRQ_EXTERNAL, &twl3025_irq);
111 irq_config(IRQ_EXTERNAL, 0, 0, 0);
112 irq_enable(IRQ_EXTERNAL);
114 irq_register_handler(IRQ_EXTERNAL_FIQ, &twl3025_irq);
115 irq_config(IRQ_EXTERNAL_FIQ, 1, 0, 0);
116 irq_enable(IRQ_EXTERNAL_FIQ);
119 void twl3025_reg_write(uint8_t reg, uint16_t data)
123 printd("tw3025_reg_write(%u,%u)=0x%04x\n", REG_PAGE(reg),
124 REG_ADDR(reg), data);
126 if (reg != PAGEREG && REG_PAGE(reg) != twl3025_state.page)
127 twl3025_switch_page(REG_PAGE(reg));
129 tx = ((data & 0x3ff) << 6) | (REG_ADDR(reg) << 1);
131 spi_xfer(TWL3025_DEV_IDX, 16, &tx, NULL);
134 void twl3025_tsp_write(uint8_t data)
136 tsp_write(TWL3025_TSP_DEV_IDX, 7, data);
139 uint16_t twl3025_reg_read(uint8_t reg)
143 if (REG_PAGE(reg) != twl3025_state.page)
144 twl3025_switch_page(REG_PAGE(reg));
146 tx = (REG_ADDR(reg) << 1) | 1;
148 /* A read cycle contains two SPI transfers */
149 spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
151 spi_xfer(TWL3025_DEV_IDX, 16, &tx, &rx);
155 printd("tw3025_reg_read(%u,%u)=0x%04x\n", REG_PAGE(reg),
161 static void twl3025_wait_ibic_access(void)
163 /* Wait 6 * 32kHz clock cycles for first IBIC access (187us + 10% = 210us) */
167 void twl3025_power_off(void)
169 twl3025_reg_write(VRPCDEV, 0x01);
172 void twl3025_clk13m(int enable)
175 twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
176 twl3025_wait_ibic_access();
177 /* for whatever reason we need to do this twice */
178 twl3025_reg_write(TOGBR2, TOGBR2_ACTS);
179 twl3025_wait_ibic_access();
181 twl3025_reg_write(TOGBR2, TOGBR2_ACTR);
182 twl3025_wait_ibic_access();
186 #define TSP_DELAY 6 /* 13* Tclk6M5 = ~ 3 GSM Qbits + 3 TPU instructions */
187 #define BDLON_TO_BDLCAL 6
188 #define BDLCAL_DURATION 66
189 #define BDLON_TO_BDLENA 7
190 #define BULON_TO_BULENA 16
192 /* Enqueue a series of TSP commands in the TPU to (de)activate the downlink path */
193 void twl3025_downlink(int on, int16_t at)
195 int16_t bdl_ena = at - TSP_DELAY - 6;
199 printf("BDLENA time negative (%d)\n", bdl_ena);
200 /* FIXME: calibration should be done just before BDLENA */
201 twl3025_tsp_write(BDLON);
202 tpu_enq_wait(BDLON_TO_BDLCAL - TSP_DELAY);
203 twl3025_tsp_write(BDLON | BDLCAL);
204 tpu_enq_wait(BDLCAL_DURATION - TSP_DELAY);
205 twl3025_tsp_write(BDLON);
206 //tpu_enq_wait(BDLCAL_TO_BDLENA) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
208 twl3025_tsp_write(BDLON | BDLENA);
211 twl3025_tsp_write(BDLON);
212 //tpu_enq_wait(nBDLENA_TO_nBDLON) this is only 3.7us == 4 qbits, i.e. less than the TSP_DELAY
213 twl3025_tsp_write(0);
217 void twl3025_afc_set(int16_t val)
219 printf("twl3025_afc_set(%d)\n", val);
223 else if (val <= -4096)
226 /* FIXME: we currently write from the USP rather than BSP */
227 twl3025_reg_write(AUXAFC2, val >> 10);
228 twl3025_reg_write(AUXAFC1, val & 0x3ff);
231 int16_t twl3025_afc_get(void)
235 val = (twl3025_reg_read(AUXAFC2) & 0x7);
237 val = val | (twl3025_reg_read(AUXAFC1) & 0x3ff);
244 void twl3025_unit_enable(enum twl3025_unit unit, int on)
249 case TWL3025_UNIT_AFC:
255 case TWL3025_UNIT_MAD:
261 case TWL3025_UNIT_ADA:
266 case TWL3025_UNIT_VDL:
272 case TWL3025_UNIT_VUL:
279 twl3025_reg_write(TOGBR1, togbr1);
282 uint8_t twl3025_afcout_get(void)
284 return twl3025_reg_read(AFCOUT) & 0xff;
287 void twl3025_afcout_set(uint8_t val)
289 twl3025_reg_write(AFCCTLADD, 0x05);
290 twl3025_reg_write(AFCOUT, val);