blob: 41b31ed9a94fc8652c316508f4a152052eba6046 [file] [log] [blame]
Uwe Hermannb80dbf02007-04-22 19:08:13 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Uwe Hermannb80dbf02007-04-22 19:08:13 +00003 *
4 * Copyright (C) 2004 Tyan
5 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
6 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Uwe Hermannb80dbf02007-04-22 19:08:13 +000020 */
21
Yinghai Lu7213d0f2004-12-03 03:39:04 +000022#include <console/console.h>
23#include <stdint.h>
24#include <device/device.h>
25#include <device/path.h>
26#include <device/smbus.h>
27
28struct bus *get_pbus_smbus(device_t dev)
29{
30 struct bus *pbus = dev->bus;
Uwe Hermannd453dd02010-10-18 00:00:57 +000031
32 while (pbus && pbus->dev && !ops_smbus_bus(pbus))
Yinghai Lu7213d0f2004-12-03 03:39:04 +000033 pbus = pbus->dev->bus;
Uwe Hermannd453dd02010-10-18 00:00:57 +000034
35 if (!pbus || !pbus->dev || !pbus->dev->ops
36 || !pbus->dev->ops->ops_smbus_bus) {
37 printk(BIOS_ALERT, "%s Cannot find SMBus bus operations",
38 dev_path(dev));
Yinghai Lu7213d0f2004-12-03 03:39:04 +000039 die("");
Yinghai Lu7213d0f2004-12-03 03:39:04 +000040 }
Uwe Hermannd453dd02010-10-18 00:00:57 +000041
Yinghai Lu7213d0f2004-12-03 03:39:04 +000042 return pbus;
43}
44
Uwe Hermannc1ee4292010-10-17 19:01:48 +000045/*
Uwe Hermanne4870472010-11-04 23:23:47 +000046 * Multi-level I2C MUX? May need to find the first I2C device and then set link
Uwe Hermannc1ee4292010-10-17 19:01:48 +000047 * down to current dev.
48 *
49 * 1 store get_pbus_smbus list link
50 * 2 reverse the link and call set link.
51 *
52 * @param dev TODO.
53 */
Yinghai Lu7213d0f2004-12-03 03:39:04 +000054int smbus_set_link(device_t dev)
55{
56 struct bus *pbus_a[4]; // 4 level mux only. Enough?
Uwe Hermannd453dd02010-10-18 00:00:57 +000057 struct bus *pbus = dev->bus;
58 int pbus_num = 0;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000059 int i;
Uwe Hermannd453dd02010-10-18 00:00:57 +000060
61 while (pbus && pbus->dev && (pbus->dev->path.type == DEVICE_PATH_I2C)) {
Yinghai Lu7213d0f2004-12-03 03:39:04 +000062 pbus_a[pbus_num++] = pbus;
Uwe Hermannd453dd02010-10-18 00:00:57 +000063 pbus = pbus->dev->bus;
64 }
65
66 // printk(BIOS_INFO, "smbus_set_link: ");
67 for (i = pbus_num - 1; i >= 0; i--) {
68 // printk(BIOS_INFO, " %s[%d] -> ", dev_path(pbus_a[i]->dev),
69 // pbus_a[i]->link);
70 if (ops_smbus_bus(get_pbus_smbus(pbus_a[i]->dev))) {
71 if (pbus_a[i]->dev->ops
72 && pbus_a[i]->dev->ops->set_link)
73 pbus_a[i]->dev->ops->set_link(pbus_a[i]->dev,
74 pbus_a[i]->link_num);
Yinghai Lu7213d0f2004-12-03 03:39:04 +000075 }
76 }
Uwe Hermannd453dd02010-10-18 00:00:57 +000077 // printk(BIOS_INFO, " %s\n", dev_path(dev));
Yinghai Lu7213d0f2004-12-03 03:39:04 +000078
Uwe Hermannd453dd02010-10-18 00:00:57 +000079 return pbus_num;
Yinghai Lu7213d0f2004-12-03 03:39:04 +000080}
81
Vladimir Serbinenkodec91982014-01-27 23:46:46 +010082#define CHECK_PRESENCE(x) \
83 if (!ops_smbus_bus(get_pbus_smbus(dev))->x) { \
84 printk(BIOS_ERR, "%s missing " #x "\n", \
85 dev_path(dev)); \
86 return -1; \
87 }
88
89
Yinghai Lu7213d0f2004-12-03 03:39:04 +000090int smbus_quick_read(device_t dev)
91{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +010092 CHECK_PRESENCE(quick_read);
93
Yinghai Lu7213d0f2004-12-03 03:39:04 +000094 return ops_smbus_bus(get_pbus_smbus(dev))->quick_read(dev);
95}
Uwe Hermannd453dd02010-10-18 00:00:57 +000096
Yinghai Lu7213d0f2004-12-03 03:39:04 +000097int smbus_quick_write(device_t dev)
98{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +010099 CHECK_PRESENCE(quick_write);
100
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000101 return ops_smbus_bus(get_pbus_smbus(dev))->quick_write(dev);
102}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000103
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000104int smbus_recv_byte(device_t dev)
105{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100106 CHECK_PRESENCE(recv_byte);
107
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000108 return ops_smbus_bus(get_pbus_smbus(dev))->recv_byte(dev);
109}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000110
111int smbus_send_byte(device_t dev, u8 byte)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000112{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100113 CHECK_PRESENCE(send_byte);
114
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000115 return ops_smbus_bus(get_pbus_smbus(dev))->send_byte(dev, byte);
116}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000117
118int smbus_read_byte(device_t dev, u8 addr)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000119{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100120 CHECK_PRESENCE(read_byte);
121
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000122 return ops_smbus_bus(get_pbus_smbus(dev))->read_byte(dev, addr);
123}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000124
125int smbus_write_byte(device_t dev, u8 addr, u8 val)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000126{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100127 CHECK_PRESENCE(write_byte);
128
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000129 return ops_smbus_bus(get_pbus_smbus(dev))->write_byte(dev, addr, val);
130}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000131
132int smbus_read_word(device_t dev, u8 addr)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000133{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100134 CHECK_PRESENCE(read_word);
135
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000136 return ops_smbus_bus(get_pbus_smbus(dev))->read_word(dev, addr);
137}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000138
139int smbus_write_word(device_t dev, u8 addr, u16 val)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000140{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100141 CHECK_PRESENCE(write_word);
142
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000143 return ops_smbus_bus(get_pbus_smbus(dev))->write_word(dev, addr, val);
144}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000145
146int smbus_process_call(device_t dev, u8 cmd, u16 data)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000147{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100148 CHECK_PRESENCE(process_call);
149
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000150 return ops_smbus_bus(get_pbus_smbus(dev))->process_call(dev, cmd, data);
151}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000152
153int smbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buffer)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000154{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100155 CHECK_PRESENCE(block_read);
156
Uwe Hermannd453dd02010-10-18 00:00:57 +0000157 return ops_smbus_bus(get_pbus_smbus(dev))->block_read(dev, cmd,
158 bytes, buffer);
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000159}
Uwe Hermannd453dd02010-10-18 00:00:57 +0000160
161int smbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buffer)
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000162{
Vladimir Serbinenkodec91982014-01-27 23:46:46 +0100163 CHECK_PRESENCE(block_write);
164
Uwe Hermannd453dd02010-10-18 00:00:57 +0000165 return ops_smbus_bus(get_pbus_smbus(dev))->block_write(dev, cmd,
166 bytes, buffer);
Yinghai Lu7213d0f2004-12-03 03:39:04 +0000167}