2011-02-03 00:36:45

by Tomoya MORINAGA

[permalink] [raw]
Subject: [PATCH] i2c-eg20t: support new devie ML7213 IOH

Support ML7213 device of OKI SEMICONDUCTOR.
ML7213 is companion chip of Intel Atom E6xx series for IVI(In-Vehicle Infotainment).
ML7213 is completely compatible for Intel EG20T PCH.

Signed-off-by: Tomoya MORINAGA <[email protected]>
---
drivers/i2c/busses/Kconfig | 17 +++--
drivers/i2c/busses/i2c-eg20t.c | 158 +++++++++++++++++++++++++---------------
2 files changed, 109 insertions(+), 66 deletions(-)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 113505a..8086d49 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -639,12 +639,17 @@ config I2C_XILINX
will be called xilinx_i2c.

config I2C_EG20T
- tristate "PCH I2C of Intel EG20T"
- depends on PCI
- help
- This driver is for PCH(Platform controller Hub) I2C of EG20T which
- is an IOH(Input/Output Hub) for x86 embedded processor.
- This driver can access PCH I2C bus device.
+ tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+ depends on PCI
+ help
+ This driver is for PCH(Platform controller Hub) I2C of EG20T which
+ is an IOH(Input/Output Hub) for x86 embedded processor.
+ This driver can access PCH I2C bus device.
+
+ This driver also can be used for OKI SEMICONDUCTOR's ML7213 IOH which
+ is for IVI(In-Vehicle Infotainment) use.
+ ML7213 IOH is companion chip for Intel Atom E6xx series.
+ ML7213 IOH is completely compatible for Intel EG20T PCH.

comment "External I2C/SMBus adapter drivers"

diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 50ea1f4..d4beed5 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -132,6 +132,13 @@
#define pch_pci_dbg(pdev, fmt, arg...) \
dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)

+/*
+Set the number of I2C instance max
+Intel EG20T PCH : 1ch
+OKI SEMICONDUCTOR ML7213 IOH : 2ch
+*/
+#define PCH_I2C_MAX_DEV 2
+
/**
* struct i2c_algo_pch_data - for I2C driver functionalities
* @pch_adapter: stores the reference to i2c_adapter structure
@@ -156,12 +163,14 @@ struct i2c_algo_pch_data {
* @pch_data: stores a list of i2c_algo_pch_data
* @pch_i2c_suspended: specifies whether the system is suspended or not
* perhaps with more lines and words.
+ * @ch_num: specifies the number of i2c instance
*
* pch_data has as many elements as maximum I2C channels
*/
struct adapter_info {
- struct i2c_algo_pch_data pch_data;
+ struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
bool pch_i2c_suspended;
+ int ch_num;
};


@@ -170,8 +179,13 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
static wait_queue_head_t pch_event;
static DEFINE_MUTEX(pch_mutex);

+/* Definition for ML7213 by OKI SEMICONDUCTOR */
+#define PCI_VENDOR_ID_ROHM 0x10DB
+#define PCI_DEVICE_ID_ML7213_I2C 0x802D
+
static struct pci_device_id __devinitdata pch_pcidev_id[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)},
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
{0,}
};

@@ -212,8 +226,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap)
/* Initialize I2C registers */
iowrite32(0x21, p + PCH_I2CNF);

- pch_setbit(adap->pch_base_address, PCH_I2CCTL,
- PCH_I2CCTL_I2CMEN);
+ pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);

if (pch_i2c_speed != 400)
pch_i2c_speed = 100;
@@ -255,7 +268,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
* @timeout: waiting time counter (us).
*/
static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
- s32 timeout)
+ s32 timeout)
{
void __iomem *p = adap->pch_base_address;

@@ -475,8 +488,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
* @last: specifies whether last message or not.
* @first: specifies whether first message or not.
*/
-s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
- u32 last, u32 first)
+static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
{
struct i2c_algo_pch_data *adap = i2c_adap->algo_data;

@@ -569,10 +582,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
}

