Pull i2c updates from Wolfram Sang: - 'remove' callback converted to return void. Big change with trivial fixes all over the tree. Other subsystems depending on this change have been asked to pull an immutable topic branch for this. - new driver for Microchip PCI1xxxx switch - heavy refactoring of the Mellanox BlueField driver - we prefer async probe in the i801 driver now - the rest is usual driver updates (support for more SoCs, some refactoring, some feature additions) * tag 'i2c-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (37 commits) i2c: pci1xxxx: prevent signed integer overflow i2c: acpi: Replace zero-length array with DECLARE_FLEX_ARRAY() helper i2c: i801: Prefer async probe i2c: designware-pci: Use standard pattern for memory allocation i2c: designware-pci: Group AMD NAVI quirk parts together i2c: microchip: pci1xxxx: Add driver for I2C host controller in multifunction endpoint of pci1xxxx switch docs: i2c: slave-interface: return errno when handle I2C_SLAVE_WRITE_REQUESTED i2c: mlxbf: remove device tree support i2c: mlxbf: support BlueField-3 SoC i2c: cadence: Add standard bus recovery support i2c: mlxbf: add multi slave functionality i2c: mlxbf: support lock mechanism macintosh/ams: Adapt declaration of ams_i2c_remove() to earlier change i2c: riic: Use devm_platform_ioremap_resource() i2c: mlxbf: remove IRQF_ONESHOT dt-bindings: i2c: rockchip: add rockchip,rk3128-i2c dt-bindings: i2c: renesas,rcar-i2c: Add r8a779g0 support i2c: tegra: Add GPCDMA support i2c: scmi: Convert to be a platform driver i2c: rk3x: Add rv1126 support ...
162 lines
3.6 KiB
C
162 lines
3.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2020 NovaTech LLC
|
|
* George McCollister <george.mccollister@gmail.com>
|
|
*/
|
|
|
|
#include <linux/bits.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/module.h>
|
|
#include "xrs700x.h"
|
|
#include "xrs700x_reg.h"
|
|
|
|
struct xrs700x_i2c_cmd {
|
|
__be32 reg;
|
|
__be16 val;
|
|
} __packed;
|
|
|
|
static int xrs700x_i2c_reg_read(void *context, unsigned int reg,
|
|
unsigned int *val)
|
|
{
|
|
struct device *dev = context;
|
|
struct i2c_client *i2c = to_i2c_client(dev);
|
|
struct xrs700x_i2c_cmd cmd;
|
|
int ret;
|
|
|
|
cmd.reg = cpu_to_be32(reg | 1);
|
|
|
|
ret = i2c_master_send(i2c, (char *)&cmd.reg, sizeof(cmd.reg));
|
|
if (ret < 0) {
|
|
dev_err(dev, "xrs i2c_master_send returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = i2c_master_recv(i2c, (char *)&cmd.val, sizeof(cmd.val));
|
|
if (ret < 0) {
|
|
dev_err(dev, "xrs i2c_master_recv returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
*val = be16_to_cpu(cmd.val);
|
|
return 0;
|
|
}
|
|
|
|
static int xrs700x_i2c_reg_write(void *context, unsigned int reg,
|
|
unsigned int val)
|
|
{
|
|
struct device *dev = context;
|
|
struct i2c_client *i2c = to_i2c_client(dev);
|
|
struct xrs700x_i2c_cmd cmd;
|
|
int ret;
|
|
|
|
cmd.reg = cpu_to_be32(reg);
|
|
cmd.val = cpu_to_be16(val);
|
|
|
|
ret = i2c_master_send(i2c, (char *)&cmd, sizeof(cmd));
|
|
if (ret < 0) {
|
|
dev_err(dev, "xrs i2c_master_send returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct regmap_config xrs700x_i2c_regmap_config = {
|
|
.val_bits = 16,
|
|
.reg_stride = 2,
|
|
.reg_bits = 32,
|
|
.pad_bits = 0,
|
|
.write_flag_mask = 0,
|
|
.read_flag_mask = 0,
|
|
.reg_read = xrs700x_i2c_reg_read,
|
|
.reg_write = xrs700x_i2c_reg_write,
|
|
.max_register = 0,
|
|
.cache_type = REGCACHE_NONE,
|
|
.reg_format_endian = REGMAP_ENDIAN_BIG,
|
|
.val_format_endian = REGMAP_ENDIAN_BIG
|
|
};
|
|
|
|
static int xrs700x_i2c_probe(struct i2c_client *i2c,
|
|
const struct i2c_device_id *i2c_id)
|
|
{
|
|
struct xrs700x *priv;
|
|
int ret;
|
|
|
|
priv = xrs700x_switch_alloc(&i2c->dev, i2c);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
priv->regmap = devm_regmap_init(&i2c->dev, NULL, &i2c->dev,
|
|
&xrs700x_i2c_regmap_config);
|
|
if (IS_ERR(priv->regmap)) {
|
|
ret = PTR_ERR(priv->regmap);
|
|
dev_err(&i2c->dev, "Failed to initialize regmap: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
i2c_set_clientdata(i2c, priv);
|
|
|
|
ret = xrs700x_switch_register(priv);
|
|
|
|
/* Main DSA driver may not be started yet. */
|
|
if (ret)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void xrs700x_i2c_remove(struct i2c_client *i2c)
|
|
{
|
|
struct xrs700x *priv = i2c_get_clientdata(i2c);
|
|
|
|
if (!priv)
|
|
return;
|
|
|
|
xrs700x_switch_remove(priv);
|
|
}
|
|
|
|
static void xrs700x_i2c_shutdown(struct i2c_client *i2c)
|
|
{
|
|
struct xrs700x *priv = i2c_get_clientdata(i2c);
|
|
|
|
if (!priv)
|
|
return;
|
|
|
|
xrs700x_switch_shutdown(priv);
|
|
|
|
i2c_set_clientdata(i2c, NULL);
|
|
}
|
|
|
|
static const struct i2c_device_id xrs700x_i2c_id[] = {
|
|
{ "xrs700x-switch", 0 },
|
|
{},
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id);
|
|
|
|
static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = {
|
|
{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
|
|
{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
|
|
{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
|
|
{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids);
|
|
|
|
static struct i2c_driver xrs700x_i2c_driver = {
|
|
.driver = {
|
|
.name = "xrs700x-i2c",
|
|
.of_match_table = of_match_ptr(xrs700x_i2c_dt_ids),
|
|
},
|
|
.probe = xrs700x_i2c_probe,
|
|
.remove = xrs700x_i2c_remove,
|
|
.shutdown = xrs700x_i2c_shutdown,
|
|
.id_table = xrs700x_i2c_id,
|
|
};
|
|
|
|
module_i2c_driver(xrs700x_i2c_driver);
|
|
|
|
MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
|
|
MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver");
|
|
MODULE_LICENSE("GPL v2");
|