1450N/A/*
1450N/A * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
1450N/A *
1450N/A * Permission is hereby granted, free of charge, to any person obtaining a
1450N/A * copy of this software and associated documentation files (the "Software"),
1450N/A * to deal in the Software without restriction, including without limitation
1450N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1450N/A * and/or sell copies of the Software, and to permit persons to whom the
1450N/A * Software is furnished to do so, subject to the following conditions:
1450N/A *
1450N/A * The above copyright notice and this permission notice (including the next
1450N/A * paragraph) shall be included in all copies or substantial portions of the
1450N/A * Software.
1450N/A *
1450N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1450N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1450N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1450N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1450N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1450N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1450N/A * DEALINGS IN THE SOFTWARE.
1450N/A */
1450N/A
1450N/A/*
1450N/A * Copyright (c) 2012 Intel Corporation. All rights reserved.
1450N/A */
1450N/A
1450N/A#include "drmP.h"
1450N/A
1450N/A#define mutex_lock_nested(a,b) mutex_enter(a)
1450N/A
1450N/A#define I2C_HI_CLOCK(adap, ret) \
1450N/Ado { \
1450N/A ret = i2c_setscl(adap); \
1450N/A if (ret) { \
1450N/A /* Other master keeps the clock low. */ \
1450N/A /* Free the bus. */ \
1450N/A i2c_setsda(adap); \
1450N/A i2c_udelay(adap); \
1450N/A return ret; \
1450N/A } \
1450N/A} while (*"\0");
1450N/A
1450N/Astatic inline void
1450N/Ai2c_udelay(struct i2c_adapter *adap)
1450N/A{
1450N/A udelay((adap->udelay + 1) >> 1);
1450N/A}
1450N/A
1450N/Astatic inline int
1450N/Ai2c_getsda(struct i2c_adapter *adap)
1450N/A{
1450N/A return adap->getsda(adap->data) ? 1 : 0;
1450N/A}
1450N/A
1450N/Astatic inline void
1450N/Ai2c_clrsda(struct i2c_adapter *adap)
1450N/A{
1450N/A adap->setsda(adap->data, 0);
1450N/A}
1450N/A
1450N/Astatic inline void
1450N/Ai2c_setsda(struct i2c_adapter *adap)
1450N/A{
1450N/A adap->setsda(adap->data, 1);
1450N/A}
1450N/A
1450N/Astatic inline int
1450N/Ai2c_getscl(struct i2c_adapter *adap)
1450N/A{
1450N/A return adap->getscl(adap->data) ? 1 : 0;
1450N/A}
1450N/A
1450N/Astatic inline void
1450N/Ai2c_clrscl(struct i2c_adapter *adap)
1450N/A{
1450N/A adap->setscl(adap->data, 0);
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_setscl(struct i2c_adapter *adap)
1450N/A{
1450N/A clock_t start;
1450N/A
1450N/A adap->setscl(adap->data, 1);
1450N/A
1450N/A /* Clock Synchronization */
1450N/A start = ddi_get_lbolt();
1450N/A while (!i2c_getscl(adap)) {
1450N/A /* FIXME: Does ddi_get_lbolt() return negative
1450N/A * value? If so, leave me.
1450N/A */
1450N/A if ((ddi_get_lbolt() - start) > adap->timeout)
1450N/A return -ETIMEDOUT;
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_start(struct i2c_adapter *adap)
1450N/A{
1450N/A int ret = 0;
1450N/A
1450N/A /* Step 1: free the bus. */
1450N/A i2c_setsda(adap);
1450N/A i2c_udelay(adap);
1450N/A ret = i2c_setscl(adap);
1450N/A if (ret) {
1450N/A /* Other master keeps the clock low.
1450N/A * The bus is busy.
1450N/A */
1450N/A return ret;
1450N/A }
1450N/A if (!i2c_getsda(adap)) {
1450N/A /* The bus is busy. */
1450N/A return -EBUSY;
1450N/A }
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: (S/Sr) condition. */
1450N/A i2c_clrsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 3: free the clock. */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_stop(struct i2c_adapter *adap)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Stop() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A /* Step 1: Free the data */
1450N/A i2c_clrsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: Hold the clock */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 3: (P) condition */
1450N/A i2c_setsda(adap);
1450N/A i2c_udelay(adap);
1450N/A if (!i2c_getsda(adap)) {
1450N/A /* Other master keeps the data low.
1450N/A * The bus is busy.
1450N/A */
1450N/A return -EBUSY;
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_write_byte(struct i2c_adapter *adap, unsigned char c)
1450N/A{
1450N/A int needARB = 0;
1450N/A int ret = 0, i;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Write() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A for (i = 7; i >= 0; i--) {
1450N/A /* Step 1: set data. */
1450N/A if (c & (1 << i)) {
1450N/A needARB = 1;
1450N/A i2c_setsda(adap);
1450N/A } else {
1450N/A needARB = 0;
1450N/A i2c_clrsda(adap);
1450N/A }
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: hold the clock. */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A if (needARB && !i2c_getsda(adap)) {
1450N/A /* Do arbitration: lose the bus. */
1450N/A return -EBUSY;
1450N/A }
1450N/A /* Double delay. */
1450N/A i2c_udelay(adap);
1450N/A i2c_udelay(adap);
1450N/A if (needARB && !i2c_getsda(adap)) {
1450N/A /* Do arbitration: someone performs (S) condition. */
1450N/A return -EBUSY;
1450N/A }
1450N/A
1450N/A /* Step 3: free the clock. */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_read_byte(struct i2c_adapter *adap, unsigned char *cp)
1450N/A{
1450N/A int ret, r, i;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Read() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A i2c_setsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A *cp = 0;
1450N/A for (i = 7; i >= 0; i--) {
1450N/A /* Step 1: hold the clock. */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A r = i2c_getsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: read the data. */
1450N/A if (r != i2c_getsda(adap)) {
1450N/A /* Do arbitration: someone performs (S/Sr/P) condition. */
1450N/A return -EBUSY;
1450N/A }
1450N/A if (r)
1450N/A *cp |= (1 << i);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 3: free the clock */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_ack(struct i2c_adapter *adap)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Ack() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A /* Step 1: free the data. */
1450N/A i2c_clrsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: hold the clock. */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 3: free the clock */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_no_ack(struct i2c_adapter *adap)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Nak() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A /* Step 1: hold the data. */
1450N/A i2c_setsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: hold the clock. */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A if (!i2c_getsda(adap)) {
1450N/A /* Other master keeps the data low. */
1450N/A return -EBUSY;
1450N/A }
1450N/A i2c_udelay(adap);
1450N/A if (!i2c_getsda(adap)) {
1450N/A /* Do arbitration: someone performs (S/Sr) condition. */
1450N/A return -EBUSY;
1450N/A }
1450N/A
1450N/A /* Step 3: free the clock */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_wait_ack(struct i2c_adapter *adap)
1450N/A{
1450N/A int ret;
1450N/A
1450N/A if (i2c_getscl(adap)) {
1450N/A /* Wack() must be called after start() or any
1450N/A * transfer routines, which all free the clock
1450N/A * before returning.
1450N/A */
1450N/A return -ENOTSUP;
1450N/A }
1450N/A
1450N/A /* Step 1: hold the data. */
1450N/A i2c_setsda(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 2: hold the clock. */
1450N/A I2C_HI_CLOCK(adap, ret);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A /* Step 3: read the data. */
1450N/A ret = i2c_getsda(adap) ? 0 : 1;
1450N/A
1450N/A /* Step 4: free the clock */
1450N/A i2c_clrscl(adap);
1450N/A i2c_udelay(adap);
1450N/A
1450N/A return ret;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_write_msg(struct i2c_adapter *adap, struct i2c_msg *msg)
1450N/A{
1450N/A int i, ret;
1450N/A
1450N/A for (i = 0; i < msg->len; i++) {
1450N/A ret = i2c_write_byte(adap, msg->buf[i]);
1450N/A if (ret)
1450N/A return ret;
1450N/A
1450N/A ret = i2c_wait_ack(adap);
1450N/A if (ret == 1)
1450N/A continue;
1450N/A else if (ret == 0)
1450N/A return -ENXIO;
1450N/A else
1450N/A return ret;
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_read_msg(struct i2c_adapter *adap, struct i2c_msg *msg)
1450N/A{
1450N/A unsigned char c;
1450N/A int i, ret;
1450N/A
1450N/A for (i = 0; i < msg->len; i++) {
1450N/A ret = i2c_read_byte(adap, &c);
1450N/A if (ret)
1450N/A return ret;
1450N/A
1450N/A msg->buf[i] = c;
1450N/A
1450N/A if (i < msg->len - 1)
1450N/A ret = i2c_ack(adap);
1450N/A else
1450N/A ret = i2c_no_ack(adap);
1450N/A if (ret)
1450N/A return ret;
1450N/A }
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_address(struct i2c_adapter *adap, struct i2c_msg *msg)
1450N/A{
1450N/A unsigned char addr;
1450N/A int ret;
1450N/A
1450N/A addr = msg->addr << 1;
1450N/A if (msg->flags & I2C_M_RD)
1450N/A addr |= 1;
1450N/A
1450N/A ret = i2c_write_byte(adap, addr);
1450N/A if (ret)
1450N/A return ret;
1450N/A
1450N/A ret = i2c_wait_ack(adap);
1450N/A if (ret == 1)
1450N/A return 0;
1450N/A else if (ret == 0)
1450N/A return -ENXIO;
1450N/A
1450N/A return ret;
1450N/A}
1450N/A
1450N/Astatic int
1450N/Ai2c_do_transfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
1450N/A{
1450N/A struct i2c_msg *msg;
1450N/A int i, ret = 0;
1450N/A
1450N/A for (i = 0; i < num; i++) {
1450N/A msg = &msgs[i];
1450N/A
1450N/A if (!(i && (msg->flags & I2C_M_NOSTART))) {
1450N/A ret = i2c_start(adap);
1450N/A if (ret)
1450N/A return ret;
1450N/A
1450N/A ret = i2c_address(adap, msg);
1450N/A if (ret)
1450N/A return ret;
1450N/A }
1450N/A
1450N/A if (msg->flags & I2C_M_RD)
1450N/A ret = i2c_read_msg(adap, msg);
1450N/A else
1450N/A ret = i2c_write_msg(adap, msg);
1450N/A if (ret)
1450N/A return ret;
1450N/A }
1450N/A
1450N/A ret = i2c_stop(adap);
1450N/A if (ret)
1450N/A return ret;
1450N/A
1450N/A return num;
1450N/A}
1450N/A
1450N/Astruct i2c_algorithm i2c_bit_algo = {
1450N/A .master_xfer = i2c_do_transfer,
1450N/A .functionality = NULL,
1450N/A};
1450N/A
1450N/Aint
1450N/Ai2c_bit_add_bus(struct i2c_adapter *adap)
1450N/A{
1450N/A if (!adap->setscl || !adap->getscl || !adap->setsda || !adap->getsda)
1450N/A return -EINVAL;
1450N/A
1450N/A adap->algo = (struct i2c_algorithm *)&i2c_bit_algo;
1450N/A adap->retries = 3;
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/Aint
1450N/Ai2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1450N/A{
1450N/A clock_t start;
1450N/A int i, ret = 0;
1450N/A
1450N/A mutex_enter(&adap->bus_lock);
1450N/A start = ddi_get_lbolt();
1450N/A for (i = 0; i <= adap->retries; i++) {
1450N/A ret = adap->algo->master_xfer(adap, msgs, num);
1450N/A switch (ret) {
1450N/A case 0:
1450N/A case ETIMEDOUT:
1450N/A goto do_exit;
1450N/A default:
1450N/A break;
1450N/A }
1450N/A
1450N/A /* FIXME: Does ddi_get_lbolt() return negative
1450N/A * value? If so, leave me.
1450N/A */
1450N/A if ((ddi_get_lbolt() - start) > adap->timeout)
1450N/A break;
1450N/A }
1450N/A
1450N/Ado_exit:
1450N/A mutex_exit(&adap->bus_lock);
1450N/A return ret;
1450N/A}