/**
- * pch_i2c_cb_ch0() - Interrupt handler Call back function
+ * pch_i2c_cb() - Interrupt handler Call back function
* @adap: Pointer to struct i2c_algo_pch_data.
*/
-static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
+static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
{
u32 sts;
void __iomem *p = adap->pch_base_address;
@@ -600,24 +613,31 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
*/
static irqreturn_t pch_i2c_handler(int irq, void *pData)
{
- s32 reg_val;
-
- struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData;
- void __iomem *p = adap_data->pch_base_address;
- u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE);
-
- if (mode != NORMAL_MODE) {
- pch_err(adap_data, "I2C mode is not supported\n");
- return IRQ_NONE;
+ u32 reg_val;
+ int flag;
+ int i;
+ struct adapter_info *adap_info = pData;
+
+ void __iomem *p;
+ u32 mode;
+
+ for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
+ p = adap_info->pch_data[i].pch_base_address;
+ mode = ioread32(p + PCH_I2CMOD) &
+ (BUFFER_MODE | EEPROM_SR_MODE);
+ if (mode != NORMAL_MODE) {
+ pch_err(adap_info->pch_data,
+ "I2C-%d mode(%d) is not supported\n", mode, i);
+ continue;
+ }
+ reg_val = ioread32(p + PCH_I2CSR);
+ if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
+ pch_i2c_cb(&adap_info->pch_data[i]);
+ flag = 1;
+ }
}

- reg_val = ioread32(p + PCH_I2CSR);
- if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT))
- pch_i2c_cb_ch0(adap_data);
- else
- return IRQ_NONE;
-
- return IRQ_HANDLED;
+ return flag ? IRQ_HANDLED : IRQ_NONE;
}

/**
@@ -627,7 +647,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData)
* @num: number of messages.
*/
static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg *msgs, s32 num)
+ struct i2c_msg *msgs, s32 num)
{
struct i2c_msg *pmsg;
u32 i = 0;
@@ -710,10 +730,11 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
}

static int __devinit pch_i2c_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id)
{
void __iomem *base_addr;
- s32 ret;
+ int ret;
+ int i, j;
struct adapter_info *adap_info;

pch_pci_dbg(pdev, "Entered.\n");
@@ -744,32 +765,36 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
goto err_pci_iomap;
}

- adap_info->pch_i2c_suspended = false;
+ /* Set the number of I2C channel instance */
+ adap_info->ch_num = id->driver_data;

- adap_info->pch_data.p_adapter_info = adap_info;
+ for (i = 0; i < adap_info->ch_num; i++) {
+ adap_info->pch_i2c_suspended = false;

- adap_info->pch_data.pch_adapter.owner = THIS_MODULE;
- adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON;
- strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME);
- adap_info->pch_data.pch_adapter.algo = &pch_algorithm;
- adap_info->pch_data.pch_adapter.algo_data =
- &adap_info->pch_data;
+ adap_info->pch_data[i].p_adapter_info = adap_info;

- /* (i * 0x80) + base_addr; */
- adap_info->pch_data.pch_base_address = base_addr;
+ adap_info->pch_data[i].pch_adapter.owner = THIS_MODULE;
+ adap_info->pch_data[i].pch_adapter.class = I2C_CLASS_HWMON;
+ strcpy(adap_info->pch_data[i].pch_adapter.name, KBUILD_MODNAME);
+ adap_info->pch_data[i].pch_adapter.algo = &pch_algorithm;
+ adap_info->pch_data[i].pch_adapter.algo_data =
+ &adap_info->pch_data[i];

- adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev;
+ /* base_addr + offset; */
+ adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;

- ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter));
+ adap_info->pch_data[i].pch_adapter.dev.parent = &pdev->dev;

- if (ret) {
- pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
- goto err_i2c_add_adapter;
- }
+ ret = i2c_add_adapter(&(adap_info->pch_data[i].pch_adapter));
+ if (ret) {
+ pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
+ goto err_i2c_add_adapter;
+ }

