Commit 00d93611 authored by Corey Minyard's avatar Corey Minyard Committed by Corey Minyard

ipmi:ipmb: Add the ability to have a separate slave and master device

A situation has come up where there is a slave-only device for the slave
and a separate master device on the same bug.  Allow a separate slave
device to be registered.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
parent 57c9e3c9
......@@ -36,6 +36,14 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of retries before a failure is declared. Defaults to 1.
slave-dev:
$ref: /schemas/types.yaml#/definitions/phandle
description: |
The slave i2c device. If not present, the main device is used. This
lets you use two devices on the IPMB, one for master and one for slave,
in case you have a slave device that can only be a slave. The slave
will receive messages and the master will transmit.
required:
- compatible
- reg
......
......@@ -39,6 +39,7 @@ MODULE_PARM_DESC(max_retries, "Max resends of a command before timing out.");
struct ipmi_ipmb_dev {
struct ipmi_smi *intf;
struct i2c_client *client;
struct i2c_client *slave;
struct ipmi_smi_handlers handlers;
......@@ -257,7 +258,7 @@ static void ipmi_ipmb_format_for_xmit(struct ipmi_ipmb_dev *iidev,
memcpy(iidev->xmitmsg + 5, msg->data + 1, msg->data_size - 1);
iidev->xmitlen = msg->data_size + 4;
}
iidev->xmitmsg[3] = iidev->client->addr << 1;
iidev->xmitmsg[3] = iidev->slave->addr << 1;
if (((msg->data[0] >> 2) & 1) == 0)
/* If it's a command, put in our own sequence number. */
iidev->xmitmsg[4] = ((iidev->xmitmsg[4] & 0x03) |
......@@ -427,10 +428,13 @@ static int ipmi_ipmb_remove(struct i2c_client *client)
{
struct ipmi_ipmb_dev *iidev = i2c_get_clientdata(client);
if (iidev->client) {
iidev->client = NULL;
i2c_slave_unregister(client);
if (iidev->slave) {
i2c_slave_unregister(iidev->slave);
if (iidev->slave != iidev->client)
i2c_unregister_device(iidev->slave);
}
iidev->slave = NULL;
iidev->client = NULL;
ipmi_ipmb_stop_thread(iidev);
ipmi_unregister_smi(iidev->intf);
......@@ -443,6 +447,9 @@ static int ipmi_ipmb_probe(struct i2c_client *client,
{
struct device *dev = &client->dev;
struct ipmi_ipmb_dev *iidev;
struct device_node *slave_np;
struct i2c_adapter *slave_adap = NULL;
struct i2c_client *slave = NULL;
int rv;
iidev = devm_kzalloc(&client->dev, sizeof(*iidev), GFP_KERNEL);
......@@ -466,14 +473,45 @@ static int ipmi_ipmb_probe(struct i2c_client *client,
&iidev->max_retries) != 0)
iidev->max_retries = max_retries;
slave_np = of_parse_phandle(dev->of_node, "slave-dev", 0);
if (slave_np) {
slave_adap = of_get_i2c_adapter_by_node(slave_np);
if (!slave_adap) {
dev_notice(&client->dev,
"Could not find slave adapter\n");
return -EINVAL;
}
}
iidev->client = client;
if (slave_adap) {
struct i2c_board_info binfo;
memset(&binfo, 0, sizeof(binfo));
strscpy(binfo.type, "ipmb-slave", I2C_NAME_SIZE);
binfo.addr = client->addr;
binfo.flags = I2C_CLIENT_SLAVE;
slave = i2c_new_client_device(slave_adap, &binfo);
i2c_put_adapter(slave_adap);
if (IS_ERR(slave)) {
rv = PTR_ERR(slave);
dev_notice(&client->dev,
"Could not allocate slave device: %d\n", rv);
return rv;
}
i2c_set_clientdata(slave, iidev);
} else {
slave = client;
}
i2c_set_clientdata(client, iidev);
client->flags |= I2C_CLIENT_SLAVE;
slave->flags |= I2C_CLIENT_SLAVE;
rv = i2c_slave_register(client, ipmi_ipmb_slave_cb);
rv = i2c_slave_register(slave, ipmi_ipmb_slave_cb);
if (rv)
return rv;
iidev->client = client;
goto out_err;
iidev->slave = slave;
slave = NULL;
iidev->handlers.flags = IPMI_SMI_CAN_HANDLE_IPMB_DIRECT;
iidev->handlers.start_processing = ipmi_ipmb_start_processing;
......@@ -504,6 +542,8 @@ static int ipmi_ipmb_probe(struct i2c_client *client,
return 0;
out_err:
if (slave && slave != client)
i2c_unregister_device(slave);
ipmi_ipmb_remove(client);
return rv;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment