1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2004 Steven J. Hill
4 * Copyright (C) 2001,2002,2003 Broadcom Corporation
5 * Copyright (C) 1995-2000 Simon G. Vogl
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/i2c.h>
13 #include <asm/sibyte/sb1250_regs.h>
14 #include <asm/sibyte/sb1250_smbus.h>
17 struct i2c_algo_sibyte_data
{
18 void *data
; /* private data */
19 int bus
; /* which bus */
20 void *reg_base
; /* CSR base */
23 /* ----- global defines ----------------------------------------------- */
24 #define SMB_CSR(a,r) ((long)(a->reg_base + r))
27 static int smbus_xfer(struct i2c_adapter
*i2c_adap
, u16 addr
,
28 unsigned short flags
, char read_write
,
29 u8 command
, int size
, union i2c_smbus_data
* data
)
31 struct i2c_algo_sibyte_data
*adap
= i2c_adap
->algo_data
;
35 while (csr_in32(SMB_CSR(adap
, R_SMB_STATUS
)) & M_SMB_BUSY
)
40 csr_out32((V_SMB_ADDR(addr
) |
41 (read_write
== I2C_SMBUS_READ
? M_SMB_QDATA
: 0) |
42 V_SMB_TT_QUICKCMD
), SMB_CSR(adap
, R_SMB_START
));
45 if (read_write
== I2C_SMBUS_READ
) {
46 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_RD1BYTE
),
47 SMB_CSR(adap
, R_SMB_START
));
50 csr_out32(V_SMB_CMD(command
), SMB_CSR(adap
, R_SMB_CMD
));
51 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_WR1BYTE
),
52 SMB_CSR(adap
, R_SMB_START
));
55 case I2C_SMBUS_BYTE_DATA
:
56 csr_out32(V_SMB_CMD(command
), SMB_CSR(adap
, R_SMB_CMD
));
57 if (read_write
== I2C_SMBUS_READ
) {
58 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_CMD_RD1BYTE
),
59 SMB_CSR(adap
, R_SMB_START
));
62 csr_out32(V_SMB_LB(data
->byte
),
63 SMB_CSR(adap
, R_SMB_DATA
));
64 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_WR2BYTE
),
65 SMB_CSR(adap
, R_SMB_START
));
68 case I2C_SMBUS_WORD_DATA
:
69 csr_out32(V_SMB_CMD(command
), SMB_CSR(adap
, R_SMB_CMD
));
70 if (read_write
== I2C_SMBUS_READ
) {
71 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_CMD_RD2BYTE
),
72 SMB_CSR(adap
, R_SMB_START
));
75 csr_out32(V_SMB_LB(data
->word
& 0xff),
76 SMB_CSR(adap
, R_SMB_DATA
));
77 csr_out32(V_SMB_MB(data
->word
>> 8),
78 SMB_CSR(adap
, R_SMB_DATA
));
79 csr_out32((V_SMB_ADDR(addr
) | V_SMB_TT_WR2BYTE
),
80 SMB_CSR(adap
, R_SMB_START
));
87 while (csr_in32(SMB_CSR(adap
, R_SMB_STATUS
)) & M_SMB_BUSY
)
90 error
= csr_in32(SMB_CSR(adap
, R_SMB_STATUS
));
91 if (error
& M_SMB_ERROR
) {
92 /* Clear error bit by writing a 1 */
93 csr_out32(M_SMB_ERROR
, SMB_CSR(adap
, R_SMB_STATUS
));
94 return (error
& M_SMB_ERROR_TYPE
) ? -EIO
: -ENXIO
;
98 data
->byte
= csr_in32(SMB_CSR(adap
, R_SMB_DATA
)) & 0xff;
100 data
->word
= csr_in32(SMB_CSR(adap
, R_SMB_DATA
)) & 0xffff;
105 static u32
bit_func(struct i2c_adapter
*adap
)
107 return (I2C_FUNC_SMBUS_QUICK
| I2C_FUNC_SMBUS_BYTE
|
108 I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA
);
112 /* -----exported algorithm data: ------------------------------------- */
114 static const struct i2c_algorithm i2c_sibyte_algo
= {
115 .smbus_xfer
= smbus_xfer
,
116 .functionality
= bit_func
,
120 * registering functions to load algorithms at runtime
122 static int __init
i2c_sibyte_add_bus(struct i2c_adapter
*i2c_adap
, int speed
)
124 struct i2c_algo_sibyte_data
*adap
= i2c_adap
->algo_data
;
126 /* Register new adapter to i2c module... */
127 i2c_adap
->algo
= &i2c_sibyte_algo
;
129 /* Set the requested frequency. */
130 csr_out32(speed
, SMB_CSR(adap
,R_SMB_FREQ
));
131 csr_out32(0, SMB_CSR(adap
,R_SMB_CONTROL
));
133 return i2c_add_numbered_adapter(i2c_adap
);
137 static struct i2c_algo_sibyte_data sibyte_board_data
[2] = {
138 { NULL
, 0, (void *) (CKSEG1
+A_SMB_BASE(0)) },
139 { NULL
, 1, (void *) (CKSEG1
+A_SMB_BASE(1)) }
142 static struct i2c_adapter sibyte_board_adapter
[2] = {
144 .owner
= THIS_MODULE
,
145 .class = I2C_CLASS_HWMON
,
147 .algo_data
= &sibyte_board_data
[0],
149 .name
= "SiByte SMBus 0",
152 .owner
= THIS_MODULE
,
153 .class = I2C_CLASS_HWMON
,
155 .algo_data
= &sibyte_board_data
[1],
157 .name
= "SiByte SMBus 1",
161 static int __init
i2c_sibyte_init(void)
163 pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n");
164 if (i2c_sibyte_add_bus(&sibyte_board_adapter
[0], K_SMB_FREQ_100KHZ
) < 0)
166 if (i2c_sibyte_add_bus(&sibyte_board_adapter
[1],
167 K_SMB_FREQ_400KHZ
) < 0) {
168 i2c_del_adapter(&sibyte_board_adapter
[0]);
174 static void __exit
i2c_sibyte_exit(void)
176 i2c_del_adapter(&sibyte_board_adapter
[0]);
177 i2c_del_adapter(&sibyte_board_adapter
[1]);
180 module_init(i2c_sibyte_init
);
181 module_exit(i2c_sibyte_exit
);
183 MODULE_AUTHOR("Kip Walker (Broadcom Corp.)");
184 MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
185 MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
186 MODULE_LICENSE("GPL");