- pch_i2c_init(&adap_info->pch_data);
+ pch_i2c_init(&adap_info->pch_data[i]);
+ }
ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
- KBUILD_MODNAME, &adap_info->pch_data);
+ KBUILD_MODNAME, adap_info);
if (ret) {
pch_pci_err(pdev, "request_irq FAILED\n");
goto err_request_irq;
@@ -780,7 +805,8 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
return 0;

err_request_irq:
- i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
+ for (j = 0; j < i; j++)
+ i2c_del_adapter(&(adap_info->pch_data[j].pch_adapter));
err_i2c_add_adapter:
pci_iounmap(pdev, base_addr);
err_pci_iomap:
@@ -794,17 +820,22 @@ err_pci_enable:

static void __devexit pch_i2c_remove(struct pci_dev *pdev)
{
+ int i;
struct adapter_info *adap_info = pci_get_drvdata(pdev);

- pch_i2c_disbl_int(&adap_info->pch_data);
- free_irq(pdev->irq, &adap_info->pch_data);
- i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
+ free_irq(pdev->irq, adap_info);

- if (adap_info->pch_data.pch_base_address) {
- pci_iounmap(pdev, adap_info->pch_data.pch_base_address);
- adap_info->pch_data.pch_base_address = 0;
+ for (i = 0; i < adap_info->ch_num; i++) {
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);
+ i2c_del_adapter(&(adap_info->pch_data[i].pch_adapter));
}

+ if (adap_info->pch_data[0].pch_base_address)
+ pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
+
+ for (i = 0; i < adap_info->ch_num; i++)
+ adap_info->pch_data[i].pch_base_address = 0;
+
pci_set_drvdata(pdev, NULL);

pci_release_regions(pdev);
@@ -817,17 +848,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev)
static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
{
int ret;
+ int i;
struct adapter_info *adap_info = pci_get_drvdata(pdev);
- void __iomem *p = adap_info->pch_data.pch_base_address;
+ void __iomem *p = adap_info->pch_data[0].pch_base_address;

adap_info->pch_i2c_suspended = true;

- while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) {
- /* Wait until all channel transfers are completed */
- msleep(20);
+ for (i = 0; i < adap_info->ch_num; i++) {
+ while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
+ /* Wait until all channel transfers are completed */
+ msleep(20);
+ }
}
+
/* Disable the i2c interrupts */
- pch_i2c_disbl_int(&adap_info->pch_data);
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_disbl_int(&adap_info->pch_data[i]);

pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
"invoked function pch_i2c_disbl_int successfully\n",
@@ -850,6 +886,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)

static int pch_i2c_resume(struct pci_dev *pdev)
{
+ int i;
struct adapter_info *adap_info = pci_get_drvdata(pdev);

pci_set_power_state(pdev, PCI_D0);
@@ -862,7 +899,8 @@ static int pch_i2c_resume(struct pci_dev *pdev)

pci_enable_wake(pdev, PCI_D3hot, 0);

- pch_i2c_init(&adap_info->pch_data);
+ for (i = 0; i < adap_info->ch_num; i++)
+ pch_i2c_init(&adap_info->pch_data[i]);

adap_info->pch_i2c_suspended = false;

@@ -894,7 +932,7 @@ static void __exit pch_pci_exit(void)
}
module_exit(pch_pci_exit);

-MODULE_DESCRIPTION("PCH I2C PCI Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tomoya MORINAGA. <[email protected]>");
module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
--
1.7.3.4


2011-02-05 16:05:52

by Ben Dooks

[permalink] [raw]
Subject: Re: [PATCH] i2c-eg20t: support new devie ML7213 IOH

