/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __I2C_H #define __I2C_H struct i2c_request; struct i2c_bus { struct list_node link; struct dt_node *dt_node; uint32_t opal_id; int (*queue_req)(struct i2c_request *req); uint64_t (*run_req)(struct i2c_request *req); int (*check_quirk)(void *data, struct i2c_request *req, int *rc); void *check_quirk_data; }; /* * I2C specific OPAL error codes: * * OPAL_I2C_TIMEOUT I2C request timed out * OPAL_I2C_INVALID_CMD New command given when old not completed yet * OPAL_I2C_LBUS_PARITY Local bus parity error * OPAL_I2C_BKEND_OVERRUN Writing/reading into full/empty fifo respectively * OPAL_I2C_BKEND_ACCESS Writing/reading more data than requested * OPAL_I2C_ARBT_LOST I2C bus is held by some other master * OPAL_I2C_NACK_RCVD Slave is not responding back with the ACK * OPAL_I2C_STOP_ERR Did not able to send the STOP condtion on bus */ struct i2c_request { struct list_node link; struct i2c_bus *bus; enum i2c_operation { I2C_READ, /* RAW read from the device without offset */ I2C_WRITE, /* RAW write to the device without offset */ SMBUS_READ, /* SMBUS protocol read from the device */ SMBUS_WRITE, /* SMBUS protocol write to the device */ } op; int result; /* OPAL i2c error code */ uint32_t dev_addr; /* Slave device address */ uint32_t offset_bytes; /* Internal device offset */ uint32_t offset; /* Internal device offset */ uint32_t rw_len; /* Length of the data request */ void *rw_buf; /* Data request buffer */ enum i2c_request_state { i2c_req_new, /* un-initialised */ i2c_req_queued, /* waiting in the queue */ i2c_req_done, /* request has been completed */ } req_state; void (*completion)( /* Completion callback */ int rc, struct i2c_request *req); void *user_data; /* Client data */ int retries; uint64_t timeout; /* in ms */ }; /* Generic i2c */ extern void i2c_add_bus(struct i2c_bus *bus); extern struct i2c_bus *i2c_find_bus_by_id(uint32_t opal_id); static inline int64_t i2c_queue_req(struct i2c_request *req) { int64_t ret = req->bus->queue_req(req); if (!ret) req->req_state = i2c_req_queued; return ret; } static inline uint64_t i2c_run_req(struct i2c_request *req) { if (req->bus->run_req) return req->bus->run_req(req); return 0; } static inline int i2c_check_quirk(struct i2c_request *req, int *rc) { if (req->bus->check_quirk) return req->bus->check_quirk(req->bus->check_quirk_data, req, rc); return 0; } /* I2C synchronous request API */ int64_t i2c_request_sync(struct i2c_request *req); int64_t i2c_request_send(int bus_id, int dev_addr, int read_write, uint32_t offset, uint32_t offset_bytes, void* buf, size_t buflen, int timeout); /* P8 implementation details */ extern void p8_i2c_init(void); extern void p8_i2c_interrupt(uint32_t chip_id); /* P9 I2C Ownership Change OCC interrupt handler */ extern void p9_i2c_bus_owner_change(u32 chip_id); #endif /* __I2C_H */