treewide: remove FSF address
[osmocom-bb.git] / src / target / firmware / calypso / i2c.c
blobad7d584c426c8ac54dcd458f009fa9e38eea0bee
1 /* Driver for I2C Master Controller inside TI Calypso */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
5 * All Rights Reserved
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.
19 #include <stdint.h>
20 #include <stdio.h>
22 #include <debug.h>
23 #include <memory.h>
24 #include <i2c.h>
26 #define BASE_ADDR_I2C 0xfffe2800
27 #define I2C_REG(x) (BASE_ADDR_I2C+(x))
29 enum i2c_reg {
30 DEVICE_REG = 0,
31 ADDRESS_REG,
32 DATA_WR_REG,
33 DATA_RD_REG,
34 CMD_REG,
35 CONF_FIFO_REG,
36 CONF_CLK_REG,
37 CONF_CLK_FUNC_REF,
38 STATUS_FIFO_REG,
39 STATUS_ACTIVITY_REG,
42 #define I2C_CMD_SOFT_RESET (1 << 0)
43 #define I2C_CMD_EN_CLK (1 << 1)
44 #define I2C_CMD_START (1 << 2)
45 #define I2C_CMD_RW_READ (1 << 3)
46 #define I2C_CMD_COMP_READ (1 << 4)
47 #define I2C_CMD_IRQ_ENABLE (1 << 5)
49 #define I2C_STATUS_ERROR_DATA (1 << 0)
50 #define I2C_STATUS_ERROR_DEV (1 << 1)
51 #define I2C_STATUS_IDLE (1 << 2) // 1: not idle, 0: idle
52 #define I2C_STATUS_INTERRUPT (1 << 3)
54 int i2c_write(uint8_t chip, uint32_t addr, int alen, const uint8_t *buffer, int len)
56 uint8_t cmd;
58 /* Calypso I2C controller doesn't support fancy addressing */
59 if (alen > 1)
60 return -1;
62 /* FIXME: implement writes longer than fifo size */
63 if (len > 16)
64 return -1;
66 printd("i2c_write(chip=0x%02u, addr=0x%02u): ", chip, addr);
68 writeb(chip & 0x7f, I2C_REG(DEVICE_REG));
69 writeb(addr & 0xff, I2C_REG(ADDRESS_REG));
71 /* we have to tell the controller how many bits we'll put into the fifo ?!? */
72 writeb(len-1, I2C_REG(CONF_FIFO_REG));
74 /* fill the FIFO */
75 while (len--) {
76 uint8_t byte = *buffer++;
77 writeb(byte, I2C_REG(DATA_WR_REG));
78 printd("%02X ", byte);
80 dputchar('\n');
82 /* start the transfer */
83 cmd = readb(I2C_REG(CMD_REG));
84 cmd |= I2C_CMD_START;
85 writeb(cmd, I2C_REG(CMD_REG));
87 /* wait until transfer completes */
88 while (1) {
89 uint8_t reg = readb(I2C_REG(STATUS_ACTIVITY_REG));
90 printd("I2C Status: 0x%02x\n", reg & 0xf);
91 if (!(reg & I2C_STATUS_IDLE)) // 0: idle 1: not idle
92 break;
94 dputs("I2C transfer completed\n");
96 return 0;
99 void i2c_init(int speed, int slaveadd)
101 /* scl_out = clk_func_ref / 3,
102 clk_func_ref = master_clock_freq / (divisor_2 + 1)
103 master_clock_freq = ext_clock_freq / divisor_1 */
104 /* clk_func_ref = scl_out * 3,
105 divisor_2 = (master_clock_freq / clk_func_ref) - 1
106 divisor_1 = ext_clock_freq / master_clock_freq */
107 /* for a target freq of 200kHz:
108 ext_clock_freq = 13MHz
109 clk_func_ref = 3 * 300kHZ = 600kHz
110 divisor_1 = 1 => master_clock_freq = ext_clock_freq = 13MHz
111 divisor_2 = 21 => clk_func_ref = 13MHz / (21+2) = 590.91 kHz
112 scl_out = clk_func_ref / 3 = 509.91 kHz / 3 = 196.97kHz */
113 writeb(I2C_CMD_SOFT_RESET, I2C_REG(CMD_REG));
115 writeb(0x00, I2C_REG(CONF_CLK_REG));
116 writeb(21, I2C_REG(CONF_CLK_FUNC_REF));
118 writeb(I2C_CMD_EN_CLK, I2C_REG(CMD_REG));