On Thu, Feb 03, 2011 at 09:37:47AM +0900, Tomoya MORINAGA wrote:
> Support ML7213 device of OKI SEMICONDUCTOR.
> ML7213 is companion chip of Intel Atom E6xx series for IVI(In-Vehicle Infotainment).
> ML7213 is completely compatible for Intel EG20T PCH.
>
> Signed-off-by: Tomoya MORINAGA <[email protected]>
> ---
> drivers/i2c/busses/Kconfig | 17 +++--
> drivers/i2c/busses/i2c-eg20t.c | 158 +++++++++++++++++++++++++---------------
> 2 files changed, 109 insertions(+), 66 deletions(-)
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 113505a..8086d49 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -639,12 +639,17 @@ config I2C_XILINX
> will be called xilinx_i2c.
>
> config I2C_EG20T
> - tristate "PCH I2C of Intel EG20T"
> - depends on PCI
> - help
> - This driver is for PCH(Platform controller Hub) I2C of EG20T which
> - is an IOH(Input/Output Hub) for x86 embedded processor.
> - This driver can access PCH I2C bus device.
> + tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
> + depends on PCI
> + help
> + This driver is for PCH(Platform controller Hub) I2C of EG20T which
> + is an IOH(Input/Output Hub) for x86 embedded processor.
> + This driver can access PCH I2C bus device.
> +
> + This driver also can be used for OKI SEMICONDUCTOR's ML7213 IOH which
> + is for IVI(In-Vehicle Infotainment) use.
> + ML7213 IOH is companion chip for Intel Atom E6xx series.
> + ML7213 IOH is completely compatible for Intel EG20T PCH.

You could have this asL:

This driver also supports the ML7213, a companion chip for the
Atom E6xx series and compatible with the Intel EG20T PCH.

> +/*
> +Set the number of I2C instance max
> +Intel EG20T PCH : 1ch
> +OKI SEMICONDUCTOR ML7213 IOH : 2ch
> +*/
> +#define PCH_I2C_MAX_DEV 2
> +
> /**
> * struct i2c_algo_pch_data - for I2C driver functionalities
> * @pch_adapter: stores the reference to i2c_adapter structure
> @@ -156,12 +163,14 @@ struct i2c_algo_pch_data {
> * @pch_data: stores a list of i2c_algo_pch_data
> * @pch_i2c_suspended: specifies whether the system is suspended or not
> * perhaps with more lines and words.
> + * @ch_num: specifies the number of i2c instance
> *
> * pch_data has as many elements as maximum I2C channels
> */
> struct adapter_info {
> - struct i2c_algo_pch_data pch_data;
> + struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
> bool pch_i2c_suspended;
> + int ch_num;
> };
>
>
> @@ -170,8 +179,13 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */
> static wait_queue_head_t pch_event;
> static DEFINE_MUTEX(pch_mutex);
>
> +/* Definition for ML7213 by OKI SEMICONDUCTOR */
> +#define PCI_VENDOR_ID_ROHM 0x10DB
> +#define PCI_DEVICE_ID_ML7213_I2C 0x802D
> +
> static struct pci_device_id __devinitdata pch_pcidev_id[] = {
> - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)},
> + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
> + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },

will let the reformatting slide on this occasion

> @@ -212,8 +226,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap)
> /* Initialize I2C registers */
> iowrite32(0x21, p + PCH_I2CNF);
>
> - pch_setbit(adap->pch_base_address, PCH_I2CCTL,
> - PCH_I2CCTL_I2CMEN);
> + pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);

Please don't format change, I would like to see this change reverted
unless there's a good reason for it.

