16894f640SThomas Richard // SPDX-License-Identifier: GPL-2.0-or-later
26894f640SThomas Richard /*
36894f640SThomas Richard * Congatec Board Controller I2C busses driver
46894f640SThomas Richard *
56894f640SThomas Richard * Copyright (C) 2024 Bootlin
66894f640SThomas Richard * Author: Thomas Richard <thomas.richard@bootlin.com>
76894f640SThomas Richard */
86894f640SThomas Richard
96894f640SThomas Richard #include <linux/i2c.h>
106894f640SThomas Richard #include <linux/iopoll.h>
116894f640SThomas Richard #include <linux/mfd/cgbc.h>
126894f640SThomas Richard #include <linux/module.h>
136894f640SThomas Richard #include <linux/platform_device.h>
146894f640SThomas Richard
156894f640SThomas Richard #define CGBC_I2C_PRIMARY_BUS_ID 0
166894f640SThomas Richard #define CGBC_I2C_PM_BUS_ID 4
176894f640SThomas Richard
186894f640SThomas Richard #define CGBC_I2C_CMD_START 0x40
196894f640SThomas Richard #define CGBC_I2C_CMD_STAT 0x48
206894f640SThomas Richard #define CGBC_I2C_CMD_DATA 0x50
216894f640SThomas Richard #define CGBC_I2C_CMD_SPEED 0x58
226894f640SThomas Richard
236894f640SThomas Richard #define CGBC_I2C_STAT_IDL 0x00
246894f640SThomas Richard #define CGBC_I2C_STAT_DAT 0x01
256894f640SThomas Richard #define CGBC_I2C_STAT_BUSY 0x02
266894f640SThomas Richard
276894f640SThomas Richard #define CGBC_I2C_START 0x80
286894f640SThomas Richard #define CGBC_I2C_STOP 0x40
296894f640SThomas Richard
306894f640SThomas Richard #define CGBC_I2C_LAST_ACK 0x80 /* send ACK on last read byte */
316894f640SThomas Richard
326894f640SThomas Richard /*
336894f640SThomas Richard * Reference code defines 1kHz as min freq and 6.1MHz as max freq.
346894f640SThomas Richard * But in practice, the board controller limits the frequency to 1MHz, and the
356894f640SThomas Richard * 1kHz is not functional (minimal working freq is 50kHz).
366894f640SThomas Richard * So use these values as limits.
376894f640SThomas Richard */
386894f640SThomas Richard #define CGBC_I2C_FREQ_MIN_HZ 50000 /* 50 kHz */
396894f640SThomas Richard #define CGBC_I2C_FREQ_MAX_HZ 1000000 /* 1 MHz */
406894f640SThomas Richard
416894f640SThomas Richard #define CGBC_I2C_FREQ_UNIT_1KHZ 0x40
426894f640SThomas Richard #define CGBC_I2C_FREQ_UNIT_10KHZ 0x80
436894f640SThomas Richard #define CGBC_I2C_FREQ_UNIT_100KHZ 0xC0
446894f640SThomas Richard
456894f640SThomas Richard #define CGBC_I2C_FREQ_UNIT_MASK 0xC0
466894f640SThomas Richard #define CGBC_I2C_FREQ_VALUE_MASK 0x3F
476894f640SThomas Richard
486894f640SThomas Richard #define CGBC_I2C_READ_MAX_LEN 31
496894f640SThomas Richard #define CGBC_I2C_WRITE_MAX_LEN 32
506894f640SThomas Richard
516894f640SThomas Richard #define CGBC_I2C_CMD_HEADER_SIZE 4
526894f640SThomas Richard #define CGBC_I2C_CMD_SIZE (CGBC_I2C_CMD_HEADER_SIZE + CGBC_I2C_WRITE_MAX_LEN)
536894f640SThomas Richard
546894f640SThomas Richard enum cgbc_i2c_state {
556894f640SThomas Richard CGBC_I2C_STATE_DONE = 0,
566894f640SThomas Richard CGBC_I2C_STATE_INIT,
576894f640SThomas Richard CGBC_I2C_STATE_START,
586894f640SThomas Richard CGBC_I2C_STATE_READ,
596894f640SThomas Richard CGBC_I2C_STATE_WRITE,
606894f640SThomas Richard CGBC_I2C_STATE_ERROR,
616894f640SThomas Richard };
626894f640SThomas Richard
636894f640SThomas Richard struct i2c_algo_cgbc_data {
646894f640SThomas Richard u8 bus_id;
656894f640SThomas Richard unsigned long read_maxtime_us;
666894f640SThomas Richard };
676894f640SThomas Richard
686894f640SThomas Richard struct cgbc_i2c_data {
696894f640SThomas Richard struct device *dev;
706894f640SThomas Richard struct cgbc_device_data *cgbc;
716894f640SThomas Richard struct i2c_adapter adap;
726894f640SThomas Richard struct i2c_msg *msg;
736894f640SThomas Richard int nmsgs;
746894f640SThomas Richard int pos;
756894f640SThomas Richard enum cgbc_i2c_state state;
766894f640SThomas Richard };
776894f640SThomas Richard
786894f640SThomas Richard struct cgbc_i2c_transfer {
796894f640SThomas Richard u8 bus_id;
806894f640SThomas Richard bool start;
816894f640SThomas Richard bool stop;
826894f640SThomas Richard bool last_ack;
836894f640SThomas Richard u8 read;
846894f640SThomas Richard u8 write;
856894f640SThomas Richard u8 addr;
866894f640SThomas Richard u8 data[CGBC_I2C_WRITE_MAX_LEN];
876894f640SThomas Richard };
886894f640SThomas Richard
cgbc_i2c_freq_to_reg(unsigned int bus_frequency)896894f640SThomas Richard static u8 cgbc_i2c_freq_to_reg(unsigned int bus_frequency)
906894f640SThomas Richard {
916894f640SThomas Richard u8 reg;
926894f640SThomas Richard
936894f640SThomas Richard if (bus_frequency <= 10000)
946894f640SThomas Richard reg = CGBC_I2C_FREQ_UNIT_1KHZ | (bus_frequency / 1000);
956894f640SThomas Richard else if (bus_frequency <= 100000)
966894f640SThomas Richard reg = CGBC_I2C_FREQ_UNIT_10KHZ | (bus_frequency / 10000);
976894f640SThomas Richard else
986894f640SThomas Richard reg = CGBC_I2C_FREQ_UNIT_100KHZ | (bus_frequency / 100000);
996894f640SThomas Richard
1006894f640SThomas Richard return reg;
1016894f640SThomas Richard }
1026894f640SThomas Richard
cgbc_i2c_reg_to_freq(u8 reg)1036894f640SThomas Richard static unsigned int cgbc_i2c_reg_to_freq(u8 reg)
1046894f640SThomas Richard {
1056894f640SThomas Richard unsigned int freq = reg & CGBC_I2C_FREQ_VALUE_MASK;
1066894f640SThomas Richard u8 unit = reg & CGBC_I2C_FREQ_UNIT_MASK;
1076894f640SThomas Richard
1086894f640SThomas Richard if (unit == CGBC_I2C_FREQ_UNIT_100KHZ)
1096894f640SThomas Richard return freq * 100000;
1106894f640SThomas Richard else if (unit == CGBC_I2C_FREQ_UNIT_10KHZ)
1116894f640SThomas Richard return freq * 10000;
1126894f640SThomas Richard else
1136894f640SThomas Richard return freq * 1000;
1146894f640SThomas Richard }
1156894f640SThomas Richard
cgbc_i2c_get_status(struct i2c_adapter * adap)1166894f640SThomas Richard static int cgbc_i2c_get_status(struct i2c_adapter *adap)
1176894f640SThomas Richard {
1186894f640SThomas Richard struct i2c_algo_cgbc_data *algo_data = adap->algo_data;
1196894f640SThomas Richard struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
1206894f640SThomas Richard struct cgbc_device_data *cgbc = i2c->cgbc;
1216894f640SThomas Richard u8 cmd = CGBC_I2C_CMD_STAT | algo_data->bus_id;
1226894f640SThomas Richard u8 status;
1236894f640SThomas Richard int ret;
1246894f640SThomas Richard
1256894f640SThomas Richard ret = cgbc_command(cgbc, &cmd, sizeof(cmd), NULL, 0, &status);
1266894f640SThomas Richard if (ret)
1276894f640SThomas Richard return ret;
1286894f640SThomas Richard
1296894f640SThomas Richard return status;
1306894f640SThomas Richard }
1316894f640SThomas Richard
cgbc_i2c_set_frequency(struct i2c_adapter * adap,unsigned int bus_frequency)1326894f640SThomas Richard static int cgbc_i2c_set_frequency(struct i2c_adapter *adap,
1336894f640SThomas Richard unsigned int bus_frequency)
1346894f640SThomas Richard {
1356894f640SThomas Richard struct i2c_algo_cgbc_data *algo_data = adap->algo_data;
1366894f640SThomas Richard struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
1376894f640SThomas Richard struct cgbc_device_data *cgbc = i2c->cgbc;
1386894f640SThomas Richard u8 cmd[2], data;
1396894f640SThomas Richard int ret;
1406894f640SThomas Richard
1416894f640SThomas Richard if (bus_frequency > CGBC_I2C_FREQ_MAX_HZ ||
1426894f640SThomas Richard bus_frequency < CGBC_I2C_FREQ_MIN_HZ) {
1436894f640SThomas Richard dev_info(i2c->dev, "invalid frequency %u, using default\n", bus_frequency);
1446894f640SThomas Richard bus_frequency = I2C_MAX_STANDARD_MODE_FREQ;
1456894f640SThomas Richard }
1466894f640SThomas Richard
1476894f640SThomas Richard cmd[0] = CGBC_I2C_CMD_SPEED | algo_data->bus_id;
1486894f640SThomas Richard cmd[1] = cgbc_i2c_freq_to_reg(bus_frequency);
1496894f640SThomas Richard
1506894f640SThomas Richard ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL);
1516894f640SThomas Richard if (ret)
1526894f640SThomas Richard return dev_err_probe(i2c->dev, ret,
1536894f640SThomas Richard "Failed to initialize I2C bus %s",
1546894f640SThomas Richard adap->name);
1556894f640SThomas Richard
1566894f640SThomas Richard cmd[1] = 0x00;
1576894f640SThomas Richard
1586894f640SThomas Richard ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL);
1596894f640SThomas Richard if (ret)
1606894f640SThomas Richard return dev_err_probe(i2c->dev, ret,
1616894f640SThomas Richard "Failed to get I2C bus frequency");
1626894f640SThomas Richard
1636894f640SThomas Richard bus_frequency = cgbc_i2c_reg_to_freq(data);
1646894f640SThomas Richard
1656894f640SThomas Richard dev_dbg(i2c->dev, "%s is running at %d Hz\n", adap->name, bus_frequency);
1666894f640SThomas Richard
1676894f640SThomas Richard /*
1686894f640SThomas Richard * The read_maxtime_us variable represents the maximum time to wait
1696894f640SThomas Richard * for data during a read operation. The maximum amount of data that
1706894f640SThomas Richard * can be read by a command is CGBC_I2C_READ_MAX_LEN.
1716894f640SThomas Richard * Therefore, calculate the max time to properly size the timeout.
1726894f640SThomas Richard */
1736894f640SThomas Richard algo_data->read_maxtime_us = (BITS_PER_BYTE + 1) * CGBC_I2C_READ_MAX_LEN
1746894f640SThomas Richard * USEC_PER_SEC / bus_frequency;
1756894f640SThomas Richard
1766894f640SThomas Richard return 0;
1776894f640SThomas Richard }
1786894f640SThomas Richard
cgbc_i2c_xfer_to_cmd(struct cgbc_i2c_transfer xfer,u8 * cmd)1796894f640SThomas Richard static unsigned int cgbc_i2c_xfer_to_cmd(struct cgbc_i2c_transfer xfer, u8 *cmd)
1806894f640SThomas Richard {
1816894f640SThomas Richard int i = 0;
1826894f640SThomas Richard
1836894f640SThomas Richard cmd[i++] = CGBC_I2C_CMD_START | xfer.bus_id;
1846894f640SThomas Richard
1856894f640SThomas Richard cmd[i] = (xfer.start) ? CGBC_I2C_START : 0x00;
1866894f640SThomas Richard if (xfer.stop)
1876894f640SThomas Richard cmd[i] |= CGBC_I2C_STOP;
1886894f640SThomas Richard cmd[i++] |= (xfer.start) ? xfer.write + 1 : xfer.write;
1896894f640SThomas Richard
1906894f640SThomas Richard cmd[i++] = (xfer.last_ack) ? (xfer.read | CGBC_I2C_LAST_ACK) : xfer.read;
1916894f640SThomas Richard
1926894f640SThomas Richard if (xfer.start)
1936894f640SThomas Richard cmd[i++] = xfer.addr;
1946894f640SThomas Richard
1956894f640SThomas Richard if (xfer.write > 0)
1966894f640SThomas Richard memcpy(&cmd[i], &xfer.data, xfer.write);
1976894f640SThomas Richard
1986894f640SThomas Richard return i + xfer.write;
1996894f640SThomas Richard }
2006894f640SThomas Richard
cgbc_i2c_xfer_msg(struct i2c_adapter * adap)2016894f640SThomas Richard static int cgbc_i2c_xfer_msg(struct i2c_adapter *adap)
2026894f640SThomas Richard {
2036894f640SThomas Richard struct i2c_algo_cgbc_data *algo_data = adap->algo_data;
2046894f640SThomas Richard struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
2056894f640SThomas Richard struct cgbc_device_data *cgbc = i2c->cgbc;
2066894f640SThomas Richard struct i2c_msg *msg = i2c->msg;
2076894f640SThomas Richard u8 cmd[CGBC_I2C_CMD_SIZE];
2086894f640SThomas Richard int ret, max_len, len, i;
2096894f640SThomas Richard unsigned int cmd_len;
2106894f640SThomas Richard u8 cmd_data;
2116894f640SThomas Richard
2126894f640SThomas Richard struct cgbc_i2c_transfer xfer = {
2136894f640SThomas Richard .bus_id = algo_data->bus_id,
2146894f640SThomas Richard .addr = i2c_8bit_addr_from_msg(msg),
2156894f640SThomas Richard };
2166894f640SThomas Richard
2176894f640SThomas Richard if (i2c->state == CGBC_I2C_STATE_DONE)
2186894f640SThomas Richard return 0;
2196894f640SThomas Richard
2206894f640SThomas Richard ret = cgbc_i2c_get_status(adap);
2216894f640SThomas Richard
2226894f640SThomas Richard if (ret == CGBC_I2C_STAT_BUSY)
2236894f640SThomas Richard return -EBUSY;
2246894f640SThomas Richard else if (ret < 0)
2256894f640SThomas Richard goto err;
2266894f640SThomas Richard
2276894f640SThomas Richard if (i2c->state == CGBC_I2C_STATE_INIT ||
2286894f640SThomas Richard (i2c->state == CGBC_I2C_STATE_WRITE && msg->flags & I2C_M_RD))
2296894f640SThomas Richard xfer.start = true;
2306894f640SThomas Richard
2316894f640SThomas Richard i2c->state = (msg->flags & I2C_M_RD) ? CGBC_I2C_STATE_READ : CGBC_I2C_STATE_WRITE;
2326894f640SThomas Richard
2336894f640SThomas Richard max_len = (i2c->state == CGBC_I2C_STATE_READ) ?
2346894f640SThomas Richard CGBC_I2C_READ_MAX_LEN : CGBC_I2C_WRITE_MAX_LEN;
2356894f640SThomas Richard
2366894f640SThomas Richard if (msg->len - i2c->pos > max_len) {
2376894f640SThomas Richard len = max_len;
2386894f640SThomas Richard } else {
2396894f640SThomas Richard len = msg->len - i2c->pos;
2406894f640SThomas Richard
2416894f640SThomas Richard if (i2c->nmsgs == 1)
2426894f640SThomas Richard xfer.stop = true;
2436894f640SThomas Richard }
2446894f640SThomas Richard
2456894f640SThomas Richard if (i2c->state == CGBC_I2C_STATE_WRITE) {
2466894f640SThomas Richard xfer.write = len;
2476894f640SThomas Richard xfer.read = 0;
2486894f640SThomas Richard
2496894f640SThomas Richard for (i = 0; i < len; i++)
2506894f640SThomas Richard xfer.data[i] = msg->buf[i2c->pos + i];
2516894f640SThomas Richard
2526894f640SThomas Richard cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]);
2536894f640SThomas Richard
2546894f640SThomas Richard ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL);
2556894f640SThomas Richard if (ret)
2566894f640SThomas Richard goto err;
2576894f640SThomas Richard } else if (i2c->state == CGBC_I2C_STATE_READ) {
2586894f640SThomas Richard xfer.write = 0;
2596894f640SThomas Richard xfer.read = len;
2606894f640SThomas Richard
2616894f640SThomas Richard if (i2c->nmsgs > 1 || msg->len - i2c->pos > max_len)
2626894f640SThomas Richard xfer.read |= CGBC_I2C_LAST_ACK;
2636894f640SThomas Richard
2646894f640SThomas Richard cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]);
2656894f640SThomas Richard ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL);
2666894f640SThomas Richard if (ret)
2676894f640SThomas Richard goto err;
2686894f640SThomas Richard
2696894f640SThomas Richard ret = read_poll_timeout(cgbc_i2c_get_status, ret,
2706894f640SThomas Richard ret != CGBC_I2C_STAT_BUSY, 0,
2716894f640SThomas Richard 2 * algo_data->read_maxtime_us, false, adap);
2726894f640SThomas Richard if (ret < 0)
2736894f640SThomas Richard goto err;
2746894f640SThomas Richard
2756894f640SThomas Richard cmd_data = CGBC_I2C_CMD_DATA | algo_data->bus_id;
2766894f640SThomas Richard ret = cgbc_command(cgbc, &cmd_data, sizeof(cmd_data),
2776894f640SThomas Richard msg->buf + i2c->pos, len, NULL);
2786894f640SThomas Richard if (ret)
2796894f640SThomas Richard goto err;
2806894f640SThomas Richard }
2816894f640SThomas Richard
2826894f640SThomas Richard if (len == (msg->len - i2c->pos)) {
2836894f640SThomas Richard i2c->msg++;
2846894f640SThomas Richard i2c->nmsgs--;
2856894f640SThomas Richard i2c->pos = 0;
2866894f640SThomas Richard } else {
2876894f640SThomas Richard i2c->pos += len;
2886894f640SThomas Richard }
2896894f640SThomas Richard
2906894f640SThomas Richard if (i2c->nmsgs == 0)
2916894f640SThomas Richard i2c->state = CGBC_I2C_STATE_DONE;
2926894f640SThomas Richard
2936894f640SThomas Richard return 0;
2946894f640SThomas Richard
2956894f640SThomas Richard err:
2966894f640SThomas Richard i2c->state = CGBC_I2C_STATE_ERROR;
2976894f640SThomas Richard return ret;
2986894f640SThomas Richard }
2996894f640SThomas Richard
cgbc_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)3006894f640SThomas Richard static int cgbc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
3016894f640SThomas Richard int num)
3026894f640SThomas Richard {
3036894f640SThomas Richard struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
3046894f640SThomas Richard unsigned long timeout = jiffies + HZ;
3056894f640SThomas Richard int ret;
3066894f640SThomas Richard
3076894f640SThomas Richard i2c->state = CGBC_I2C_STATE_INIT;
3086894f640SThomas Richard i2c->msg = msgs;
3096894f640SThomas Richard i2c->nmsgs = num;
3106894f640SThomas Richard i2c->pos = 0;
3116894f640SThomas Richard
3126894f640SThomas Richard while (time_before(jiffies, timeout)) {
3136894f640SThomas Richard ret = cgbc_i2c_xfer_msg(adap);
3146894f640SThomas Richard if (i2c->state == CGBC_I2C_STATE_DONE)
3156894f640SThomas Richard return num;
3166894f640SThomas Richard
3176894f640SThomas Richard if (i2c->state == CGBC_I2C_STATE_ERROR)
3186894f640SThomas Richard return ret;
3196894f640SThomas Richard
3206894f640SThomas Richard if (ret == 0)
3216894f640SThomas Richard timeout = jiffies + HZ;
3226894f640SThomas Richard }
3236894f640SThomas Richard
3246894f640SThomas Richard i2c->state = CGBC_I2C_STATE_ERROR;
3256894f640SThomas Richard return -ETIMEDOUT;
3266894f640SThomas Richard }
3276894f640SThomas Richard
cgbc_i2c_func(struct i2c_adapter * adap)3286894f640SThomas Richard static u32 cgbc_i2c_func(struct i2c_adapter *adap)
3296894f640SThomas Richard {
3306894f640SThomas Richard return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~(I2C_FUNC_SMBUS_QUICK));
3316894f640SThomas Richard }
3326894f640SThomas Richard
3336894f640SThomas Richard static const struct i2c_algorithm cgbc_i2c_algorithm = {
3346894f640SThomas Richard .master_xfer = cgbc_i2c_xfer,
3356894f640SThomas Richard .functionality = cgbc_i2c_func,
3366894f640SThomas Richard };
3376894f640SThomas Richard
3386894f640SThomas Richard static struct i2c_algo_cgbc_data cgbc_i2c_algo_data[] = {
3396894f640SThomas Richard { .bus_id = CGBC_I2C_PRIMARY_BUS_ID },
3406894f640SThomas Richard { .bus_id = CGBC_I2C_PM_BUS_ID },
3416894f640SThomas Richard };
3426894f640SThomas Richard
3436894f640SThomas Richard static const struct i2c_adapter cgbc_i2c_adapter[] = {
3446894f640SThomas Richard {
3456894f640SThomas Richard .owner = THIS_MODULE,
3466894f640SThomas Richard .name = "Congatec General Purpose I2C adapter",
3476894f640SThomas Richard .class = I2C_CLASS_DEPRECATED,
3486894f640SThomas Richard .algo = &cgbc_i2c_algorithm,
3496894f640SThomas Richard .algo_data = &cgbc_i2c_algo_data[0],
3506894f640SThomas Richard .nr = -1,
3516894f640SThomas Richard },
3526894f640SThomas Richard {
3536894f640SThomas Richard .owner = THIS_MODULE,
3546894f640SThomas Richard .name = "Congatec Power Management I2C adapter",
3556894f640SThomas Richard .class = I2C_CLASS_DEPRECATED,
3566894f640SThomas Richard .algo = &cgbc_i2c_algorithm,
3576894f640SThomas Richard .algo_data = &cgbc_i2c_algo_data[1],
3586894f640SThomas Richard .nr = -1,
3596894f640SThomas Richard },
3606894f640SThomas Richard };
3616894f640SThomas Richard
cgbc_i2c_probe(struct platform_device * pdev)3626894f640SThomas Richard static int cgbc_i2c_probe(struct platform_device *pdev)
3636894f640SThomas Richard {
3646894f640SThomas Richard struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent);
3656894f640SThomas Richard struct cgbc_i2c_data *i2c;
3666894f640SThomas Richard int ret;
3676894f640SThomas Richard
3686894f640SThomas Richard i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
3696894f640SThomas Richard if (!i2c)
3706894f640SThomas Richard return -ENOMEM;
3716894f640SThomas Richard
3726894f640SThomas Richard i2c->cgbc = cgbc;
3736894f640SThomas Richard i2c->dev = &pdev->dev;
3746894f640SThomas Richard i2c->adap = cgbc_i2c_adapter[pdev->id];
3756894f640SThomas Richard i2c->adap.dev.parent = i2c->dev;
3766894f640SThomas Richard i2c_set_adapdata(&i2c->adap, i2c);
3776894f640SThomas Richard platform_set_drvdata(pdev, i2c);
3786894f640SThomas Richard
3796894f640SThomas Richard ret = cgbc_i2c_set_frequency(&i2c->adap, I2C_MAX_STANDARD_MODE_FREQ);
3806894f640SThomas Richard if (ret)
3816894f640SThomas Richard return ret;
3826894f640SThomas Richard
3836894f640SThomas Richard return i2c_add_numbered_adapter(&i2c->adap);
3846894f640SThomas Richard }
3856894f640SThomas Richard
cgbc_i2c_remove(struct platform_device * pdev)3866894f640SThomas Richard static void cgbc_i2c_remove(struct platform_device *pdev)
3876894f640SThomas Richard {
3886894f640SThomas Richard struct cgbc_i2c_data *i2c = platform_get_drvdata(pdev);
3896894f640SThomas Richard
3906894f640SThomas Richard i2c_del_adapter(&i2c->adap);
3916894f640SThomas Richard }
3926894f640SThomas Richard
3936894f640SThomas Richard static struct platform_driver cgbc_i2c_driver = {
3946894f640SThomas Richard .driver = {
3956894f640SThomas Richard .name = "cgbc-i2c",
3966894f640SThomas Richard },
3976894f640SThomas Richard .probe = cgbc_i2c_probe,
398*e70140baSLinus Torvalds .remove = cgbc_i2c_remove,
3996894f640SThomas Richard };
4006894f640SThomas Richard
4016894f640SThomas Richard module_platform_driver(cgbc_i2c_driver);
4026894f640SThomas Richard
4036894f640SThomas Richard MODULE_DESCRIPTION("Congatec Board Controller I2C Driver");
4046894f640SThomas Richard MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
4056894f640SThomas Richard MODULE_LICENSE("GPL");
4066894f640SThomas Richard MODULE_ALIAS("platform:cgbc_i2c");
407