18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/errno.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/fs.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
168c2ecf20Sopenharmony_ci#include <linux/pci.h>
178c2ecf20Sopenharmony_ci#include <linux/mutex.h>
188c2ecf20Sopenharmony_ci#include <linux/ktime.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define PCH_EVENT_SET	0	/* I2C Interrupt Event Set Status */
228c2ecf20Sopenharmony_ci#define PCH_EVENT_NONE	1	/* I2C Interrupt Event Clear Status */
238c2ecf20Sopenharmony_ci#define PCH_MAX_CLK		100000	/* Maximum Clock speed in MHz */
248c2ecf20Sopenharmony_ci#define PCH_BUFFER_MODE_ENABLE	0x0002	/* flag for Buffer mode enable */
258c2ecf20Sopenharmony_ci#define PCH_EEPROM_SW_RST_MODE_ENABLE	0x0008	/* EEPROM SW RST enable flag */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define PCH_I2CSADR	0x00	/* I2C slave address register */
288c2ecf20Sopenharmony_ci#define PCH_I2CCTL	0x04	/* I2C control register */
298c2ecf20Sopenharmony_ci#define PCH_I2CSR	0x08	/* I2C status register */
308c2ecf20Sopenharmony_ci#define PCH_I2CDR	0x0C	/* I2C data register */
318c2ecf20Sopenharmony_ci#define PCH_I2CMON	0x10	/* I2C bus monitor register */
328c2ecf20Sopenharmony_ci#define PCH_I2CBC	0x14	/* I2C bus transfer rate setup counter */
338c2ecf20Sopenharmony_ci#define PCH_I2CMOD	0x18	/* I2C mode register */
348c2ecf20Sopenharmony_ci#define PCH_I2CBUFSLV	0x1C	/* I2C buffer mode slave address register */
358c2ecf20Sopenharmony_ci#define PCH_I2CBUFSUB	0x20	/* I2C buffer mode subaddress register */
368c2ecf20Sopenharmony_ci#define PCH_I2CBUFFOR	0x24	/* I2C buffer mode format register */
378c2ecf20Sopenharmony_ci#define PCH_I2CBUFCTL	0x28	/* I2C buffer mode control register */
388c2ecf20Sopenharmony_ci#define PCH_I2CBUFMSK	0x2C	/* I2C buffer mode interrupt mask register */
398c2ecf20Sopenharmony_ci#define PCH_I2CBUFSTA	0x30	/* I2C buffer mode status register */
408c2ecf20Sopenharmony_ci#define PCH_I2CBUFLEV	0x34	/* I2C buffer mode level register */
418c2ecf20Sopenharmony_ci#define PCH_I2CESRFOR	0x38	/* EEPROM software reset mode format register */
428c2ecf20Sopenharmony_ci#define PCH_I2CESRCTL	0x3C	/* EEPROM software reset mode ctrl register */
438c2ecf20Sopenharmony_ci#define PCH_I2CESRMSK	0x40	/* EEPROM software reset mode */
448c2ecf20Sopenharmony_ci#define PCH_I2CESRSTA	0x44	/* EEPROM software reset mode status register */
458c2ecf20Sopenharmony_ci#define PCH_I2CTMR	0x48	/* I2C timer register */
468c2ecf20Sopenharmony_ci#define PCH_I2CSRST	0xFC	/* I2C reset register */
478c2ecf20Sopenharmony_ci#define PCH_I2CNF	0xF8	/* I2C noise filter register */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define BUS_IDLE_TIMEOUT	20
508c2ecf20Sopenharmony_ci#define PCH_I2CCTL_I2CMEN	0x0080
518c2ecf20Sopenharmony_ci#define TEN_BIT_ADDR_DEFAULT	0xF000
528c2ecf20Sopenharmony_ci#define TEN_BIT_ADDR_MASK	0xF0
538c2ecf20Sopenharmony_ci#define PCH_START		0x0020
548c2ecf20Sopenharmony_ci#define PCH_RESTART		0x0004
558c2ecf20Sopenharmony_ci#define PCH_ESR_START		0x0001
568c2ecf20Sopenharmony_ci#define PCH_BUFF_START		0x1
578c2ecf20Sopenharmony_ci#define PCH_REPSTART		0x0004
588c2ecf20Sopenharmony_ci#define PCH_ACK			0x0008
598c2ecf20Sopenharmony_ci#define PCH_GETACK		0x0001
608c2ecf20Sopenharmony_ci#define CLR_REG			0x0
618c2ecf20Sopenharmony_ci#define I2C_RD			0x1
628c2ecf20Sopenharmony_ci#define I2CMCF_BIT		0x0080
638c2ecf20Sopenharmony_ci#define I2CMIF_BIT		0x0002
648c2ecf20Sopenharmony_ci#define I2CMAL_BIT		0x0010
658c2ecf20Sopenharmony_ci#define I2CBMFI_BIT		0x0001
668c2ecf20Sopenharmony_ci#define I2CBMAL_BIT		0x0002
678c2ecf20Sopenharmony_ci#define I2CBMNA_BIT		0x0004
688c2ecf20Sopenharmony_ci#define I2CBMTO_BIT		0x0008
698c2ecf20Sopenharmony_ci#define I2CBMIS_BIT		0x0010
708c2ecf20Sopenharmony_ci#define I2CESRFI_BIT		0X0001
718c2ecf20Sopenharmony_ci#define I2CESRTO_BIT		0x0002
728c2ecf20Sopenharmony_ci#define I2CESRFIIE_BIT		0x1
738c2ecf20Sopenharmony_ci#define I2CESRTOIE_BIT		0x2
748c2ecf20Sopenharmony_ci#define I2CBMDZ_BIT		0x0040
758c2ecf20Sopenharmony_ci#define I2CBMAG_BIT		0x0020
768c2ecf20Sopenharmony_ci#define I2CMBB_BIT		0x0020
778c2ecf20Sopenharmony_ci#define BUFFER_MODE_MASK	(I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
788c2ecf20Sopenharmony_ci				I2CBMTO_BIT | I2CBMIS_BIT)
798c2ecf20Sopenharmony_ci#define I2C_ADDR_MSK		0xFF
808c2ecf20Sopenharmony_ci#define I2C_MSB_2B_MSK		0x300
818c2ecf20Sopenharmony_ci#define FAST_MODE_CLK		400
828c2ecf20Sopenharmony_ci#define FAST_MODE_EN		0x0001
838c2ecf20Sopenharmony_ci#define SUB_ADDR_LEN_MAX	4
848c2ecf20Sopenharmony_ci#define BUF_LEN_MAX		32
858c2ecf20Sopenharmony_ci#define PCH_BUFFER_MODE		0x1
868c2ecf20Sopenharmony_ci#define EEPROM_SW_RST_MODE	0x0002
878c2ecf20Sopenharmony_ci#define NORMAL_INTR_ENBL	0x0300
888c2ecf20Sopenharmony_ci#define EEPROM_RST_INTR_ENBL	(I2CESRFIIE_BIT | I2CESRTOIE_BIT)
898c2ecf20Sopenharmony_ci#define EEPROM_RST_INTR_DISBL	0x0
908c2ecf20Sopenharmony_ci#define BUFFER_MODE_INTR_ENBL	0x001F
918c2ecf20Sopenharmony_ci#define BUFFER_MODE_INTR_DISBL	0x0
928c2ecf20Sopenharmony_ci#define NORMAL_MODE		0x0
938c2ecf20Sopenharmony_ci#define BUFFER_MODE		0x1
948c2ecf20Sopenharmony_ci#define EEPROM_SR_MODE		0x2
958c2ecf20Sopenharmony_ci#define I2C_TX_MODE		0x0010
968c2ecf20Sopenharmony_ci#define PCH_BUF_TX		0xFFF7
978c2ecf20Sopenharmony_ci#define PCH_BUF_RD		0x0008
988c2ecf20Sopenharmony_ci#define I2C_ERROR_MASK	(I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
998c2ecf20Sopenharmony_ci			I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
1008c2ecf20Sopenharmony_ci#define I2CMAL_EVENT		0x0001
1018c2ecf20Sopenharmony_ci#define I2CMCF_EVENT		0x0002
1028c2ecf20Sopenharmony_ci#define I2CBMFI_EVENT		0x0004
1038c2ecf20Sopenharmony_ci#define I2CBMAL_EVENT		0x0008
1048c2ecf20Sopenharmony_ci#define I2CBMNA_EVENT		0x0010
1058c2ecf20Sopenharmony_ci#define I2CBMTO_EVENT		0x0020
1068c2ecf20Sopenharmony_ci#define I2CBMIS_EVENT		0x0040
1078c2ecf20Sopenharmony_ci#define I2CESRFI_EVENT		0x0080
1088c2ecf20Sopenharmony_ci#define I2CESRTO_EVENT		0x0100
1098c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_PCH_I2C	0x8817
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define pch_dbg(adap, fmt, arg...)  \
1128c2ecf20Sopenharmony_ci	dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#define pch_err(adap, fmt, arg...)  \
1158c2ecf20Sopenharmony_ci	dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define pch_pci_err(pdev, fmt, arg...)  \
1188c2ecf20Sopenharmony_ci	dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#define pch_pci_dbg(pdev, fmt, arg...)  \
1218c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/*
1248c2ecf20Sopenharmony_ciSet the number of I2C instance max
1258c2ecf20Sopenharmony_ciIntel EG20T PCH :		1ch
1268c2ecf20Sopenharmony_ciLAPIS Semiconductor ML7213 IOH :	2ch
1278c2ecf20Sopenharmony_ciLAPIS Semiconductor ML7831 IOH :	1ch
1288c2ecf20Sopenharmony_ci*/
1298c2ecf20Sopenharmony_ci#define PCH_I2C_MAX_DEV			2
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/**
1328c2ecf20Sopenharmony_ci * struct i2c_algo_pch_data - for I2C driver functionalities
1338c2ecf20Sopenharmony_ci * @pch_adapter:		stores the reference to i2c_adapter structure
1348c2ecf20Sopenharmony_ci * @p_adapter_info:		stores the reference to adapter_info structure
1358c2ecf20Sopenharmony_ci * @pch_base_address:		specifies the remapped base address
1368c2ecf20Sopenharmony_ci * @pch_buff_mode_en:		specifies if buffer mode is enabled
1378c2ecf20Sopenharmony_ci * @pch_event_flag:		specifies occurrence of interrupt events
1388c2ecf20Sopenharmony_ci * @pch_i2c_xfer_in_progress:	specifies whether the transfer is completed
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistruct i2c_algo_pch_data {
1418c2ecf20Sopenharmony_ci	struct i2c_adapter pch_adapter;
1428c2ecf20Sopenharmony_ci	struct adapter_info *p_adapter_info;
1438c2ecf20Sopenharmony_ci	void __iomem *pch_base_address;
1448c2ecf20Sopenharmony_ci	int pch_buff_mode_en;
1458c2ecf20Sopenharmony_ci	u32 pch_event_flag;
1468c2ecf20Sopenharmony_ci	bool pch_i2c_xfer_in_progress;
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/**
1508c2ecf20Sopenharmony_ci * struct adapter_info - This structure holds the adapter information for the
1518c2ecf20Sopenharmony_ci			 PCH i2c controller
1528c2ecf20Sopenharmony_ci * @pch_data:		stores a list of i2c_algo_pch_data
1538c2ecf20Sopenharmony_ci * @pch_i2c_suspended:	specifies whether the system is suspended or not
1548c2ecf20Sopenharmony_ci *			perhaps with more lines and words.
1558c2ecf20Sopenharmony_ci * @ch_num:		specifies the number of i2c instance
1568c2ecf20Sopenharmony_ci *
1578c2ecf20Sopenharmony_ci * pch_data has as many elements as maximum I2C channels
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistruct adapter_info {
1608c2ecf20Sopenharmony_ci	struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
1618c2ecf20Sopenharmony_ci	bool pch_i2c_suspended;
1628c2ecf20Sopenharmony_ci	int ch_num;
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int pch_i2c_speed = 100; /* I2C bus speed in Kbps */
1678c2ecf20Sopenharmony_cistatic int pch_clk = 50000;	/* specifies I2C clock speed in KHz */
1688c2ecf20Sopenharmony_cistatic wait_queue_head_t pch_event;
1698c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pch_mutex);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Definition for ML7213 by LAPIS Semiconductor */
1728c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ML7213_I2C	0x802D
1738c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ML7223_I2C	0x8010
1748c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_ML7831_I2C	0x8817
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic const struct pci_device_id pch_pcidev_id[] = {
1778c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
1788c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
1798c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
1808c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
1818c2ecf20Sopenharmony_ci	{0,}
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pch_pcidev_id);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic irqreturn_t pch_i2c_handler(int irq, void *pData);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	u32 val;
1908c2ecf20Sopenharmony_ci	val = ioread32(addr + offset);
1918c2ecf20Sopenharmony_ci	val |= bitmask;
1928c2ecf20Sopenharmony_ci	iowrite32(val, addr + offset);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	u32 val;
1988c2ecf20Sopenharmony_ci	val = ioread32(addr + offset);
1998c2ecf20Sopenharmony_ci	val &= (~bitmask);
2008c2ecf20Sopenharmony_ci	iowrite32(val, addr + offset);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci/**
2048c2ecf20Sopenharmony_ci * pch_i2c_init() - hardware initialization of I2C module
2058c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_cistatic void pch_i2c_init(struct i2c_algo_pch_data *adap)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
2108c2ecf20Sopenharmony_ci	u32 pch_i2cbc;
2118c2ecf20Sopenharmony_ci	u32 pch_i2ctmr;
2128c2ecf20Sopenharmony_ci	u32 reg_value;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* reset I2C controller */
2158c2ecf20Sopenharmony_ci	iowrite32(0x01, p + PCH_I2CSRST);
2168c2ecf20Sopenharmony_ci	msleep(20);
2178c2ecf20Sopenharmony_ci	iowrite32(0x0, p + PCH_I2CSRST);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Initialize I2C registers */
2208c2ecf20Sopenharmony_ci	iowrite32(0x21, p + PCH_I2CNF);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (pch_i2c_speed != 400)
2258c2ecf20Sopenharmony_ci		pch_i2c_speed = 100;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	reg_value = PCH_I2CCTL_I2CMEN;
2288c2ecf20Sopenharmony_ci	if (pch_i2c_speed == FAST_MODE_CLK) {
2298c2ecf20Sopenharmony_ci		reg_value |= FAST_MODE_EN;
2308c2ecf20Sopenharmony_ci		pch_dbg(adap, "Fast mode enabled\n");
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (pch_clk > PCH_MAX_CLK)
2348c2ecf20Sopenharmony_ci		pch_clk = 62500;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
2378c2ecf20Sopenharmony_ci	/* Set transfer speed in I2CBC */
2388c2ecf20Sopenharmony_ci	iowrite32(pch_i2cbc, p + PCH_I2CBC);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	pch_i2ctmr = (pch_clk) / 8;
2418c2ecf20Sopenharmony_ci	iowrite32(pch_i2ctmr, p + PCH_I2CTMR);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	reg_value |= NORMAL_INTR_ENBL;	/* Enable interrupts in normal mode */
2448c2ecf20Sopenharmony_ci	iowrite32(reg_value, p + PCH_I2CCTL);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	pch_dbg(adap,
2478c2ecf20Sopenharmony_ci		"I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n",
2488c2ecf20Sopenharmony_ci		ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	init_waitqueue_head(&pch_event);
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci/**
2548c2ecf20Sopenharmony_ci * pch_i2c_wait_for_bus_idle() - check the status of bus.
2558c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
2568c2ecf20Sopenharmony_ci * @timeout:	waiting time counter (ms).
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_cistatic s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
2598c2ecf20Sopenharmony_ci				     s32 timeout)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
2628c2ecf20Sopenharmony_ci	int schedule = 0;
2638c2ecf20Sopenharmony_ci	unsigned long end = jiffies + msecs_to_jiffies(timeout);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) {
2668c2ecf20Sopenharmony_ci		if (time_after(jiffies, end)) {
2678c2ecf20Sopenharmony_ci			pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
2688c2ecf20Sopenharmony_ci			pch_err(adap, "%s: Timeout Error.return%d\n",
2698c2ecf20Sopenharmony_ci					__func__, -ETIME);
2708c2ecf20Sopenharmony_ci			pch_i2c_init(adap);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci			return -ETIME;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		if (!schedule)
2768c2ecf20Sopenharmony_ci			/* Retry after some usecs */
2778c2ecf20Sopenharmony_ci			udelay(5);
2788c2ecf20Sopenharmony_ci		else
2798c2ecf20Sopenharmony_ci			/* Wait a bit more without consuming CPU */
2808c2ecf20Sopenharmony_ci			usleep_range(20, 1000);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		schedule = 1;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/**
2898c2ecf20Sopenharmony_ci * pch_i2c_start() - Generate I2C start condition in normal mode.
2908c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
2918c2ecf20Sopenharmony_ci *
2928c2ecf20Sopenharmony_ci * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1.
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_cistatic void pch_i2c_start(struct i2c_algo_pch_data *adap)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
2978c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
2988c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/**
3028c2ecf20Sopenharmony_ci * pch_i2c_stop() - generate stop condition in normal mode.
3038c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_cistatic void pch_i2c_stop(struct i2c_algo_pch_data *adap)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
3088c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
3098c2ecf20Sopenharmony_ci	/* clear the start bit */
3108c2ecf20Sopenharmony_ci	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	long ret;
3168c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	ret = wait_event_timeout(pch_event,
3198c2ecf20Sopenharmony_ci			(adap->pch_event_flag != 0), msecs_to_jiffies(1000));
3208c2ecf20Sopenharmony_ci	if (!ret) {
3218c2ecf20Sopenharmony_ci		pch_err(adap, "%s:wait-event timeout\n", __func__);
3228c2ecf20Sopenharmony_ci		adap->pch_event_flag = 0;
3238c2ecf20Sopenharmony_ci		pch_i2c_stop(adap);
3248c2ecf20Sopenharmony_ci		pch_i2c_init(adap);
3258c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (adap->pch_event_flag & I2C_ERROR_MASK) {
3298c2ecf20Sopenharmony_ci		pch_err(adap, "Lost Arbitration\n");
3308c2ecf20Sopenharmony_ci		adap->pch_event_flag = 0;
3318c2ecf20Sopenharmony_ci		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
3328c2ecf20Sopenharmony_ci		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
3338c2ecf20Sopenharmony_ci		pch_i2c_init(adap);
3348c2ecf20Sopenharmony_ci		return -EAGAIN;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	adap->pch_event_flag = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (ioread32(p + PCH_I2CSR) & PCH_GETACK) {
3408c2ecf20Sopenharmony_ci		pch_dbg(adap, "Receive NACK for slave address setting\n");
3418c2ecf20Sopenharmony_ci		return -ENXIO;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	return 0;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/**
3488c2ecf20Sopenharmony_ci * pch_i2c_repstart() - generate repeated start condition in normal mode
3498c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
3508c2ecf20Sopenharmony_ci */
3518c2ecf20Sopenharmony_cistatic void pch_i2c_repstart(struct i2c_algo_pch_data *adap)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
3548c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
3558c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/**
3598c2ecf20Sopenharmony_ci * pch_i2c_writebytes() - write data to I2C bus in normal mode
3608c2ecf20Sopenharmony_ci * @i2c_adap:	Pointer to the struct i2c_adapter.
3618c2ecf20Sopenharmony_ci * @last:	specifies whether last message or not.
3628c2ecf20Sopenharmony_ci *		In the case of compound mode it will be 1 for last message,
3638c2ecf20Sopenharmony_ci *		otherwise 0.
3648c2ecf20Sopenharmony_ci * @first:	specifies whether first message or not.
3658c2ecf20Sopenharmony_ci *		1 for first message otherwise 0.
3668c2ecf20Sopenharmony_ci */
3678c2ecf20Sopenharmony_cistatic s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
3688c2ecf20Sopenharmony_ci			      struct i2c_msg *msgs, u32 last, u32 first)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
3718c2ecf20Sopenharmony_ci	u8 *buf;
3728c2ecf20Sopenharmony_ci	u32 length;
3738c2ecf20Sopenharmony_ci	u32 addr;
3748c2ecf20Sopenharmony_ci	u32 addr_2_msb;
3758c2ecf20Sopenharmony_ci	u32 addr_8_lsb;
3768c2ecf20Sopenharmony_ci	s32 wrcount;
3778c2ecf20Sopenharmony_ci	s32 rtn;
3788c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	length = msgs->len;
3818c2ecf20Sopenharmony_ci	buf = msgs->buf;
3828c2ecf20Sopenharmony_ci	addr = msgs->addr;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* enable master tx */
3858c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL),
3888c2ecf20Sopenharmony_ci		length);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (first) {
3918c2ecf20Sopenharmony_ci		if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
3928c2ecf20Sopenharmony_ci			return -ETIME;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (msgs->flags & I2C_M_TEN) {
3968c2ecf20Sopenharmony_ci		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
3978c2ecf20Sopenharmony_ci		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
3988c2ecf20Sopenharmony_ci		if (first)
3998c2ecf20Sopenharmony_ci			pch_i2c_start(adap);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		rtn = pch_i2c_wait_for_check_xfer(adap);
4028c2ecf20Sopenharmony_ci		if (rtn)
4038c2ecf20Sopenharmony_ci			return rtn;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		addr_8_lsb = (addr & I2C_ADDR_MSK);
4068c2ecf20Sopenharmony_ci		iowrite32(addr_8_lsb, p + PCH_I2CDR);
4078c2ecf20Sopenharmony_ci	} else {
4088c2ecf20Sopenharmony_ci		/* set 7 bit slave address and R/W bit as 0 */
4098c2ecf20Sopenharmony_ci		iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
4108c2ecf20Sopenharmony_ci		if (first)
4118c2ecf20Sopenharmony_ci			pch_i2c_start(adap);
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	rtn = pch_i2c_wait_for_check_xfer(adap);
4158c2ecf20Sopenharmony_ci	if (rtn)
4168c2ecf20Sopenharmony_ci		return rtn;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	for (wrcount = 0; wrcount < length; ++wrcount) {
4198c2ecf20Sopenharmony_ci		/* write buffer value to I2C data register */
4208c2ecf20Sopenharmony_ci		iowrite32(buf[wrcount], p + PCH_I2CDR);
4218c2ecf20Sopenharmony_ci		pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		rtn = pch_i2c_wait_for_check_xfer(adap);
4248c2ecf20Sopenharmony_ci		if (rtn)
4258c2ecf20Sopenharmony_ci			return rtn;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMCF_BIT);
4288c2ecf20Sopenharmony_ci		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* check if this is the last message */
4328c2ecf20Sopenharmony_ci	if (last)
4338c2ecf20Sopenharmony_ci		pch_i2c_stop(adap);
4348c2ecf20Sopenharmony_ci	else
4358c2ecf20Sopenharmony_ci		pch_i2c_repstart(adap);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	pch_dbg(adap, "return=%d\n", wrcount);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return wrcount;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/**
4438c2ecf20Sopenharmony_ci * pch_i2c_sendack() - send ACK
4448c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
4458c2ecf20Sopenharmony_ci */
4468c2ecf20Sopenharmony_cistatic void pch_i2c_sendack(struct i2c_algo_pch_data *adap)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
4498c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
4508c2ecf20Sopenharmony_ci	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci/**
4548c2ecf20Sopenharmony_ci * pch_i2c_sendnack() - send NACK
4558c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
4568c2ecf20Sopenharmony_ci */
4578c2ecf20Sopenharmony_cistatic void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
4608c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
4618c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci/**
4658c2ecf20Sopenharmony_ci * pch_i2c_restart() - Generate I2C restart condition in normal mode.
4668c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA.
4698c2ecf20Sopenharmony_ci */
4708c2ecf20Sopenharmony_cistatic void pch_i2c_restart(struct i2c_algo_pch_data *adap)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
4738c2ecf20Sopenharmony_ci	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
4748c2ecf20Sopenharmony_ci	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART);
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci/**
4788c2ecf20Sopenharmony_ci * pch_i2c_readbytes() - read data  from I2C bus in normal mode.
4798c2ecf20Sopenharmony_ci * @i2c_adap:	Pointer to the struct i2c_adapter.
4808c2ecf20Sopenharmony_ci * @msgs:	Pointer to i2c_msg structure.
4818c2ecf20Sopenharmony_ci * @last:	specifies whether last message or not.
4828c2ecf20Sopenharmony_ci * @first:	specifies whether first message or not.
4838c2ecf20Sopenharmony_ci */
4848c2ecf20Sopenharmony_cistatic s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
4858c2ecf20Sopenharmony_ci			     u32 last, u32 first)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	u8 *buf;
4908c2ecf20Sopenharmony_ci	u32 count;
4918c2ecf20Sopenharmony_ci	u32 length;
4928c2ecf20Sopenharmony_ci	u32 addr;
4938c2ecf20Sopenharmony_ci	u32 addr_2_msb;
4948c2ecf20Sopenharmony_ci	u32 addr_8_lsb;
4958c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
4968c2ecf20Sopenharmony_ci	s32 rtn;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	length = msgs->len;
4998c2ecf20Sopenharmony_ci	buf = msgs->buf;
5008c2ecf20Sopenharmony_ci	addr = msgs->addr;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* enable master reception */
5038c2ecf20Sopenharmony_ci	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (first) {
5068c2ecf20Sopenharmony_ci		if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
5078c2ecf20Sopenharmony_ci			return -ETIME;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (msgs->flags & I2C_M_TEN) {
5118c2ecf20Sopenharmony_ci		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
5128c2ecf20Sopenharmony_ci		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
5138c2ecf20Sopenharmony_ci		if (first)
5148c2ecf20Sopenharmony_ci			pch_i2c_start(adap);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		rtn = pch_i2c_wait_for_check_xfer(adap);
5178c2ecf20Sopenharmony_ci		if (rtn)
5188c2ecf20Sopenharmony_ci			return rtn;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		addr_8_lsb = (addr & I2C_ADDR_MSK);
5218c2ecf20Sopenharmony_ci		iowrite32(addr_8_lsb, p + PCH_I2CDR);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		pch_i2c_restart(adap);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		rtn = pch_i2c_wait_for_check_xfer(adap);
5268c2ecf20Sopenharmony_ci		if (rtn)
5278c2ecf20Sopenharmony_ci			return rtn;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		addr_2_msb |= I2C_RD;
5308c2ecf20Sopenharmony_ci		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
5318c2ecf20Sopenharmony_ci	} else {
5328c2ecf20Sopenharmony_ci		/* 7 address bits + R/W bit */
5338c2ecf20Sopenharmony_ci		iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	/* check if it is the first message */
5378c2ecf20Sopenharmony_ci	if (first)
5388c2ecf20Sopenharmony_ci		pch_i2c_start(adap);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	rtn = pch_i2c_wait_for_check_xfer(adap);
5418c2ecf20Sopenharmony_ci	if (rtn)
5428c2ecf20Sopenharmony_ci		return rtn;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (length == 0) {
5458c2ecf20Sopenharmony_ci		pch_i2c_stop(adap);
5468c2ecf20Sopenharmony_ci		ioread32(p + PCH_I2CDR); /* Dummy read needs */
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		count = length;
5498c2ecf20Sopenharmony_ci	} else {
5508c2ecf20Sopenharmony_ci		int read_index;
5518c2ecf20Sopenharmony_ci		int loop;
5528c2ecf20Sopenharmony_ci		pch_i2c_sendack(adap);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		/* Dummy read */
5558c2ecf20Sopenharmony_ci		for (loop = 1, read_index = 0; loop < length; loop++) {
5568c2ecf20Sopenharmony_ci			buf[read_index] = ioread32(p + PCH_I2CDR);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci			if (loop != 1)
5598c2ecf20Sopenharmony_ci				read_index++;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci			rtn = pch_i2c_wait_for_check_xfer(adap);
5628c2ecf20Sopenharmony_ci			if (rtn)
5638c2ecf20Sopenharmony_ci				return rtn;
5648c2ecf20Sopenharmony_ci		}	/* end for */
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		pch_i2c_sendnack(adap);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci		buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		if (length != 1)
5718c2ecf20Sopenharmony_ci			read_index++;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		rtn = pch_i2c_wait_for_check_xfer(adap);
5748c2ecf20Sopenharmony_ci		if (rtn)
5758c2ecf20Sopenharmony_ci			return rtn;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci		if (last)
5788c2ecf20Sopenharmony_ci			pch_i2c_stop(adap);
5798c2ecf20Sopenharmony_ci		else
5808c2ecf20Sopenharmony_ci			pch_i2c_repstart(adap);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
5838c2ecf20Sopenharmony_ci		count = read_index;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return count;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/**
5908c2ecf20Sopenharmony_ci * pch_i2c_cb() - Interrupt handler Call back function
5918c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
5928c2ecf20Sopenharmony_ci */
5938c2ecf20Sopenharmony_cistatic void pch_i2c_cb(struct i2c_algo_pch_data *adap)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	u32 sts;
5968c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	sts = ioread32(p + PCH_I2CSR);
5998c2ecf20Sopenharmony_ci	sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
6008c2ecf20Sopenharmony_ci	if (sts & I2CMAL_BIT)
6018c2ecf20Sopenharmony_ci		adap->pch_event_flag |= I2CMAL_EVENT;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (sts & I2CMCF_BIT)
6048c2ecf20Sopenharmony_ci		adap->pch_event_flag |= I2CMCF_EVENT;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* clear the applicable bits */
6078c2ecf20Sopenharmony_ci	pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR));
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	wake_up(&pch_event);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci/**
6158c2ecf20Sopenharmony_ci * pch_i2c_handler() - interrupt handler for the PCH I2C controller
6168c2ecf20Sopenharmony_ci * @irq:	irq number.
6178c2ecf20Sopenharmony_ci * @pData:	cookie passed back to the handler function.
6188c2ecf20Sopenharmony_ci */
6198c2ecf20Sopenharmony_cistatic irqreturn_t pch_i2c_handler(int irq, void *pData)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	u32 reg_val;
6228c2ecf20Sopenharmony_ci	int flag;
6238c2ecf20Sopenharmony_ci	int i;
6248c2ecf20Sopenharmony_ci	struct adapter_info *adap_info = pData;
6258c2ecf20Sopenharmony_ci	void __iomem *p;
6268c2ecf20Sopenharmony_ci	u32 mode;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
6298c2ecf20Sopenharmony_ci		p = adap_info->pch_data[i].pch_base_address;
6308c2ecf20Sopenharmony_ci		mode = ioread32(p + PCH_I2CMOD);
6318c2ecf20Sopenharmony_ci		mode &= BUFFER_MODE | EEPROM_SR_MODE;
6328c2ecf20Sopenharmony_ci		if (mode != NORMAL_MODE) {
6338c2ecf20Sopenharmony_ci			pch_err(adap_info->pch_data,
6348c2ecf20Sopenharmony_ci				"I2C-%d mode(%d) is not supported\n", mode, i);
6358c2ecf20Sopenharmony_ci			continue;
6368c2ecf20Sopenharmony_ci		}
6378c2ecf20Sopenharmony_ci		reg_val = ioread32(p + PCH_I2CSR);
6388c2ecf20Sopenharmony_ci		if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
6398c2ecf20Sopenharmony_ci			pch_i2c_cb(&adap_info->pch_data[i]);
6408c2ecf20Sopenharmony_ci			flag = 1;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	return flag ? IRQ_HANDLED : IRQ_NONE;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci/**
6488c2ecf20Sopenharmony_ci * pch_i2c_xfer() - Reading adnd writing data through I2C bus
6498c2ecf20Sopenharmony_ci * @i2c_adap:	Pointer to the struct i2c_adapter.
6508c2ecf20Sopenharmony_ci * @msgs:	Pointer to i2c_msg structure.
6518c2ecf20Sopenharmony_ci * @num:	number of messages.
6528c2ecf20Sopenharmony_ci */
6538c2ecf20Sopenharmony_cistatic s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
6548c2ecf20Sopenharmony_ci			struct i2c_msg *msgs, s32 num)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct i2c_msg *pmsg;
6578c2ecf20Sopenharmony_ci	u32 i = 0;
6588c2ecf20Sopenharmony_ci	u32 status;
6598c2ecf20Sopenharmony_ci	s32 ret;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&pch_mutex);
6648c2ecf20Sopenharmony_ci	if (ret)
6658c2ecf20Sopenharmony_ci		return ret;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (adap->p_adapter_info->pch_i2c_suspended) {
6688c2ecf20Sopenharmony_ci		mutex_unlock(&pch_mutex);
6698c2ecf20Sopenharmony_ci		return -EBUSY;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n",
6738c2ecf20Sopenharmony_ci		adap->p_adapter_info->pch_i2c_suspended);
6748c2ecf20Sopenharmony_ci	/* transfer not completed */
6758c2ecf20Sopenharmony_ci	adap->pch_i2c_xfer_in_progress = true;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	for (i = 0; i < num && ret >= 0; i++) {
6788c2ecf20Sopenharmony_ci		pmsg = &msgs[i];
6798c2ecf20Sopenharmony_ci		pmsg->flags |= adap->pch_buff_mode_en;
6808c2ecf20Sopenharmony_ci		status = pmsg->flags;
6818c2ecf20Sopenharmony_ci		pch_dbg(adap,
6828c2ecf20Sopenharmony_ci			"After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		if ((status & (I2C_M_RD)) != false) {
6858c2ecf20Sopenharmony_ci			ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
6868c2ecf20Sopenharmony_ci						(i == 0));
6878c2ecf20Sopenharmony_ci		} else {
6888c2ecf20Sopenharmony_ci			ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
6898c2ecf20Sopenharmony_ci						 (i == 0));
6908c2ecf20Sopenharmony_ci		}
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	adap->pch_i2c_xfer_in_progress = false;	/* transfer completed */
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	mutex_unlock(&pch_mutex);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return (ret < 0) ? ret : num;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/**
7018c2ecf20Sopenharmony_ci * pch_i2c_func() - return the functionality of the I2C driver
7028c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
7038c2ecf20Sopenharmony_ci */
7048c2ecf20Sopenharmony_cistatic u32 pch_i2c_func(struct i2c_adapter *adap)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic const struct i2c_algorithm pch_algorithm = {
7108c2ecf20Sopenharmony_ci	.master_xfer = pch_i2c_xfer,
7118c2ecf20Sopenharmony_ci	.functionality = pch_i2c_func
7128c2ecf20Sopenharmony_ci};
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/**
7158c2ecf20Sopenharmony_ci * pch_i2c_disbl_int() - Disable PCH I2C interrupts
7168c2ecf20Sopenharmony_ci * @adap:	Pointer to struct i2c_algo_pch_data.
7178c2ecf20Sopenharmony_ci */
7188c2ecf20Sopenharmony_cistatic void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	void __iomem *p = adap->pch_base_address;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic int pch_i2c_probe(struct pci_dev *pdev,
7308c2ecf20Sopenharmony_ci				   const struct pci_device_id *id)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	void __iomem *base_addr;
7338c2ecf20Sopenharmony_ci	int ret;
7348c2ecf20Sopenharmony_ci	int i, j;
7358c2ecf20Sopenharmony_ci	struct adapter_info *adap_info;
7368c2ecf20Sopenharmony_ci	struct i2c_adapter *pch_adap;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	pch_pci_dbg(pdev, "Entered.\n");
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
7418c2ecf20Sopenharmony_ci	if (adap_info == NULL)
7428c2ecf20Sopenharmony_ci		return -ENOMEM;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
7458c2ecf20Sopenharmony_ci	if (ret) {
7468c2ecf20Sopenharmony_ci		pch_pci_err(pdev, "pci_enable_device FAILED\n");
7478c2ecf20Sopenharmony_ci		goto err_pci_enable;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	ret = pci_request_regions(pdev, KBUILD_MODNAME);
7518c2ecf20Sopenharmony_ci	if (ret) {
7528c2ecf20Sopenharmony_ci		pch_pci_err(pdev, "pci_request_regions FAILED\n");
7538c2ecf20Sopenharmony_ci		goto err_pci_req;
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	base_addr = pci_iomap(pdev, 1, 0);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (base_addr == NULL) {
7598c2ecf20Sopenharmony_ci		pch_pci_err(pdev, "pci_iomap FAILED\n");
7608c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7618c2ecf20Sopenharmony_ci		goto err_pci_iomap;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* Set the number of I2C channel instance */
7658c2ecf20Sopenharmony_ci	adap_info->ch_num = id->driver_data;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++) {
7688c2ecf20Sopenharmony_ci		pch_adap = &adap_info->pch_data[i].pch_adapter;
7698c2ecf20Sopenharmony_ci		adap_info->pch_i2c_suspended = false;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		adap_info->pch_data[i].p_adapter_info = adap_info;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		pch_adap->owner = THIS_MODULE;
7748c2ecf20Sopenharmony_ci		pch_adap->class = I2C_CLASS_HWMON;
7758c2ecf20Sopenharmony_ci		strlcpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name));
7768c2ecf20Sopenharmony_ci		pch_adap->algo = &pch_algorithm;
7778c2ecf20Sopenharmony_ci		pch_adap->algo_data = &adap_info->pch_data[i];
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		/* base_addr + offset; */
7808c2ecf20Sopenharmony_ci		adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		pch_adap->dev.of_node = pdev->dev.of_node;
7838c2ecf20Sopenharmony_ci		pch_adap->dev.parent = &pdev->dev;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
7878c2ecf20Sopenharmony_ci		  KBUILD_MODNAME, adap_info);
7888c2ecf20Sopenharmony_ci	if (ret) {
7898c2ecf20Sopenharmony_ci		pch_pci_err(pdev, "request_irq FAILED\n");
7908c2ecf20Sopenharmony_ci		goto err_request_irq;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++) {
7948c2ecf20Sopenharmony_ci		pch_adap = &adap_info->pch_data[i].pch_adapter;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci		pch_i2c_init(&adap_info->pch_data[i]);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		pch_adap->nr = i;
7998c2ecf20Sopenharmony_ci		ret = i2c_add_numbered_adapter(pch_adap);
8008c2ecf20Sopenharmony_ci		if (ret) {
8018c2ecf20Sopenharmony_ci			pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
8028c2ecf20Sopenharmony_ci			goto err_add_adapter;
8038c2ecf20Sopenharmony_ci		}
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, adap_info);
8078c2ecf20Sopenharmony_ci	pch_pci_dbg(pdev, "returns %d.\n", ret);
8088c2ecf20Sopenharmony_ci	return 0;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_cierr_add_adapter:
8118c2ecf20Sopenharmony_ci	for (j = 0; j < i; j++)
8128c2ecf20Sopenharmony_ci		i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
8138c2ecf20Sopenharmony_ci	free_irq(pdev->irq, adap_info);
8148c2ecf20Sopenharmony_cierr_request_irq:
8158c2ecf20Sopenharmony_ci	pci_iounmap(pdev, base_addr);
8168c2ecf20Sopenharmony_cierr_pci_iomap:
8178c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
8188c2ecf20Sopenharmony_cierr_pci_req:
8198c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
8208c2ecf20Sopenharmony_cierr_pci_enable:
8218c2ecf20Sopenharmony_ci	kfree(adap_info);
8228c2ecf20Sopenharmony_ci	return ret;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic void pch_i2c_remove(struct pci_dev *pdev)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	int i;
8288c2ecf20Sopenharmony_ci	struct adapter_info *adap_info = pci_get_drvdata(pdev);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	free_irq(pdev->irq, adap_info);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++) {
8338c2ecf20Sopenharmony_ci		pch_i2c_disbl_int(&adap_info->pch_data[i]);
8348c2ecf20Sopenharmony_ci		i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (adap_info->pch_data[0].pch_base_address)
8388c2ecf20Sopenharmony_ci		pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++)
8418c2ecf20Sopenharmony_ci		adap_info->pch_data[i].pch_base_address = NULL;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
8468c2ecf20Sopenharmony_ci	kfree(adap_info);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic int __maybe_unused pch_i2c_suspend(struct device *dev)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	int i;
8528c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
8538c2ecf20Sopenharmony_ci	struct adapter_info *adap_info = pci_get_drvdata(pdev);
8548c2ecf20Sopenharmony_ci	void __iomem *p = adap_info->pch_data[0].pch_base_address;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	adap_info->pch_i2c_suspended = true;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++) {
8598c2ecf20Sopenharmony_ci		while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
8608c2ecf20Sopenharmony_ci			/* Wait until all channel transfers are completed */
8618c2ecf20Sopenharmony_ci			msleep(20);
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	/* Disable the i2c interrupts */
8668c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++)
8678c2ecf20Sopenharmony_ci		pch_i2c_disbl_int(&adap_info->pch_data[i]);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
8708c2ecf20Sopenharmony_ci		"invoked function pch_i2c_disbl_int successfully\n",
8718c2ecf20Sopenharmony_ci		ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
8728c2ecf20Sopenharmony_ci		ioread32(p + PCH_I2CESRSTA));
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	return 0;
8758c2ecf20Sopenharmony_ci}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic int __maybe_unused pch_i2c_resume(struct device *dev)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	int i;
8808c2ecf20Sopenharmony_ci	struct adapter_info *adap_info = dev_get_drvdata(dev);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	for (i = 0; i < adap_info->ch_num; i++)
8838c2ecf20Sopenharmony_ci		pch_i2c_init(&adap_info->pch_data[i]);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	adap_info->pch_i2c_suspended = false;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	return 0;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pch_i2c_pm_ops, pch_i2c_suspend, pch_i2c_resume);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic struct pci_driver pch_pcidriver = {
8938c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
8948c2ecf20Sopenharmony_ci	.id_table = pch_pcidev_id,
8958c2ecf20Sopenharmony_ci	.probe = pch_i2c_probe,
8968c2ecf20Sopenharmony_ci	.remove = pch_i2c_remove,
8978c2ecf20Sopenharmony_ci	.driver.pm = &pch_i2c_pm_ops,
8988c2ecf20Sopenharmony_ci};
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_cimodule_pci_driver(pch_pcidriver);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
9038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
9048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tomoya MORINAGA. <tomoya.rohm@gmail.com>");
9058c2ecf20Sopenharmony_cimodule_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
9068c2ecf20Sopenharmony_cimodule_param(pch_clk, int, (S_IRUSR | S_IWUSR));
907