> if (pch_i2c_speed != 400)
> pch_i2c_speed = 100;
> @@ -255,7 +268,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
> * @timeout: waiting time counter (us).
> */
> static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
> - s32 timeout)
> + s32 timeout)
> {
> void __iomem *p = adap->pch_base_address;

see above.

> @@ -475,8 +488,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
> * @last: specifies whether last message or not.
> * @first: specifies whether first message or not.
> */
> -s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
> - u32 last, u32 first)
> +static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
> + u32 last, u32 first)
> {
> struct i2c_algo_pch_data *adap = i2c_adap->algo_data;


this looks like a format change again.

> @@ -569,10 +582,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
> }
>
> /**
> - * pch_i2c_cb_ch0() - Interrupt handler Call back function
> + * pch_i2c_cb() - Interrupt handler Call back function
> * @adap: Pointer to struct i2c_algo_pch_data.
> */
> -static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
> +static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
> {
> u32 sts;
> void __iomem *p = adap->pch_base_address;
> @@ -600,24 +613,31 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap)
> */
> static irqreturn_t pch_i2c_handler(int irq, void *pData)
> {
> - s32 reg_val;
> -
> - struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData;
> - void __iomem *p = adap_data->pch_base_address;
> - u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE);
> -
> - if (mode != NORMAL_MODE) {
> - pch_err(adap_data, "I2C mode is not supported\n");
> - return IRQ_NONE;
> + u32 reg_val;
> + int flag;
> + int i;
> + struct adapter_info *adap_info = pData;
> + void __iomem *p;
> + u32 mode;
> +
> + for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
> + p = adap_info->pch_data[i].pch_base_address;
> + mode = ioread32(p + PCH_I2CMOD) &
> + (BUFFER_MODE | EEPROM_SR_MODE);

could we split into mode = , then a new line with "mode &= " on please
as it doesn't really flow.

> + if (mode != NORMAL_MODE) {
> + pch_err(adap_info->pch_data,
> + "I2C-%d mode(%d) is not supported\n", mode, i);
> + continue;
> + }
> + reg_val = ioread32(p + PCH_I2CSR);
> + if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
> + pch_i2c_cb(&adap_info->pch_data[i]);
> + flag = 1;
> + }
> }
>
> - reg_val = ioread32(p + PCH_I2CSR);
> - if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT))
> - pch_i2c_cb_ch0(adap_data);
> - else
> - return IRQ_NONE;
> -
> - return IRQ_HANDLED;
> + return flag ? IRQ_HANDLED : IRQ_NONE;
> }
>
> /**
> @@ -627,7 +647,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData)
> * @num: number of messages.
> */
> static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
> - struct i2c_msg *msgs, s32 num)
> + struct i2c_msg *msgs, s32 num)
> {

formatting again.

struct i2c_msg *pmsg;
> u32 i = 0;
> @@ -710,10 +730,11 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
> }
>
> static int __devinit pch_i2c_probe(struct pci_dev *pdev,
> - const struct pci_device_id *id)
> + const struct pci_device_id *id)
> {
> void __iomem *base_addr;
> - s32 ret;
> + int ret;
> + int i, j;
> struct adapter_info *adap_info;
>
> pch_pci_dbg(pdev, "Entered.\n");
> @@ -744,32 +765,36 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
> goto err_pci_iomap;
> }
>
> - adap_info->pch_i2c_suspended = false;
> + /* Set the number of I2C channel instance */
> + adap_info->ch_num = id->driver_data;
>
> - adap_info->pch_data.p_adapter_info = adap_info;
> + for (i = 0; i < adap_info->ch_num; i++) {
> + adap_info->pch_i2c_suspended = false;
>
> - adap_info->pch_data.pch_adapter.owner = THIS_MODULE;
> - adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON;
> - strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME);
> - adap_info->pch_data.pch_adapter.algo = &pch_algorithm;
> - adap_info->pch_data.pch_adapter.algo_data =
> - &adap_info->pch_data;
> + adap_info->pch_data[i].p_adapter_info = adap_info;
>
> - /* (i * 0x80) + base_addr; */
> - adap_info->pch_data.pch_base_address = base_addr;
> + adap_info->pch_data[i].pch_adapter.owner = THIS_MODULE;
> + adap_info->pch_data[i].pch_adapter.class = I2C_CLASS_HWMON;
> + strcpy(adap_info->pch_data[i].pch_adapter.name, KBUILD_MODNAME);
> + adap_info->pch_data[i].pch_adapter.algo = &pch_algorithm;
> + adap_info->pch_data[i].pch_adapter.algo_data =
> + &adap_info->pch_data[i];

how about having a pointer to " adap_info->pch_data[i].pch_adapter" to
make the code lines shorte?

>
> - adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev;
> + /* base_addr + offset; */
> + adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
>
> - ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter));
> + adap_info->pch_data[i].pch_adapter.dev.parent = &pdev->dev;
>
> - if (ret) {
> - pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
> - goto err_i2c_add_adapter;
> - }
> + ret = i2c_add_adapter(&(adap_info->pch_data[i].pch_adapter));


shouldn't need an () around the and?

> + if (ret) {
> + pch_pci_err(pdev, "i2c_add_adapter FAILED\n");
> + goto err_i2c_add_adapter;
> + }

would be useful to print the number of the adapter that failed.

