1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab * Driver for the NXP SAA7164 PCIe bridge
4b285192aSMauro Carvalho Chehab *
563a412ecSSteven Toth * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
6b285192aSMauro Carvalho Chehab */
7b285192aSMauro Carvalho Chehab
8b285192aSMauro Carvalho Chehab #include <linux/module.h>
9b285192aSMauro Carvalho Chehab #include <linux/moduleparam.h>
10b285192aSMauro Carvalho Chehab #include <linux/init.h>
11b285192aSMauro Carvalho Chehab #include <linux/delay.h>
12b285192aSMauro Carvalho Chehab #include <linux/io.h>
13b285192aSMauro Carvalho Chehab
14b285192aSMauro Carvalho Chehab #include "saa7164.h"
15b285192aSMauro Carvalho Chehab
i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg * msgs,int num)16b285192aSMauro Carvalho Chehab static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
17b285192aSMauro Carvalho Chehab {
18b285192aSMauro Carvalho Chehab struct saa7164_i2c *bus = i2c_adap->algo_data;
19b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = bus->dev;
20b285192aSMauro Carvalho Chehab int i, retval = 0;
21b285192aSMauro Carvalho Chehab
22b285192aSMauro Carvalho Chehab dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num);
23b285192aSMauro Carvalho Chehab
24b285192aSMauro Carvalho Chehab for (i = 0 ; i < num; i++) {
25b285192aSMauro Carvalho Chehab dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
26b285192aSMauro Carvalho Chehab __func__, num, msgs[i].addr, msgs[i].len);
27b285192aSMauro Carvalho Chehab if (msgs[i].flags & I2C_M_RD) {
285f954b5bSSteven Toth retval = saa7164_api_i2c_read(bus,
295f954b5bSSteven Toth msgs[i].addr,
305f954b5bSSteven Toth 0 /* reglen */,
317071b2eaSHans Verkuil NULL /* reg */, msgs[i].len, msgs[i].buf);
32b285192aSMauro Carvalho Chehab } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
33b285192aSMauro Carvalho Chehab msgs[i].addr == msgs[i + 1].addr) {
34b285192aSMauro Carvalho Chehab /* write then read from same address */
35b285192aSMauro Carvalho Chehab
36b285192aSMauro Carvalho Chehab retval = saa7164_api_i2c_read(bus, msgs[i].addr,
37b285192aSMauro Carvalho Chehab msgs[i].len, msgs[i].buf,
38b285192aSMauro Carvalho Chehab msgs[i+1].len, msgs[i+1].buf
39b285192aSMauro Carvalho Chehab );
40b285192aSMauro Carvalho Chehab
41b285192aSMauro Carvalho Chehab i++;
42b285192aSMauro Carvalho Chehab
43b285192aSMauro Carvalho Chehab if (retval < 0)
44b285192aSMauro Carvalho Chehab goto err;
45b285192aSMauro Carvalho Chehab } else {
46b285192aSMauro Carvalho Chehab /* write */
47b285192aSMauro Carvalho Chehab retval = saa7164_api_i2c_write(bus, msgs[i].addr,
48b285192aSMauro Carvalho Chehab msgs[i].len, msgs[i].buf);
49b285192aSMauro Carvalho Chehab }
50b285192aSMauro Carvalho Chehab if (retval < 0)
51b285192aSMauro Carvalho Chehab goto err;
52b285192aSMauro Carvalho Chehab }
53b285192aSMauro Carvalho Chehab return num;
54b285192aSMauro Carvalho Chehab
55b285192aSMauro Carvalho Chehab err:
56b285192aSMauro Carvalho Chehab return retval;
57b285192aSMauro Carvalho Chehab }
58b285192aSMauro Carvalho Chehab
saa7164_functionality(struct i2c_adapter * adap)59b285192aSMauro Carvalho Chehab static u32 saa7164_functionality(struct i2c_adapter *adap)
60b285192aSMauro Carvalho Chehab {
61b285192aSMauro Carvalho Chehab return I2C_FUNC_I2C;
62b285192aSMauro Carvalho Chehab }
63b285192aSMauro Carvalho Chehab
6478f2c50bSJulia Lawall static const struct i2c_algorithm saa7164_i2c_algo_template = {
65b285192aSMauro Carvalho Chehab .master_xfer = i2c_xfer,
66b285192aSMauro Carvalho Chehab .functionality = saa7164_functionality,
67b285192aSMauro Carvalho Chehab };
68b285192aSMauro Carvalho Chehab
69b285192aSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
70b285192aSMauro Carvalho Chehab
71e5fffebeSBhumika Goyal static const struct i2c_adapter saa7164_i2c_adap_template = {
72b285192aSMauro Carvalho Chehab .name = "saa7164",
73b285192aSMauro Carvalho Chehab .owner = THIS_MODULE,
74b285192aSMauro Carvalho Chehab .algo = &saa7164_i2c_algo_template,
75b285192aSMauro Carvalho Chehab };
76b285192aSMauro Carvalho Chehab
77b8e9b36dSBhumika Goyal static const struct i2c_client saa7164_i2c_client_template = {
78b285192aSMauro Carvalho Chehab .name = "saa7164 internal",
79b285192aSMauro Carvalho Chehab };
80b285192aSMauro Carvalho Chehab
saa7164_i2c_register(struct saa7164_i2c * bus)81b285192aSMauro Carvalho Chehab int saa7164_i2c_register(struct saa7164_i2c *bus)
82b285192aSMauro Carvalho Chehab {
83b285192aSMauro Carvalho Chehab struct saa7164_dev *dev = bus->dev;
84b285192aSMauro Carvalho Chehab
85b285192aSMauro Carvalho Chehab dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr);
86b285192aSMauro Carvalho Chehab
87b285192aSMauro Carvalho Chehab bus->i2c_adap = saa7164_i2c_adap_template;
88b285192aSMauro Carvalho Chehab bus->i2c_client = saa7164_i2c_client_template;
89b285192aSMauro Carvalho Chehab
90b285192aSMauro Carvalho Chehab bus->i2c_adap.dev.parent = &dev->pci->dev;
91b285192aSMauro Carvalho Chehab
92c0decac1SMauro Carvalho Chehab strscpy(bus->i2c_adap.name, bus->dev->name,
93b285192aSMauro Carvalho Chehab sizeof(bus->i2c_adap.name));
94b285192aSMauro Carvalho Chehab
95b285192aSMauro Carvalho Chehab bus->i2c_adap.algo_data = bus;
96b285192aSMauro Carvalho Chehab i2c_set_adapdata(&bus->i2c_adap, bus);
97b285192aSMauro Carvalho Chehab i2c_add_adapter(&bus->i2c_adap);
98b285192aSMauro Carvalho Chehab
99b285192aSMauro Carvalho Chehab bus->i2c_client.adapter = &bus->i2c_adap;
100b285192aSMauro Carvalho Chehab
101b285192aSMauro Carvalho Chehab if (0 != bus->i2c_rc)
102b285192aSMauro Carvalho Chehab printk(KERN_ERR "%s: i2c bus %d register FAILED\n",
103b285192aSMauro Carvalho Chehab dev->name, bus->nr);
104b285192aSMauro Carvalho Chehab
105b285192aSMauro Carvalho Chehab return bus->i2c_rc;
106b285192aSMauro Carvalho Chehab }
107b285192aSMauro Carvalho Chehab
saa7164_i2c_unregister(struct saa7164_i2c * bus)108b285192aSMauro Carvalho Chehab int saa7164_i2c_unregister(struct saa7164_i2c *bus)
109b285192aSMauro Carvalho Chehab {
110b285192aSMauro Carvalho Chehab i2c_del_adapter(&bus->i2c_adap);
111b285192aSMauro Carvalho Chehab return 0;
112b285192aSMauro Carvalho Chehab }
113