summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-20 13:52:52 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-20 13:52:52 -0800
commita4e1328a9d20ccf4a9e5a19fce172e6deb2a33e2 (patch)
tree6dca79d197408609608a1d3ac732dbbc94587f6f /drivers
parentcdce6ac277a4a1aa5316cd0cdf30fff927433917 (diff)
parentfe07adec730d271c91f4160f96a0f24fe7553c63 (diff)
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull more i2c updates from Wolfram Sang: "Included are two bugfixes needing some bigger refactoring (sh_mobile: deferred probe with DMA, mv64xxx: fix offload support) and one deprecated driver removal I thought would go in via ppc but I misunderstood. It has a proper ack from BenH" * 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: sh_mobile: fix uninitialized var when debug is enabled macintosh: therm_pm72: delete deprecated driver i2c: sh_mobile: I2C_SH_MOBILE should depend on HAS_DMA i2c: sh_mobile: rework deferred probing i2c: sh_mobile: refactor DMA setup i2c: mv64xxx: rework offload support to fix several problems i2c: mv64xxx: use BIT() macro for register value definitions
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c328
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c112
-rw-r--r--drivers/macintosh/Kconfig10
-rw-r--r--drivers/macintosh/Makefile1
-rw-r--r--drivers/macintosh/therm_pm72.c2278
-rw-r--r--drivers/macintosh/therm_pm72.h326
7 files changed, 252 insertions, 2804 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 91a488c7cc44..31e8308ba899 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -753,6 +753,7 @@ config I2C_SH7760
config I2C_SH_MOBILE
tristate "SuperH Mobile I2C Controller"
+ depends on HAS_DMA
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 373f6d4e4080..30059c1df2a3 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -30,12 +30,12 @@
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
-#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004
-#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008
-#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010
-#define MV64XXX_I2C_REG_CONTROL_START 0x00000020
-#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040
-#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080
+#define MV64XXX_I2C_REG_CONTROL_ACK BIT(2)
+#define MV64XXX_I2C_REG_CONTROL_IFLG BIT(3)
+#define MV64XXX_I2C_REG_CONTROL_STOP BIT(4)
+#define MV64XXX_I2C_REG_CONTROL_START BIT(5)
+#define MV64XXX_I2C_REG_CONTROL_TWSIEN BIT(6)
+#define MV64XXX_I2C_REG_CONTROL_INTEN BIT(7)
/* Ctlr status values */
#define MV64XXX_I2C_STATUS_BUS_ERR 0x00
@@ -68,19 +68,17 @@
#define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0
/* Bridge Control values */
-#define MV64XXX_I2C_BRIDGE_CONTROL_WR 0x00000001
-#define MV64XXX_I2C_BRIDGE_CONTROL_RD 0x00000002
+#define MV64XXX_I2C_BRIDGE_CONTROL_WR BIT(0)
+#define MV64XXX_I2C_BRIDGE_CONTROL_RD BIT(1)
#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT 2
-#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT 0x00001000
+#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT BIT(12)
#define MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT 13
#define MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT 16
-#define MV64XXX_I2C_BRIDGE_CONTROL_ENABLE 0x00080000
+#define MV64XXX_I2C_BRIDGE_CONTROL_ENABLE BIT(19)
+#define MV64XXX_I2C_BRIDGE_CONTROL_REPEATED_START BIT(20)
/* Bridge Status values */
-#define MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x00000001
-#define MV64XXX_I2C_STATUS_OFFLOAD_ERROR 0xf0000001
-#define MV64XXX_I2C_STATUS_OFFLOAD_OK 0xf0000000
-
+#define MV64XXX_I2C_BRIDGE_STATUS_ERROR BIT(0)
/* Driver states */
enum {
@@ -99,14 +97,12 @@ enum {
MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_SEND_RESTART,
- MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1,
MV64XXX_I2C_ACTION_SEND_ADDR_2,
MV64XXX_I2C_ACTION_SEND_DATA,
MV64XXX_I2C_ACTION_RCV_DATA,
MV64XXX_I2C_ACTION_RCV_DATA_STOP,
MV64XXX_I2C_ACTION_SEND_STOP,
- MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP,
};
struct mv64xxx_i2c_regs {
@@ -193,75 +189,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
}
}
-static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
-{
- unsigned long data_reg_hi = 0;
- unsigned long data_reg_lo = 0;
- unsigned long ctrl_reg;
- struct i2c_msg *msg = drv_data->msgs;
-
- if (!drv_data->offload_enabled)
- return -EOPNOTSUPP;
-
- /* Only regular transactions can be offloaded */
- if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
- return -EINVAL;
-
- /* Only 1-8 byte transfers can be offloaded */
- if (msg->len < 1 || msg->len > 8)
- return -EINVAL;
-
- /* Build transaction */
- ctrl_reg = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE |
- (msg->addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT);
-
- if ((msg->flags & I2C_M_TEN) != 0)
- ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT;
-
- if ((msg->flags & I2C_M_RD) == 0) {
- u8 local_buf[8] = { 0 };
-
- memcpy(local_buf, msg->buf, msg->len);
- data_reg_lo = cpu_to_le32(*((u32 *)local_buf));
- data_reg_hi = cpu_to_le32(*((u32 *)(local_buf+4)));
-
- ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
- (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT;
-
- writel(data_reg_lo,
- drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
- writel(data_reg_hi,
- drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
-
- } else {
- ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_RD |
- (msg->len - 1) << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT;
- }
-
- /* Execute transaction */
- writel(ctrl_reg, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
-
- return 0;
-}
-
-static void
-mv64xxx_i2c_update_offload_data(struct mv64xxx_i2c_data *drv_data)
-{
- struct i2c_msg *msg = drv_data->msg;
-
- if (msg->flags & I2C_M_RD) {
- u32 data_reg_lo = readl(drv_data->reg_base +
- MV64XXX_I2C_REG_RX_DATA_LO);
- u32 data_reg_hi = readl(drv_data->reg_base +
- MV64XXX_I2C_REG_RX_DATA_HI);
- u8 local_buf[8] = { 0 };
-
- *((u32 *)local_buf) = le32_to_cpu(data_reg_lo);
- *((u32 *)(local_buf+4)) = le32_to_cpu(data_reg_hi);
- memcpy(msg->buf, local_buf, msg->len);
- }
-
-}
/*
*****************************************************************************
*
@@ -389,16 +316,6 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
drv_data->rc = -ENXIO;
break;
- case MV64XXX_I2C_STATUS_OFFLOAD_OK:
- if (drv_data->send_stop || drv_data->aborting) {
- drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP;
- drv_data->state = MV64XXX_I2C_STATE_IDLE;
- } else {
- drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_RESTART;
- drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
- }
- break;
-
default:
dev_err(&drv_data->adapter.dev,
"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
@@ -419,25 +336,15 @@ static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
drv_data->aborting = 0;
drv_data->rc = 0;
- /* Can we offload this msg ? */
- if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
- /* No, switch to standard path */
- mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
- writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
- drv_data->reg_base + drv_data->reg_offsets.control);
- }
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+ writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+ drv_data->reg_base + drv_data->reg_offsets.control);
}
static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
switch(drv_data->action) {
- case MV64XXX_I2C_ACTION_OFFLOAD_RESTART:
- mv64xxx_i2c_update_offload_data(drv_data);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
- writel(0, drv_data->reg_base +
- MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
- /* FALLTHRU */
case MV64XXX_I2C_ACTION_SEND_RESTART:
/* We should only get here if we have further messages */
BUG_ON(drv_data->num_msgs == 0);
@@ -518,16 +425,71 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
+ }
+}
- case MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP:
- mv64xxx_i2c_update_offload_data(drv_data);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
- writel(0, drv_data->reg_base +
- MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
- drv_data->block = 0;
- wake_up(&drv_data->waitq);
- break;
+static void
+mv64xxx_i2c_read_offload_rx_data(struct mv64xxx_i2c_data *drv_data,
+ struct i2c_msg *msg)
+{
+ u32 buf[2];
+
+ buf[0] = readl(drv_data->reg_base + MV64XXX_I2C_REG_RX_DATA_LO);
+ buf[1] = readl(drv_data->reg_base + MV64XXX_I2C_REG_RX_DATA_HI);
+
+ memcpy(msg->buf, buf, msg->len);
+}
+
+static int
+mv64xxx_i2c_intr_offload(struct mv64xxx_i2c_data *drv_data)
+{
+ u32 cause, status;
+
+ cause = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ if (!cause)
+ return IRQ_NONE;
+
+ status = readl(drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_STATUS);
+
+ if (status & MV64XXX_I2C_BRIDGE_STATUS_ERROR) {
+ drv_data->rc = -EIO;
+ goto out;
+ }
+
+ drv_data->rc = 0;
+
+ /*
+ * Transaction is a one message read transaction, read data
+ * for this message.
+ */
+ if (drv_data->num_msgs == 1 && drv_data->msgs[0].flags & I2C_M_RD) {
+ mv64xxx_i2c_read_offload_rx_data(drv_data, drv_data->msgs);
+ drv_data->msgs++;
+ drv_data->num_msgs--;
+ }
+ /*
+ * Transaction is a two messages write/read transaction, read
+ * data for the second (read) message.
+ */
+ else if (drv_data->num_msgs == 2 &&
+ !(drv_data->msgs[0].flags & I2C_M_RD) &&
+ drv_data->msgs[1].flags & I2C_M_RD) {
+ mv64xxx_i2c_read_offload_rx_data(drv_data, drv_data->msgs + 1);
+ drv_data->msgs += 2;
+ drv_data->num_msgs -= 2;
}
+
+out:
+ writel(0, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ writel(0, drv_data->reg_base +
+ MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE);
+ drv_data->block = 0;
+
+ wake_up(&drv_data->waitq);
+
+ return IRQ_HANDLED;
}
static irqreturn_t
@@ -540,20 +502,9 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
spin_lock_irqsave(&drv_data->lock, flags);
- if (drv_data->offload_enabled) {
- while (readl(drv_data->reg_base +
- MV64XXX_I2C_REG_BRIDGE_INTR_CAUSE)) {
- int reg_status = readl(drv_data->reg_base +
- MV64XXX_I2C_REG_BRIDGE_STATUS);
- if (reg_status & MV64XXX_I2C_BRIDGE_STATUS_ERROR)
- status = MV64XXX_I2C_STATUS_OFFLOAD_ERROR;
- else
- status = MV64XXX_I2C_STATUS_OFFLOAD_OK;
- mv64xxx_i2c_fsm(drv_data, status);
- mv64xxx_i2c_do_action(drv_data);
- rc = IRQ_HANDLED;
- }
- }
+ if (drv_data->offload_enabled)
+ rc = mv64xxx_i2c_intr_offload(drv_data);
+
while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
@@ -635,6 +586,117 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
return drv_data->rc;
}
+static void
+mv64xxx_i2c_prepare_tx(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msg = drv_data->msgs;
+ u32 buf[2];
+
+ memcpy(buf, msg->buf, msg->len);
+
+ writel(buf[0], drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_LO);
+ writel(buf[1], drv_data->reg_base + MV64XXX_I2C_REG_TX_DATA_HI);
+}
+
+static int
+mv64xxx_i2c_offload_xfer(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msgs = drv_data->msgs;
+ int num = drv_data->num_msgs;
+ unsigned long ctrl_reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /* Build transaction */
+ ctrl_reg = MV64XXX_I2C_BRIDGE_CONTROL_ENABLE |
+ (msgs[0].addr << MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT);
+
+ if (msgs[0].flags & I2C_M_TEN)
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_ADDR_EXT;
+
+ /* Single write message transaction */
+ if (num == 1 && !(msgs[0].flags & I2C_M_RD)) {
+ size_t len = msgs[0].len - 1;
+
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_WR |
+ (len << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT);
+ mv64xxx_i2c_prepare_tx(drv_data);
+ }
+ /* Single read message transaction */
+ else if (num == 1 && msgs[0].flags & I2C_M_RD) {
+ size_t len = msgs[0].len - 1;
+
+ ctrl_reg |= MV64XXX_I2C_BRIDGE_CONTROL_RD |
+ (len << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT);
+ }
+ /*
+ * Transaction with one write and one read message. This is
+ * guaranteed by the mv64xx_i2c_can_offload() checks.
+ */
+ else if (num == 2) {
+ size_t lentx = msgs[0].len - 1;
+ size_t lenrx = msgs[1].len - 1;
+
+ ctrl_reg |=
+ MV64XXX_I2C_BRIDGE_CONTROL_RD |
+ MV64XXX_I2C_BRIDGE_CONTROL_WR |
+ (lentx << MV64XXX_I2C_BRIDGE_CONTROL_TX_SIZE_SHIFT) |
+ (lenrx << MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT) |
+ MV64XXX_I2C_BRIDGE_CONTROL_REPEATED_START;
+ mv64xxx_i2c_prepare_tx(drv_data);
+ }
+
+ /* Execute transaction */
+ drv_data->block = 1;
+ writel(ctrl_reg, drv_data->reg_base + MV64XXX_I2C_REG_BRIDGE_CONTROL);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ mv64xxx_i2c_wait_for_completion(drv_data);
+
+ return drv_data->rc;
+}
+
+static bool
+mv64xxx_i2c_valid_offload_sz(struct i2c_msg *msg)
+{
+ return msg->len <= 8 && msg->len >= 1;
+}
+
+static bool
+mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data)
+{
+ struct i2c_msg *msgs = drv_data->msgs;
+ int num = drv_data->num_msgs;
+
+ return false;
+
+ if (!drv_data->offload_enabled)
+ return false;
+
+ /*
+ * We can offload a transaction consisting of a single
+ * message, as long as the message has a length between 1 and
+ * 8 bytes.
+ */
+ if (num == 1 && mv64xxx_i2c_valid_offload_sz(msgs))
+ return true;
+
+ /*
+ * We can offload a transaction consisting of two messages, if
+ * the first is a write and a second is a read, and both have
+ * a length between 1 and 8 bytes.
+ */
+ if (num == 2 &&
+ mv64xxx_i2c_valid_offload_sz(msgs) &&
+ mv64xxx_i2c_valid_offload_sz(msgs + 1) &&
+ !(msgs[0].flags & I2C_M_RD) &&
+ msgs[1].flags & I2C_M_RD)
+ return true;
+
+ return false;
+}
+
/*
*****************************************************************************
*
@@ -658,7 +720,11 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
drv_data->msgs = msgs;
drv_data->num_msgs = num;
- rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
+ if (mv64xxx_i2c_can_offload(drv_data))
+ rc = mv64xxx_i2c_offload_xfer(drv_data);
+ else
+ rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
+
if (rc < 0)
ret = rc;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index d7efaf44868b..440d5dbc8b5f 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -140,6 +140,7 @@ struct sh_mobile_i2c_data {
int sr;
bool send_stop;
+ struct resource *res;
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
struct scatterlist sg;
@@ -539,6 +540,42 @@ static void sh_mobile_i2c_dma_callback(void *data)
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
+static struct dma_chan *sh_mobile_i2c_request_dma_chan(struct device *dev,
+ enum dma_transfer_direction dir, dma_addr_t port_addr)
+{
+ struct dma_chan *chan;
+ struct dma_slave_config cfg;
+ char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
+ int ret;
+
+ chan = dma_request_slave_channel_reason(dev, chan_name);
+ if (IS_ERR(chan)) {
+ ret = PTR_ERR(chan);
+ dev_dbg(dev, "request_channel failed for %s (%d)\n", chan_name, ret);
+ return chan;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.direction = dir;
+ if (dir == DMA_MEM_TO_DEV) {
+ cfg.dst_addr = port_addr;
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ } else {
+ cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
+
+ ret = dmaengine_slave_config(chan, &cfg);
+ if (ret) {
+ dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret);
+ dma_release_channel(chan);
+ return ERR_PTR(ret);
+ }
+
+ dev_dbg(dev, "got DMA channel for %s\n", chan_name);
+ return chan;
+}
+
static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
{
bool read = pd->msg->flags & I2C_M_RD;
@@ -548,7 +585,16 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
dma_addr_t dma_addr;
dma_cookie_t cookie;
- if (!chan)
+ if (PTR_ERR(chan) == -EPROBE_DEFER) {
+ if (read)
+ chan = pd->dma_rx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM,
+ pd->res->start + ICDR);
+ else
+ chan = pd->dma_tx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV,
+ pd->res->start + ICDR);
+ }
+
+ if (IS_ERR(chan))
return;
dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir);
@@ -747,56 +793,16 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids);
-static int sh_mobile_i2c_request_dma_chan(struct device *dev, enum dma_transfer_direction dir,
- dma_addr_t port_addr, struct dma_chan **chan_ptr)
-{
- struct dma_chan *chan;
- struct dma_slave_config cfg;
- char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
- int ret;
-
- *chan_ptr = NULL;
-
- chan = dma_request_slave_channel_reason(dev, chan_name);
- if (IS_ERR(chan)) {
- ret = PTR_ERR(chan);
- dev_dbg(dev, "request_channel failed for %s (%d)\n", chan_name, ret);
- return ret;
- }
-
- memset(&cfg, 0, sizeof(cfg));
- cfg.direction = dir;
- if (dir == DMA_MEM_TO_DEV) {
- cfg.dst_addr = port_addr;
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- } else {
- cfg.src_addr = port_addr;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- }
-
- ret = dmaengine_slave_config(chan, &cfg);
- if (ret) {
- dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret);
- dma_release_channel(chan);
- return ret;
- }
-
- *chan_ptr = chan;
-
- dev_dbg(dev, "got DMA channel for %s\n", chan_name);
- return 0;
-}
-
static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd)
{
- if (pd->dma_tx) {
+ if (!IS_ERR(pd->dma_tx)) {
dma_release_channel(pd->dma_tx);
- pd->dma_tx = NULL;
+ pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
}
- if (pd->dma_rx) {
+ if (!IS_ERR(pd->dma_rx)) {
dma_release_channel(pd->dma_rx);
- pd->dma_rx = NULL;
+ pd->dma_rx = ERR_PTR(-EPROBE_DEFER);
}
}
@@ -849,6 +855,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ pd->res = res;
pd->reg = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(pd->reg))
return PTR_ERR(pd->reg);
@@ -889,17 +896,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
/* Init DMA */
sg_init_table(&pd->sg, 1);
pd->dma_direction = DMA_NONE;
- ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM,
- res->start + ICDR, &pd->dma_rx);
- if (ret == -EPROBE_DEFER)
- return ret;
-
- ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV,
- res->start + ICDR, &pd->dma_tx);
- if (ret == -EPROBE_DEFER) {
- sh_mobile_i2c_release_dma(pd);
- return ret;
- }
+ pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* Enable Runtime PM for this device.
*
@@ -937,8 +934,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return ret;
}
- dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz, DMA=%c\n",
- adap->nr, pd->bus_speed, (pd->dma_rx || pd->dma_tx) ? 'y' : 'n');
+ dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz\n", adap->nr, pd->bus_speed);
return 0;
}
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 3067d56b11a6..5844b80bd90e 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -204,16 +204,6 @@ config THERM_ADT746X
iBook G4, and the ATI based aluminium PowerBooks, allowing slightly
better fan behaviour by default, and some manual control.
-config THERM_PM72
- tristate "Support for thermal management on PowerMac G5 (AGP)"
- depends on I2C && I2C_POWERMAC && PPC_PMAC64
- default n
- help
- This driver provides thermostat and fan control for the desktop
- G5 machines.
-
- This is deprecated, use windfarm instead.
-
config WINDFARM
tristate "New PowerMac thermal control infrastructure"
depends on PPC
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index d2f0120bc878..383ba920085b 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_ADB_IOP) += adb-iop.o
obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o
obj-$(CONFIG_ADB_MACIO) += macio-adb.o
-obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
deleted file mode 100644
index 7ed92582d2cf..000000000000
--- a/drivers/macintosh/therm_pm72.c
+++ /dev/null
@@ -1,2278 +0,0 @@
-/*
- * Device driver for the thermostats & fan controller of the
- * Apple G5 "PowerMac7,2" desktop machines.
- *
- * (c) Copyright IBM Corp. 2003-2004
- *
- * Maintained by: Benjamin Herrenschmidt
- * <benh@kernel.crashing.org>
- *
- *
- * The algorithm used is the PID control algorithm, used the same
- * way the published Darwin code does, using the same values that
- * are present in the Darwin 7.0 snapshot property lists.
- *
- * As far as the CPUs control loops are concerned, I use the
- * calibration & PID constants provided by the EEPROM,
- * I do _not_ embed any value from the property lists, as the ones
- * provided by Darwin 7.0 seem to always have an older version that
- * what I've seen on the actual computers.
- * It would be interesting to verify that though. Darwin has a
- * version code of 1.0.0d11 for all control loops it seems, while
- * so far, the machines EEPROMs contain a dataset versioned 1.0.0f
- *
- * Darwin doesn't provide source to all parts, some missing
- * bits like the AppleFCU driver or the actual scale of some
- * of the values returned by sensors had to be "guessed" some
- * way... or based on what Open Firmware does.
- *
- * I didn't yet figure out how to get the slots power consumption
- * out of the FCU, so that part has not been implemented yet and
- * the slots fan is set to a fixed 50% PWM, hoping this value is
- * safe enough ...
- *
- * Note: I have observed strange oscillations of the CPU control
- * loop on a dual G5 here. When idle, the CPU exhaust fan tend to
- * oscillates slowly (over several minutes) between the minimum
- * of 300RPMs and approx. 1000 RPMs. I don't know what is causing
- * this, it could be some incorrect constant or an error in the
- * way I ported the algorithm, or it could be just normal. I
- * don't have full understanding on the way Apple tweaked the PID
- * algorithm for the CPU control, it is definitely not a standard
- * implementation...
- *
- * TODO: - Check MPU structure version/signature
- * - Add things like /sbin/overtemp for non-critical
- * overtemp conditions so userland can take some policy
- * decisions, like slowing down CPUs
- * - Deal with fan and i2c failures in a better way
- * - Maybe do a generic PID based on params used for
- * U3 and Drives ? Definitely need to factor code a bit
- * better... also make sensor detection more robust using
- * the device-tree to probe for them
- * - Figure out how to get the slots consumption and set the
- * slots fan accordingly
- *
- * History:
- *
- * Nov. 13, 2003 : 0.5
- * - First release
- *
- * Nov. 14, 2003 : 0.6
- * - Read fan speed from FCU, low level fan routines now deal
- * with errors & check fan status, though higher level don't
- * do much.
- * - Move a bunch of definitions to .h file
- *
- * Nov. 18, 2003 : 0.7
- * - Fix build on ppc64 kernel
- * - Move back statics definitions to .c file
- * - Avoid calling schedule_timeout with a negative number
- *
- * Dec. 18, 2003 : 0.8
- * - Fix typo when reading back fan speed on 2 CPU machines
- *
- * Mar. 11, 2004 : 0.9
- * - Rework code accessing the ADC chips, make it more robust and
- * closer to the chip spec. Also make sure it is configured properly,
- * I've seen yet unexplained cases where on startup, I would have stale
- * values in the configuration register
- * - Switch back to use of target fan speed for PID, thus lowering
- * pressure on i2c
- *
- * Oct. 20, 2004 : 1.1
- * - Add device-tree lookup for fan IDs, should detect liquid cooling
- * pumps when present
- * - Enable driver for PowerMac7,3 machines
- * - Split the U3/Backside cooling on U3 & U3H versions as Darwin does
- * - Add new CPU cooling algorithm for machines with liquid cooling
- * - Workaround for some PowerMac7,3 with empty "fan" node in the devtree
- * - Fix a signed/unsigned compare issue in some PID loops
- *
- * Mar. 10, 2005 : 1.2
- * - Add basic support for Xserve G5
- * - Retrieve pumps min/max from EEPROM image in device-tree (broken)
- * - Use min/max macros here or there
- * - Latest darwin updated U3H min fan speed to 20% PWM
- *
- * July. 06, 2006 : 1.3
- * - Fix setting of RPM fans on Xserve G5 (they were going too fast)
- * - Add missing slots fan control loop for Xserve G5
- * - Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
- * still can't properly implement the control loop for these, so let's
- * reduce the noise a little bit, it appears that 40% still gives us
- * a pretty good air flow
- * - Add code to "tickle" the FCU regulary so it doesn't think that
- * we are gone while in fact, the machine just didn't need any fan
- * speed change lately
- *
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/reboot.h>
-#include <linux/kmod.h>
-#include <linux/i2c.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/sections.h>
-#include <asm/macio.h>
-
-#include "therm_pm72.h"
-
-#define VERSION "1.3"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(args...) printk(args)
-#else
-#define DBG(args...) do { } while(0)
-#endif
-
-
-/*
- * Driver statics
- */
-
-static struct platform_device * of_dev;
-static struct i2c_adapter * u3_0;
-static struct i2c_adapter * u3_1;
-static struct i2c_adapter * k2;
-static struct i2c_client * fcu;
-static struct cpu_pid_state processor_state[2];
-static struct basckside_pid_params backside_params;
-static struct backside_pid_state backside_state;
-static struct drives_pid_state drives_state;
-static struct dimm_pid_state dimms_state;
-static struct slots_pid_state slots_state;
-static int state;
-static int cpu_count;
-static int cpu_pid_type;
-static struct task_struct *ctrl_task;
-static struct completion ctrl_complete;
-static int critical_state;
-static int rackmac;
-static s32 dimm_output_clamp;
-static int fcu_rpm_shift;
-static int fcu_tickle_ticks;
-static DEFINE_MUTEX(driver_lock);
-
-/*
- * We have 3 types of CPU PID control. One is "split" old style control
- * for intake & exhaust fans, the other is "combined" control for both
- * CPUs that also deals with the pumps when present. To be "compatible"
- * with OS X at this point, we only use "COMBINED" on the machines that
- * are identified as having the pumps (though that identification is at
- * least dodgy). Ultimately, we could probably switch completely to this
- * algorithm provided we hack it to deal with the UP case
- */
-#define CPU_PID_TYPE_SPLIT 0
-#define CPU_PID_TYPE_COMBINED 1
-#define CPU_PID_TYPE_RACKMAC 2
-
-/*
- * This table describes all fans in the FCU. The "id" and "type" values
- * are defaults valid for all earlier machines. Newer machines will
- * eventually override the table content based on the device-tree
- */
-struct fcu_fan_table
-{
- char* loc; /* location code */
- int type; /* 0 = rpm, 1 = pwm, 2 = pump */
- int id; /* id or -1 */
-};
-
-#define FCU_FAN_RPM 0
-#define FCU_FAN_PWM 1
-
-#define FCU_FAN_ABSENT_ID -1
-
-#define FCU_FAN_COUNT ARRAY_SIZE(fcu_fans)
-
-struct fcu_fan_table fcu_fans[] = {
- [BACKSIDE_FAN_PWM_INDEX] = {
- .loc = "BACKSIDE,SYS CTRLR FAN",
- .type = FCU_FAN_PWM,
- .id = BACKSIDE_FAN_PWM_DEFAULT_ID,
- },
- [DRIVES_FAN_RPM_INDEX] = {
- .loc = "DRIVE BAY",
- .type = FCU_FAN_RPM,
- .id = DRIVES_FAN_RPM_DEFAULT_ID,
- },
- [SLOTS_FAN_PWM_INDEX] = {
- .loc = "SLOT,PCI FAN",
- .type = FCU_FAN_PWM,
- .id = SLOTS_FAN_PWM_DEFAULT_ID,
- },
- [CPUA_INTAKE_FAN_RPM_INDEX] = {
- .loc = "CPU A INTAKE",
- .type = FCU_FAN_RPM,
- .id = CPUA_INTAKE_FAN_RPM_DEFAULT_ID,
- },
- [CPUA_EXHAUST_FAN_RPM_INDEX] = {
- .loc = "CPU A EXHAUST",
- .type = FCU_FAN_RPM,
- .id = CPUA_EXHAUST_FAN_RPM_DEFAULT_ID,
- },
- [CPUB_INTAKE_FAN_RPM_INDEX] = {
- .loc = "CPU B INTAKE",
- .type = FCU_FAN_RPM,
- .id = CPUB_INTAKE_FAN_RPM_DEFAULT_ID,
- },
- [CPUB_EXHAUST_FAN_RPM_INDEX] = {
- .loc = "CPU B EXHAUST",
- .type = FCU_FAN_RPM,
- .id = CPUB_EXHAUST_FAN_RPM_DEFAULT_ID,
- },
- /* pumps aren't present by default, have to be looked up in the
- * device-tree
- */
- [CPUA_PUMP_RPM_INDEX] = {
- .loc = "CPU A PUMP",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPUB_PUMP_RPM_INDEX] = {
- .loc = "CPU B PUMP",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- /* Xserve fans */
- [CPU_A1_FAN_RPM_INDEX] = {
- .loc = "CPU A 1",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPU_A2_FAN_RPM_INDEX] = {
- .loc = "CPU A 2",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPU_A3_FAN_RPM_INDEX] = {
- .loc = "CPU A 3",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPU_B1_FAN_RPM_INDEX] = {
- .loc = "CPU B 1",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPU_B2_FAN_RPM_INDEX] = {
- .loc = "CPU B 2",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
- [CPU_B3_FAN_RPM_INDEX] = {
- .loc = "CPU B 3",
- .type = FCU_FAN_RPM,
- .id = FCU_FAN_ABSENT_ID,
- },
-};
-
-static struct i2c_driver therm_pm72_driver;
-
-/*
- * Utility function to create an i2c_client structure and
- * attach it to one of u3 adapters
- */
-static struct i2c_client *attach_i2c_chip(int id, const char *name)
-{
- struct i2c_client *clt;
- struct i2c_adapter *adap;
- struct i2c_board_info info;
-
- if (id & 0x200)
- adap = k2;
- else if (id & 0x100)
- adap = u3_1;
- else
- adap = u3_0;
- if (adap == NULL)
- return NULL;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = (id >> 1) & 0x7f;
- strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE);
- clt = i2c_new_device(adap, &info);
- if (!clt) {
- printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id);
- return NULL;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&clt->detected, &therm_pm72_driver.clients);
- return clt;
-}
-
-/*
- * Here are the i2c chip access wrappers
- */
-
-static void initialize_adc(struct cpu_pid_state *state)
-{
- int rc;
- u8 buf[2];
-
- /* Read ADC the configuration register and cache it. We
- * also make sure Config2 contains proper values, I've seen
- * cases where we got stale grabage in there, thus preventing
- * proper reading of conv. values
- */
-
- /* Clear Config2 */
- buf[0] = 5;
- buf[1] = 0;
- i2c_master_send(state->monitor, buf, 2);
-
- /* Read & cache Config1 */
- buf[0] = 1;
- rc = i2c_master_send(state->monitor, buf, 1);
- if (rc > 0) {
- rc = i2c_master_recv(state->monitor, buf, 1);
- if (rc > 0) {
- state->adc_config = buf[0];
- DBG("ADC config reg: %02x\n", state->adc_config);
- /* Disable shutdown mode */
- state->adc_config &= 0xfe;
- buf[0] = 1;
- buf[1] = state->adc_config;
- rc = i2c_master_send(state->monitor, buf, 2);
- }
- }
- if (rc <= 0)
- printk(KERN_ERR "therm_pm72: Error reading ADC config"
- " register !\n");
-}
-
-static int read_smon_adc(struct cpu_pid_state *state, int chan)
-{
- int rc, data, tries = 0;
- u8 buf[2];
-
- for (;;) {
- /* Set channel */
- buf[0] = 1;
- buf[1] = (state->adc_config & 0x1f) | (chan << 5);
- rc = i2c_master_send(state->monitor, buf, 2);
- if (rc <= 0)
- goto error;
- /* Wait for conversion */
- msleep(1);
- /* Switch to data register */
- buf[0] = 4;
- rc = i2c_master_send(state->monitor, buf, 1);
- if (rc <= 0)
- goto error;
- /* Re