diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-20 13:52:52 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-20 13:52:52 -0800 |
commit | a4e1328a9d20ccf4a9e5a19fce172e6deb2a33e2 (patch) | |
tree | 6dca79d197408609608a1d3ac732dbbc94587f6f | |
parent | cdce6ac277a4a1aa5316cd0cdf30fff927433917 (diff) | |
parent | fe07adec730d271c91f4160f96a0f24fe7553c63 (diff) | |
download | linux-a4e1328a9d20ccf4a9e5a19fce172e6deb2a33e2.tar.gz linux-a4e1328a9d20ccf4a9e5a19fce172e6deb2a33e2.tar.bz2 linux-a4e1328a9d20ccf4a9e5a19fce172e6deb2a33e2.zip |
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
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 328 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 112 | ||||
-rw-r--r-- | drivers/macintosh/Kconfig | 10 | ||||
-rw-r--r-- | drivers/macintosh/Makefile | 1 | ||||
-rw-r--r-- | drivers/macintosh/therm_pm72.c | 2278 | ||||
-rw-r--r-- | drivers/macintosh/therm_pm72.h | 326 |
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" |