> - pch_i2c_init(&adap_info->pch_data);
> + pch_i2c_init(&adap_info->pch_data[i]);
> + }
> ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
> - KBUILD_MODNAME, &adap_info->pch_data);
> + KBUILD_MODNAME, adap_info);
> if (ret) {
> pch_pci_err(pdev, "request_irq FAILED\n");
> goto err_request_irq;
> @@ -780,7 +805,8 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev,
> return 0;
>
> err_request_irq:
> - i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
> + for (j = 0; j < i; j++)
> + i2c_del_adapter(&(adap_info->pch_data[j].pch_adapter));

see the above comments.

> err_i2c_add_adapter:
> pci_iounmap(pdev, base_addr);
> err_pci_iomap:
> @@ -794,17 +820,22 @@ err_pci_enable:
>
> static void __devexit pch_i2c_remove(struct pci_dev *pdev)
> {
> + int i;
> struct adapter_info *adap_info = pci_get_drvdata(pdev);
>
> - pch_i2c_disbl_int(&adap_info->pch_data);
> - free_irq(pdev->irq, &adap_info->pch_data);
> - i2c_del_adapter(&(adap_info->pch_data.pch_adapter));
> + free_irq(pdev->irq, adap_info);
>
> - if (adap_info->pch_data.pch_base_address) {
> - pci_iounmap(pdev, adap_info->pch_data.pch_base_address);
> - adap_info->pch_data.pch_base_address = 0;
> + for (i = 0; i < adap_info->ch_num; i++) {
> + pch_i2c_disbl_int(&adap_info->pch_data[i]);
> + i2c_del_adapter(&(adap_info->pch_data[i].pch_adapter));
> }
>
> + if (adap_info->pch_data[0].pch_base_address)
> + pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
> +
> + for (i = 0; i < adap_info->ch_num; i++)
> + adap_info->pch_data[i].pch_base_address = 0;
> +
> pci_set_drvdata(pdev, NULL);
>
> pci_release_regions(pdev);
> @@ -817,17 +848,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev)
> static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
> {
> int ret;
> + int i;
> struct adapter_info *adap_info = pci_get_drvdata(pdev);
> - void __iomem *p = adap_info->pch_data.pch_base_address;
> + void __iomem *p = adap_info->pch_data[0].pch_base_address;
>
> adap_info->pch_i2c_suspended = true;
>
> - while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) {
> - /* Wait until all channel transfers are completed */
> - msleep(20);
> + for (i = 0; i < adap_info->ch_num; i++) {
> + while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
> + /* Wait until all channel transfers are completed */
> + msleep(20);
> + }
> }
> +
> /* Disable the i2c interrupts */
> - pch_i2c_disbl_int(&adap_info->pch_data);
> + for (i = 0; i < adap_info->ch_num; i++)
> + pch_i2c_disbl_int(&adap_info->pch_data[i]);
>
> pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
> "invoked function pch_i2c_disbl_int successfully\n",
> @@ -850,6 +886,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
>
> static int pch_i2c_resume(struct pci_dev *pdev)
> {
> + int i;
> struct adapter_info *adap_info = pci_get_drvdata(pdev);
>
> pci_set_power_state(pdev, PCI_D0);
> @@ -862,7 +899,8 @@ static int pch_i2c_resume(struct pci_dev *pdev)
>
> pci_enable_wake(pdev, PCI_D3hot, 0);
>
> - pch_i2c_init(&adap_info->pch_data);
> + for (i = 0; i < adap_info->ch_num; i++)
> + pch_i2c_init(&adap_info->pch_data[i]);
>
> adap_info->pch_i2c_suspended = false;
>
> @@ -894,7 +932,7 @@ static void __exit pch_pci_exit(void)
> }
> module_exit(pch_pci_exit);
>
> -MODULE_DESCRIPTION("PCH I2C PCI Driver");
> +MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver");
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Tomoya MORINAGA. <[email protected]>");
> module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));

Please fix the comments.

--
Ben Dooks, [email protected], http://www.fluff.org/ben/

Large Hadron Colada: A large Pina Colada that makes the universe disappear.