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
This commit is contained in:
Linus Torvalds 2014-12-20 13:52:52 -08:00
commit a4e1328a9d
7 changed files with 253 additions and 2805 deletions

View File

@ -753,6 +753,7 @@ config I2C_SH7760
config I2C_SH_MOBILE config I2C_SH_MOBILE
tristate "SuperH Mobile I2C Controller" tristate "SuperH Mobile I2C Controller"
depends on HAS_DMA
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the

View File

@ -30,12 +30,12 @@
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7) #define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3) #define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 #define MV64XXX_I2C_REG_CONTROL_ACK BIT(2)
#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 #define MV64XXX_I2C_REG_CONTROL_IFLG BIT(3)
#define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 #define MV64XXX_I2C_REG_CONTROL_STOP BIT(4)
#define MV64XXX_I2C_REG_CONTROL_START 0x00000020 #define MV64XXX_I2C_REG_CONTROL_START BIT(5)
#define MV64XXX_I2C_REG_CONTROL_TWSIEN 0x00000040 #define MV64XXX_I2C_REG_CONTROL_TWSIEN BIT(6)
#define MV64XXX_I2C_REG_CONTROL_INTEN 0x00000080 #define MV64XXX_I2C_REG_CONTROL_INTEN BIT(7)
/* Ctlr status values */ /* Ctlr status values */
#define MV64XXX_I2C_STATUS_BUS_ERR 0x00 #define MV64XXX_I2C_STATUS_BUS_ERR 0x00
@ -68,19 +68,17 @@
#define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0 #define MV64XXX_I2C_REG_BRIDGE_TIMING 0xe0
/* Bridge Control values */ /* Bridge Control values */
#define MV64XXX_I2C_BRIDGE_CONTROL_WR 0x00000001 #define MV64XXX_I2C_BRIDGE_CONTROL_WR BIT(0)
#define MV64XXX_I2C_BRIDGE_CONTROL_RD 0x00000002 #define MV64XXX_I2C_BRIDGE_CONTROL_RD BIT(1)
#define MV64XXX_I2C_BRIDGE_CONTROL_ADDR_SHIFT 2 #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_TX_SIZE_SHIFT 13
#define MV64XXX_I2C_BRIDGE_CONTROL_RX_SIZE_SHIFT 16 #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 */ /* Bridge Status values */
#define MV64XXX_I2C_BRIDGE_STATUS_ERROR 0x00000001 #define MV64XXX_I2C_BRIDGE_STATUS_ERROR BIT(0)
#define MV64XXX_I2C_STATUS_OFFLOAD_ERROR 0xf0000001
#define MV64XXX_I2C_STATUS_OFFLOAD_OK 0xf0000000
/* Driver states */ /* Driver states */
enum { enum {
@ -99,14 +97,12 @@ enum {
MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_INVALID,
MV64XXX_I2C_ACTION_CONTINUE, MV64XXX_I2C_ACTION_CONTINUE,
MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_SEND_RESTART,
MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
MV64XXX_I2C_ACTION_SEND_ADDR_1, MV64XXX_I2C_ACTION_SEND_ADDR_1,
MV64XXX_I2C_ACTION_SEND_ADDR_2, MV64XXX_I2C_ACTION_SEND_ADDR_2,
MV64XXX_I2C_ACTION_SEND_DATA, MV64XXX_I2C_ACTION_SEND_DATA,
MV64XXX_I2C_ACTION_RCV_DATA, MV64XXX_I2C_ACTION_RCV_DATA,
MV64XXX_I2C_ACTION_RCV_DATA_STOP, MV64XXX_I2C_ACTION_RCV_DATA_STOP,
MV64XXX_I2C_ACTION_SEND_STOP, MV64XXX_I2C_ACTION_SEND_STOP,
MV64XXX_I2C_ACTION_OFFLOAD_SEND_STOP,
}; };
struct mv64xxx_i2c_regs { 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; drv_data->rc = -ENXIO;
break; 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: default:
dev_err(&drv_data->adapter.dev, dev_err(&drv_data->adapter.dev,
"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, " "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->aborting = 0;
drv_data->rc = 0; drv_data->rc = 0;
/* Can we offload this msg ? */ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
if (mv64xxx_i2c_offload_msg(drv_data) < 0) { writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
/* No, switch to standard path */ 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 static void
mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{ {
switch(drv_data->action) { 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: case MV64XXX_I2C_ACTION_SEND_RESTART:
/* We should only get here if we have further messages */ /* We should only get here if we have further messages */
BUG_ON(drv_data->num_msgs == 0); BUG_ON(drv_data->num_msgs == 0);
@ -518,18 +425,73 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
drv_data->block = 0; drv_data->block = 0;
wake_up(&drv_data->waitq); wake_up(&drv_data->waitq);
break; 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 static irqreturn_t
mv64xxx_i2c_intr(int irq, void *dev_id) mv64xxx_i2c_intr(int irq, void *dev_id)
{ {
@ -540,20 +502,9 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
spin_lock_irqsave(&drv_data->lock, flags); spin_lock_irqsave(&drv_data->lock, flags);
if (drv_data->offload_enabled) { if (drv_data->offload_enabled)
while (readl(drv_data->reg_base + rc = mv64xxx_i2c_intr_offload(drv_data);
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;
}
}
while (readl(drv_data->reg_base + drv_data->reg_offsets.control) & while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
MV64XXX_I2C_REG_CONTROL_IFLG) { MV64XXX_I2C_REG_CONTROL_IFLG) {
status = readl(drv_data->reg_base + drv_data->reg_offsets.status); 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; 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->msgs = msgs;
drv_data->num_msgs = num; 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) if (rc < 0)
ret = rc; ret = rc;

View File

@ -140,6 +140,7 @@ struct sh_mobile_i2c_data {
int sr; int sr;
bool send_stop; bool send_stop;
struct resource *res;
struct dma_chan *dma_tx; struct dma_chan *dma_tx;
struct dma_chan *dma_rx; struct dma_chan *dma_rx;
struct scatterlist sg; 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); 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) static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
{ {
bool read = pd->msg->flags & I2C_M_RD; 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_addr_t dma_addr;
dma_cookie_t cookie; 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; return;
dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir); 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); 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) 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); 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); 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); res = platform_get_resource(dev, IORESOURCE_MEM, 0);
pd->res = res;
pd->reg = devm_ioremap_resource(&dev->dev, res); pd->reg = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(pd->reg)) if (IS_ERR(pd->reg))
return PTR_ERR(pd->reg); return PTR_ERR(pd->reg);
@ -889,17 +896,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
/* Init DMA */ /* Init DMA */
sg_init_table(&pd->sg, 1); sg_init_table(&pd->sg, 1);
pd->dma_direction = DMA_NONE; pd->dma_direction = DMA_NONE;
ret = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM, pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
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;
}
/* Enable Runtime PM for this device. /* Enable Runtime PM for this device.
* *
@ -937,8 +934,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return ret; return ret;
} }
dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz, DMA=%c\n", dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz\n", adap->nr, pd->bus_speed);
adap->nr, pd->bus_speed, (pd->dma_rx || pd->dma_tx) ? 'y' : 'n');
return 0; return 0;
} }

View File

@ -204,16 +204,6 @@ config THERM_ADT746X
iBook G4, and the ATI based aluminium PowerBooks, allowing slightly iBook G4, and the ATI based aluminium PowerBooks, allowing slightly
better fan behaviour by default, and some manual control. 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 config WINDFARM
tristate "New PowerMac thermal control infrastructure" tristate "New PowerMac thermal control infrastructure"
depends on PPC depends on PPC

View File

@ -25,7 +25,6 @@ obj-$(CONFIG_ADB_IOP) += adb-iop.o
obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o
obj-$(CONFIG_ADB_MACIO) += macio-adb.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_WINDTUNNEL) += therm_windtunnel.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o obj-$(CONFIG_WINDFARM) += windfarm_core.o

File diff suppressed because it is too large Load Diff

View File

@ -1,326 +0,0 @@
#ifndef __THERM_PMAC_7_2_H__
#define __THERM_PMAC_7_2_H__
typedef unsigned short fu16;
typedef int fs32;
typedef short fs16;
struct mpu_data
{
u8 signature; /* 0x00 - EEPROM sig. */
u8 bytes_used; /* 0x01 - Bytes used in eeprom (160 ?) */
u8 size; /* 0x02 - EEPROM size (256 ?) */
u8 version; /* 0x03 - EEPROM version */
u32 data_revision; /* 0x04 - Dataset revision */
u8 processor_bin_code[3]; /* 0x08 - Processor BIN code */
u8 bin_code_expansion; /* 0x0b - ??? (padding ?) */
u8 processor_num; /* 0x0c - Number of CPUs on this MPU */
u8 input_mul_bus_div; /* 0x0d - Clock input multiplier/bus divider */
u8 reserved1[2]; /* 0x0e - */
u32 input_clk_freq_high; /* 0x10 - Input clock frequency high */
u8 cpu_nb_target_cycles; /* 0x14 - ??? */
u8 cpu_statlat; /* 0x15 - ??? */
u8 cpu_snooplat; /* 0x16 - ??? */
u8 cpu_snoopacc; /* 0x17 - ??? */
u8 nb_paamwin; /* 0x18 - ??? */
u8 nb_statlat; /* 0x19 - ??? */
u8 nb_snooplat; /* 0x1a - ??? */
u8 nb_snoopwin; /* 0x1b - ??? */
u8 api_bus_mode; /* 0x1c - ??? */
u8 reserved2[3]; /* 0x1d - */
u32 input_clk_freq_low; /* 0x20 - Input clock frequency low */
u8 processor_card_slot; /* 0x24 - Processor card slot number */
u8 reserved3[2]; /* 0x25 - */
u8 padjmax; /* 0x27 - Max power adjustment (Not in OF!) */
u8 ttarget; /* 0x28 - Target temperature */
u8 tmax; /* 0x29 - Max temperature */
u8 pmaxh; /* 0x2a - Max power */
u8 tguardband; /* 0x2b - Guardband temp ??? Hist. len in OSX */
fs32 pid_gp; /* 0x2c - PID proportional gain */
fs32 pid_gr; /* 0x30 - PID reset gain */
fs32 pid_gd; /* 0x34 - PID derivative gain */
fu16 voph; /* 0x38 - Vop High */
fu16 vopl; /* 0x3a - Vop Low */
fs16 nactual_die; /* 0x3c - nActual Die */
fs16 nactual_heatsink; /* 0x3e - nActual Heatsink */
fs16 nactual_system; /* 0x40 - nActual System */
u16 calibration_flags; /* 0x42 - Calibration flags */
fu16 mdiode; /* 0x44 - Diode M value (scaling factor) */
fs16 bdiode; /* 0x46 - Diode B value (offset) */
fs32 theta_heat_sink; /* 0x48 - Theta heat sink */
u16 rminn_intake_fan; /* 0x4c - Intake fan min RPM */
u16 rmaxn_intake_fan; /* 0x4e - Intake fan max RPM */
u16 rminn_exhaust_fan; /* 0x50 - Exhaust fan min RPM */
u16 rmaxn_exhaust_fan; /* 0x52 - Exhaust fan max RPM */
u8 processor_part_num[8]; /* 0x54 - Processor part number XX pumps min/max */
u32 processor_lot_num; /* 0x5c - Processor lot number */
u8 orig_card_sernum[0x10]; /* 0x60 - Card original serial number */
u8 curr_card_sernum[0x10]; /* 0x70 - Card current serial number */
u8 mlb_sernum[0x18]; /* 0x80 - MLB serial number */
u32 checksum1; /* 0x98 - */
u32 checksum2; /* 0x9c - */
}; /* Total size = 0xa0 */
/* Display a 16.16 fixed point value */
#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
/*
* Maximum number of seconds to be in critical state (after a
* normal shutdown attempt). If the machine isn't down after
* this counter elapses, we force an immediate machine power
* off.
*/
#define MAX_CRITICAL_STATE 30
static char * critical_overtemp_path = "/sbin/critical_overtemp";
/*
* This option is "weird" :) Basically, if you define this to 1
* the control loop for the RPMs fans (not PWMs) will apply the
* correction factor obtained from the PID to the _actual_ RPM
* speed read from the FCU.
* If you define the below constant to 0, then it will be
* applied to the setpoint RPM speed, that is basically the
* speed we proviously "asked" for.
*
* I'm not sure which of these Apple's algorithm is supposed
* to use
*/
#define RPM_PID_USE_ACTUAL_SPEED 0
/*
* i2c IDs. Currently, we hard code those and assume that
* the FCU is on U3 bus 1 while all sensors are on U3 bus
* 0. This appear to be safe enough for this first version
* of the driver, though I would accept any clean patch
* doing a better use of the device-tree without turning the
* while i2c registration mechanism into a racy mess
*
* Note: Xserve changed this. We have some bits on the K2 bus,
* which I arbitrarily set to 0x200. Ultimately, we really want
* too lookup these in the device-tree though
*/
#define FAN_CTRLER_ID 0x15e
#define SUPPLY_MONITOR_ID 0x58
#define SUPPLY_MONITORB_ID 0x5a
#define DRIVES_DALLAS_ID 0x94
#define BACKSIDE_MAX_ID 0x98
#define XSERVE_DIMMS_LM87 0x25a
#define XSERVE_SLOTS_LM75 0x290
/*
* Some MAX6690, DS1775, LM87 register definitions
*/
#define MAX6690_INT_TEMP 0
#define MAX6690_EXT_TEMP 1
#define DS1775_TEMP 0
#define LM87_INT_TEMP 0x27
/*
* Scaling factors for the AD7417 ADC converters (except
* for the CPU diode which is obtained from the EEPROM).
* Those values are obtained from the property list of
* the darwin driver
*/
#define ADC_12V_CURRENT_SCALE 0x0320 /* _AD2 */
#define ADC_CPU_VOLTAGE_SCALE 0x00a0 /* _AD3 */
#define ADC_CPU_CURRENT_SCALE 0x1f40 /* _AD4 */
/*
* PID factors for the U3/Backside fan control loop. We have 2 sets
* of values here, one set for U3 and one set for U3H
*/
#define BACKSIDE_FAN_PWM_DEFAULT_ID 1
#define BACKSIDE_FAN_PWM_INDEX 0
#define BACKSIDE_PID_U3_G_d 0x02800000
#define BACKSIDE_PID_U3H_G_d 0x01400000
#define BACKSIDE_PID_RACK_G_d 0x00500000
#define BACKSIDE_PID_G_p 0x00500000
#define BACKSIDE_PID_RACK_G_p 0x0004cccc
#define BACKSIDE_PID_G_r 0x00000000
#define BACKSIDE_PID_U3_INPUT_TARGET 0x00410000
#define BACKSIDE_PID_U3H_INPUT_TARGET 0x004b0000
#define BACKSIDE_PID_RACK_INPUT_TARGET 0x00460000
#define BACKSIDE_PID_INTERVAL 5
#define BACKSIDE_PID_RACK_INTERVAL 1
#define BACKSIDE_PID_OUTPUT_MAX 100
#define BACKSIDE_PID_U3_OUTPUT_MIN 20
#define BACKSIDE_PID_U3H_OUTPUT_MIN 20
#define BACKSIDE_PID_HISTORY_SIZE 2
struct basckside_pid_params
{
s32 G_d;
s32 G_p;
s32 G_r;
s32 input_target;
s32 output_min;
s32 output_max;
s32 interval;
int additive;
};
struct backside_pid_state
{
int ticks;
struct i2c_client * monitor;
s32 sample_history[BACKSIDE_PID_HISTORY_SIZE];
s32 error_history[BACKSIDE_PID_HISTORY_SIZE];
int cur_sample;
s32 last_temp;
int pwm;
int first;
};
/*
* PID factors for the Drive Bay fan control loop
*/
#define DRIVES_FAN_RPM_DEFAULT_ID 2
#define DRIVES_FAN_RPM_INDEX 1
#define DRIVES_PID_G_d 0x01e00000
#define DRIVES_PID_G_p 0x00500000
#define DRIVES_PID_G_r 0x00000000
#define DRIVES_PID_INPUT_TARGET 0x00280000
#define DRIVES_PID_INTERVAL 5
#define DRIVES_PID_OUTPUT_MAX 4000
#define DRIVES_PID_OUTPUT_MIN 300
#define DRIVES_PID_HISTORY_SIZE 2
struct drives_pid_state
{
int ticks;
struct i2c_client * monitor;
s32 sample_history[BACKSIDE_PID_HISTORY_SIZE];
s32 error_history[BACKSIDE_PID_HISTORY_SIZE];
int cur_sample;
s32 last_temp;
int rpm;
int first;
};
#define SLOTS_FAN_PWM_DEFAULT_ID 2
#define SLOTS_FAN_PWM_INDEX 2
#define SLOTS_FAN_DEFAULT_PWM 40 /* Do better here ! */
/*
* PID factors for the Xserve DIMM control loop
*/
#define DIMM_PID_G_d 0
#define DIMM_PID_G_p 0
#define DIMM_PID_G_r 0x06553600
#define DIMM_PID_INPUT_TARGET 3276800
#define DIMM_PID_INTERVAL 1
#define DIMM_PID_OUTPUT_MAX 14000
#define DIMM_PID_OUTPUT_MIN 4000
#define DIMM_PID_HISTORY_SIZE 20
struct dimm_pid_state
{
int ticks;
struct i2c_client * monitor;
s32 sample_history[DIMM_PID_HISTORY_SIZE];
s32 error_history[DIMM_PID_HISTORY_SIZE];
int cur_sample;
s32 last_temp;
int first;
int output;
};
/*
* PID factors for the Xserve Slots control loop
*/
#define SLOTS_PID_G_d 0
#define SLOTS_PID_G_p 0
#define SLOTS_PID_G_r 0x00100000
#define SLOTS_PID_INPUT_TARGET 3200000
#define SLOTS_PID_INTERVAL 1
#define SLOTS_PID_OUTPUT_MAX 100
#define SLOTS_PID_OUTPUT_MIN 20
#define SLOTS_PID_HISTORY_SIZE 20
struct slots_pid_state
{
int ticks;
struct i2c_client * monitor;
s32 sample_history[SLOTS_PID_HISTORY_SIZE];
s32 error_history[SLOTS_PID_HISTORY_SIZE];
int cur_sample;
s32 last_temp;
int first;
int pwm;
};
/* Desktops */
#define CPUA_INTAKE_FAN_RPM_DEFAULT_ID 3
#define CPUA_EXHAUST_FAN_RPM_DEFAULT_ID 4
#define CPUB_INTAKE_FAN_RPM_DEFAULT_ID 5
#define CPUB_EXHAUST_FAN_RPM_DEFAULT_ID 6
#define CPUA_INTAKE_FAN_RPM_INDEX 3
#define CPUA_EXHAUST_FAN_RPM_INDEX 4
#define CPUB_INTAKE_FAN_RPM_INDEX 5
#define CPUB_EXHAUST_FAN_RPM_INDEX 6
#define CPU_INTAKE_SCALE 0x0000f852
#define CPU_TEMP_HISTORY_SIZE 2
#define CPU_POWER_HISTORY_SIZE 10
#define CPU_PID_INTERVAL 1
#define CPU_MAX_OVERTEMP 90
#define CPUA_PUMP_RPM_INDEX 7
#define CPUB_PUMP_RPM_INDEX 8
#define CPU_PUMP_OUTPUT_MAX 3200
#define CPU_PUMP_OUTPUT_MIN 1250
/* Xserve */
#define CPU_A1_FAN_RPM_INDEX 9
#define CPU_A2_FAN_RPM_INDEX 10
#define CPU_A3_FAN_RPM_INDEX 11
#define CPU_B1_FAN_RPM_INDEX 12
#define CPU_B2_FAN_RPM_INDEX 13
#define CPU_B3_FAN_RPM_INDEX 14
struct cpu_pid_state
{
int index;
struct i2c_client * monitor;
struct mpu_data mpu;
int overtemp;
s32 temp_history[CPU_TEMP_HISTORY_SIZE];
int cur_temp;
s32 power_history[CPU_POWER_HISTORY_SIZE];
s32 error_history[CPU_POWER_HISTORY_SIZE];
int cur_power;
int count_power;
int rpm;
int intake_rpm;
s32 voltage;
s32 current_a;
s32 last_temp;
s32 last_power;
int first;
u8 adc_config;
s32 pump_min;
s32 pump_max;
};
/* Tickle FCU every 10 seconds */
#define FCU_TICKLE_TICKS 10
/*
* Driver state
*/
enum {
state_detached,
state_attaching,
state_attached,
state_detaching,
};
#endif /* __THERM_PMAC_7_2_H__ */