162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for the NXP SAA7164 PCIe bridge
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/moduleparam.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "saa7164.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct saa7164_i2c *bus = i2c_adap->algo_data;
1962306a36Sopenharmony_ci	struct saa7164_dev *dev = bus->dev;
2062306a36Sopenharmony_ci	int i, retval = 0;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	for (i = 0 ; i < num; i++) {
2562306a36Sopenharmony_ci		dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
2662306a36Sopenharmony_ci			__func__, num, msgs[i].addr, msgs[i].len);
2762306a36Sopenharmony_ci		if (msgs[i].flags & I2C_M_RD) {
2862306a36Sopenharmony_ci			retval = saa7164_api_i2c_read(bus,
2962306a36Sopenharmony_ci				msgs[i].addr,
3062306a36Sopenharmony_ci				0 /* reglen */,
3162306a36Sopenharmony_ci				NULL /* reg */, msgs[i].len, msgs[i].buf);
3262306a36Sopenharmony_ci		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
3362306a36Sopenharmony_ci			   msgs[i].addr == msgs[i + 1].addr) {
3462306a36Sopenharmony_ci			/* write then read from same address */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci			retval = saa7164_api_i2c_read(bus, msgs[i].addr,
3762306a36Sopenharmony_ci				msgs[i].len, msgs[i].buf,
3862306a36Sopenharmony_ci				msgs[i+1].len, msgs[i+1].buf
3962306a36Sopenharmony_ci				);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci			i++;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci			if (retval < 0)
4462306a36Sopenharmony_ci				goto err;
4562306a36Sopenharmony_ci		} else {
4662306a36Sopenharmony_ci			/* write */
4762306a36Sopenharmony_ci			retval = saa7164_api_i2c_write(bus, msgs[i].addr,
4862306a36Sopenharmony_ci				msgs[i].len, msgs[i].buf);
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci		if (retval < 0)
5162306a36Sopenharmony_ci			goto err;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	return num;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cierr:
5662306a36Sopenharmony_ci	return retval;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic u32 saa7164_functionality(struct i2c_adapter *adap)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return I2C_FUNC_I2C;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct i2c_algorithm saa7164_i2c_algo_template = {
6562306a36Sopenharmony_ci	.master_xfer	= i2c_xfer,
6662306a36Sopenharmony_ci	.functionality	= saa7164_functionality,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic const struct i2c_adapter saa7164_i2c_adap_template = {
7262306a36Sopenharmony_ci	.name              = "saa7164",
7362306a36Sopenharmony_ci	.owner             = THIS_MODULE,
7462306a36Sopenharmony_ci	.algo              = &saa7164_i2c_algo_template,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct i2c_client saa7164_i2c_client_template = {
7862306a36Sopenharmony_ci	.name	= "saa7164 internal",
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciint saa7164_i2c_register(struct saa7164_i2c *bus)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct saa7164_dev *dev = bus->dev;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	bus->i2c_adap = saa7164_i2c_adap_template;
8862306a36Sopenharmony_ci	bus->i2c_client = saa7164_i2c_client_template;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	bus->i2c_adap.dev.parent = &dev->pci->dev;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	strscpy(bus->i2c_adap.name, bus->dev->name,
9362306a36Sopenharmony_ci		sizeof(bus->i2c_adap.name));
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	bus->i2c_adap.algo_data = bus;
9662306a36Sopenharmony_ci	i2c_set_adapdata(&bus->i2c_adap, bus);
9762306a36Sopenharmony_ci	i2c_add_adapter(&bus->i2c_adap);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	bus->i2c_client.adapter = &bus->i2c_adap;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (0 != bus->i2c_rc)
10262306a36Sopenharmony_ci		printk(KERN_ERR "%s: i2c bus %d register FAILED\n",
10362306a36Sopenharmony_ci			dev->name, bus->nr);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	return bus->i2c_rc;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint saa7164_i2c_unregister(struct saa7164_i2c *bus)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	i2c_del_adapter(&bus->i2c_adap);
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
113