From: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
To: Neelesh Gupta
<neelegup-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
Cc: linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org
Subject: Re: [PATCH] i2c: Driver to expose PowerNV platform i2c busses
Date: Thu, 13 Nov 2014 08:58:17 +0100 [thread overview]
Message-ID: <20141113075817.GA1288@katana> (raw)
In-Reply-To: <20141110060424.9407.2498.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 10526 bytes --]
Hi,
I am basically fine if this goes via the powerpc-tree and I was hoping
that I could ack it right now. However, the driver looks a bit rushed
and definately needs updates before it is ready to go.
On Mon, Nov 10, 2014 at 11:35:39AM +0530, Neelesh Gupta wrote:
> The patch exposes the available i2c busses on the PowerNV platform
> to the kernel and implements the bus driver to support i2c and
> smbus commands.
> The driver uses the platform device infrastructure to probe the busses
> on the platform and registers them with the i2c driver framework.
>
> Signed-off-by: Neelesh Gupta <neelegup-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> Signed-off-by: Benjamin Herrenschmidt <benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
Review for the I2C parts:
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 78d56c5..350aa86 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -102,5 +102,6 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
> obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
> obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
> obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
> +obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
Please sort it properly, not simply at the end.
>
> ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
> diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
> new file mode 100644
> index 0000000..3261716
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-opal.c
> @@ -0,0 +1,276 @@
> +/*
> + * IBM OPAL I2C driver
> + * Copyright (C) 2014 IBM
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/device.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/mm.h>
> +#include <asm/opal.h>
> +#include <asm/firmware.h>
Please sort the includes.
> +
> +static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req)
> +{
> + struct opal_msg msg;
> + int token, rc;
> +
> + token = opal_async_get_token_interruptible();
> + if (token < 0) {
> + if (token != -ERESTARTSYS)
> + pr_err("Failed to get the async token\n");
> +
> + return token;
> + }
> +
> + rc = opal_i2c_request(token, bus_id, req);
> + if (rc != OPAL_ASYNC_COMPLETION) {
> + rc = -EIO;
> + goto exit;
> + }
> +
> + rc = opal_async_wait_response(token, &msg);
> + if (rc) {
> + rc = -EIO;
> + goto exit;
Is it really -EIO? Maybe -ETIMEDOUT?
> + }
> +
> + rc = be64_to_cpu(msg.params[1]);
> + if (rc != OPAL_SUCCESS) {
> + rc = -EIO;
> + goto exit;
> + }
> +
> +exit:
> + opal_async_release_token(token);
> + return rc;
> +}
> +
> +static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
> + int num)
> +{
> + unsigned long opal_id = (unsigned long)adap->algo_data;
> + struct opal_i2c_request req;
> + int rc, i;
> +
> + /* We only support fairly simple combinations here of one
> + * or two messages
> + */
I don't think you should offer I2C_FUNC_I2C with those limitations. Is
there a case you really needs this?
> + memset(&req, 0, sizeof(req));
> + switch (num) {
> + case 0:
> + return 0;
> + case 1:
> + req.type = (msgs[0].flags & I2C_M_RD) ?
> + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
> + req.addr = cpu_to_be16(msgs[0].addr);
> + req.size = cpu_to_be32(msgs[0].len);
> + req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
> + break;
> + case 2:
> + /* For two messages, we basically support only simple
> + * smbus transactions of a write plus a read. We might
> + * want to allow also two writes but we'd have to bounce
> + * the data into a single buffer.
> + */
> + if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
> + return -EIO;
> + if (msgs[0].len > 4)
> + return -EIO;
> + if (msgs[0].addr != msgs[1].addr)
> + return -EIO;
-EOPNOTSUPP? Please check Documentation/i2c/fault-codes for the error
codes we use.
> + req.type = OPAL_I2C_SM_READ;
> + req.addr = cpu_to_be16(msgs[0].addr);
> + req.subaddr_sz = msgs[0].len;
> + for (i = 0; i < msgs[0].len; i++)
> + req.subaddr = (req.subaddr << 8) | msgs[0].buf[i];
> + req.subaddr = cpu_to_be32(req.subaddr);
> + req.size = cpu_to_be32(msgs[1].len);
> + req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
> + break;
> + default:
> + return -EIO;
> + }
> +
> + rc = i2c_opal_send_request(opal_id, &req);
> + if (rc)
> + return rc;
> +
> + return num;
> +}
> +
> +static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
> + unsigned short flags, char read_write,
> + u8 command, int size, union i2c_smbus_data *data)
> +{
> + unsigned long opal_id = (unsigned long)adap->algo_data;
> + struct opal_i2c_request req;
> + u8 local[2];
> + int rc;
> +
> + memset(&req, 0, sizeof(req));
> +
> + req.addr = cpu_to_be16(addr);
> + switch (size) {
> + case I2C_SMBUS_BYTE:
> + req.buffer_ra = cpu_to_be64(__pa(&data->byte));
> + req.size = cpu_to_be32(1);
> + /* Fall through */
> + case I2C_SMBUS_QUICK:
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
> + break;
> + case I2C_SMBUS_BYTE_DATA:
> + req.buffer_ra = cpu_to_be64(__pa(&data->byte));
> + req.size = cpu_to_be32(1);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + case I2C_SMBUS_WORD_DATA:
> + if (!read_write) {
> + local[0] = data->word & 0xff;
> + local[1] = (data->word >> 8) & 0xff;
> + }
> + req.buffer_ra = cpu_to_be64(__pa(local));
> + req.size = cpu_to_be32(2);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + case I2C_SMBUS_I2C_BLOCK_DATA:
> + req.buffer_ra = cpu_to_be64(__pa(&data->block[1]));
> + req.size = cpu_to_be32(data->block[0]);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + rc = i2c_opal_send_request(opal_id, &req);
> + if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) {
> + data->word = ((u16)local[1]) << 8;
> + data->word |= local[0];
> + }
> +
> + return rc;
> +}
> +
> +static u32 i2c_opal_func(struct i2c_adapter *adapter)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
> + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
> + I2C_FUNC_SMBUS_I2C_BLOCK;
> +}
See comment above about I2C_FUNC_I2C?
> +
> +static const struct i2c_algorithm i2c_opal_algo = {
> + .master_xfer = i2c_opal_master_xfer,
> + .smbus_xfer = i2c_opal_smbus_xfer,
> + .functionality = i2c_opal_func,
> +};
> +
> +static int i2c_opal_probe(struct platform_device *pdev)
> +{
> + struct i2c_adapter *adapter;
> + const char *pname;
> + u32 opal_id;
> + int rc;
> +
> + if (!pdev->dev.of_node)
> + return -ENODEV;
Can this happen? How would the match happen otherwise?
> + rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id);
> + if (rc) {
> + dev_err(&pdev->dev, "Missing ibm,opal-id property !\n");
> + return -EIO;
> + }
> + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
devm_kzalloc?
> + if (!adapter)
> + return -ENOMEM;
> + adapter->algo = &i2c_opal_algo;
> + adapter->algo_data = (void *)(unsigned long)opal_id;
double cast?
> + adapter->dev.parent = &pdev->dev;
> + adapter->dev.of_node = of_node_get(pdev->dev.of_node);
> + pname = of_get_property(pdev->dev.of_node, "port-name", NULL);
I have never seen this binding before, it looks fishy. Where is it documented?
> + if (pname)
> + strlcpy(adapter->name, pname, sizeof(adapter->name));
> + else
> + strlcpy(adapter->name, "opal", sizeof(adapter->name));
> +
> + platform_set_drvdata(pdev, adapter);
> + rc = i2c_add_adapter(adapter);
> + if (rc)
> + dev_err(&pdev->dev, "Failed to register the i2c adapter\n");
Leaking 'adapter' here.
> +
> + return rc;
> +}
> +
> +static int i2c_opal_remove(struct platform_device *pdev)
> +{
> + struct i2c_adapter *adapter = platform_get_drvdata(pdev);
> +
> + i2c_del_adapter(adapter);
> +
> + kfree(adapter);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id i2c_opal_of_match[] = {
> + {
> + .compatible = "ibm,power8-i2c-port",
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, i2c_opal_of_match);
> +
> +static struct platform_driver i2c_opal_driver = {
> + .probe = i2c_opal_probe,
> + .remove = i2c_opal_remove,
> + .driver = {
> + .name = "i2c-opal",
> + .owner = THIS_MODULE,
Not needed.
> + .of_match_table = i2c_opal_of_match,
> + },
> +};
> +
> +static int __init i2c_opal_init(void)
> +{
> + if (!firmware_has_feature(FW_FEATURE_OPAL))
> + return -ENODEV;
> +
> + return platform_driver_register(&i2c_opal_driver);
> +}
> +
> +static void __exit i2c_opal_exit(void)
> +{
> + return platform_driver_unregister(&i2c_opal_driver);
> +}
> +
> +MODULE_AUTHOR("Neelesh Gupta <neelegup-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>");
> +MODULE_DESCRIPTION("IBM OPAL I2C driver");
> +MODULE_LICENSE("GPL");
> +
> +module_init(i2c_opal_init);
> +module_exit(i2c_opal_exit);
Please put thos right below the functions it references.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
WARNING: multiple messages have this Message-ID (diff)
From: Wolfram Sang <wsa@the-dreams.de>
To: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Cc: linuxppc-dev@ozlabs.org, linux-i2c@vger.kernel.org
Subject: Re: [PATCH] i2c: Driver to expose PowerNV platform i2c busses
Date: Thu, 13 Nov 2014 08:58:17 +0100 [thread overview]
Message-ID: <20141113075817.GA1288@katana> (raw)
In-Reply-To: <20141110060424.9407.2498.stgit@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 10410 bytes --]
Hi,
I am basically fine if this goes via the powerpc-tree and I was hoping
that I could ack it right now. However, the driver looks a bit rushed
and definately needs updates before it is ready to go.
On Mon, Nov 10, 2014 at 11:35:39AM +0530, Neelesh Gupta wrote:
> The patch exposes the available i2c busses on the PowerNV platform
> to the kernel and implements the bus driver to support i2c and
> smbus commands.
> The driver uses the platform device infrastructure to probe the busses
> on the platform and registers them with the i2c driver framework.
>
> Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Review for the I2C parts:
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 78d56c5..350aa86 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -102,5 +102,6 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
> obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
> obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
> obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
> +obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
Please sort it properly, not simply at the end.
>
> ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
> diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
> new file mode 100644
> index 0000000..3261716
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-opal.c
> @@ -0,0 +1,276 @@
> +/*
> + * IBM OPAL I2C driver
> + * Copyright (C) 2014 IBM
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/device.h>
> +#include <linux/platform_device.h>
> +#include <linux/of.h>
> +#include <linux/mm.h>
> +#include <asm/opal.h>
> +#include <asm/firmware.h>
Please sort the includes.
> +
> +static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req)
> +{
> + struct opal_msg msg;
> + int token, rc;
> +
> + token = opal_async_get_token_interruptible();
> + if (token < 0) {
> + if (token != -ERESTARTSYS)
> + pr_err("Failed to get the async token\n");
> +
> + return token;
> + }
> +
> + rc = opal_i2c_request(token, bus_id, req);
> + if (rc != OPAL_ASYNC_COMPLETION) {
> + rc = -EIO;
> + goto exit;
> + }
> +
> + rc = opal_async_wait_response(token, &msg);
> + if (rc) {
> + rc = -EIO;
> + goto exit;
Is it really -EIO? Maybe -ETIMEDOUT?
> + }
> +
> + rc = be64_to_cpu(msg.params[1]);
> + if (rc != OPAL_SUCCESS) {
> + rc = -EIO;
> + goto exit;
> + }
> +
> +exit:
> + opal_async_release_token(token);
> + return rc;
> +}
> +
> +static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
> + int num)
> +{
> + unsigned long opal_id = (unsigned long)adap->algo_data;
> + struct opal_i2c_request req;
> + int rc, i;
> +
> + /* We only support fairly simple combinations here of one
> + * or two messages
> + */
I don't think you should offer I2C_FUNC_I2C with those limitations. Is
there a case you really needs this?
> + memset(&req, 0, sizeof(req));
> + switch (num) {
> + case 0:
> + return 0;
> + case 1:
> + req.type = (msgs[0].flags & I2C_M_RD) ?
> + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
> + req.addr = cpu_to_be16(msgs[0].addr);
> + req.size = cpu_to_be32(msgs[0].len);
> + req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
> + break;
> + case 2:
> + /* For two messages, we basically support only simple
> + * smbus transactions of a write plus a read. We might
> + * want to allow also two writes but we'd have to bounce
> + * the data into a single buffer.
> + */
> + if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
> + return -EIO;
> + if (msgs[0].len > 4)
> + return -EIO;
> + if (msgs[0].addr != msgs[1].addr)
> + return -EIO;
-EOPNOTSUPP? Please check Documentation/i2c/fault-codes for the error
codes we use.
> + req.type = OPAL_I2C_SM_READ;
> + req.addr = cpu_to_be16(msgs[0].addr);
> + req.subaddr_sz = msgs[0].len;
> + for (i = 0; i < msgs[0].len; i++)
> + req.subaddr = (req.subaddr << 8) | msgs[0].buf[i];
> + req.subaddr = cpu_to_be32(req.subaddr);
> + req.size = cpu_to_be32(msgs[1].len);
> + req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf));
> + break;
> + default:
> + return -EIO;
> + }
> +
> + rc = i2c_opal_send_request(opal_id, &req);
> + if (rc)
> + return rc;
> +
> + return num;
> +}
> +
> +static int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr,
> + unsigned short flags, char read_write,
> + u8 command, int size, union i2c_smbus_data *data)
> +{
> + unsigned long opal_id = (unsigned long)adap->algo_data;
> + struct opal_i2c_request req;
> + u8 local[2];
> + int rc;
> +
> + memset(&req, 0, sizeof(req));
> +
> + req.addr = cpu_to_be16(addr);
> + switch (size) {
> + case I2C_SMBUS_BYTE:
> + req.buffer_ra = cpu_to_be64(__pa(&data->byte));
> + req.size = cpu_to_be32(1);
> + /* Fall through */
> + case I2C_SMBUS_QUICK:
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE;
> + break;
> + case I2C_SMBUS_BYTE_DATA:
> + req.buffer_ra = cpu_to_be64(__pa(&data->byte));
> + req.size = cpu_to_be32(1);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + case I2C_SMBUS_WORD_DATA:
> + if (!read_write) {
> + local[0] = data->word & 0xff;
> + local[1] = (data->word >> 8) & 0xff;
> + }
> + req.buffer_ra = cpu_to_be64(__pa(local));
> + req.size = cpu_to_be32(2);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + case I2C_SMBUS_I2C_BLOCK_DATA:
> + req.buffer_ra = cpu_to_be64(__pa(&data->block[1]));
> + req.size = cpu_to_be32(data->block[0]);
> + req.subaddr = cpu_to_be32(command);
> + req.subaddr_sz = 1;
> + req.type = (read_write == I2C_SMBUS_READ) ?
> + OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + rc = i2c_opal_send_request(opal_id, &req);
> + if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) {
> + data->word = ((u16)local[1]) << 8;
> + data->word |= local[0];
> + }
> +
> + return rc;
> +}
> +
> +static u32 i2c_opal_func(struct i2c_adapter *adapter)
> +{
> + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
> + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
> + I2C_FUNC_SMBUS_I2C_BLOCK;
> +}
See comment above about I2C_FUNC_I2C?
> +
> +static const struct i2c_algorithm i2c_opal_algo = {
> + .master_xfer = i2c_opal_master_xfer,
> + .smbus_xfer = i2c_opal_smbus_xfer,
> + .functionality = i2c_opal_func,
> +};
> +
> +static int i2c_opal_probe(struct platform_device *pdev)
> +{
> + struct i2c_adapter *adapter;
> + const char *pname;
> + u32 opal_id;
> + int rc;
> +
> + if (!pdev->dev.of_node)
> + return -ENODEV;
Can this happen? How would the match happen otherwise?
> + rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id);
> + if (rc) {
> + dev_err(&pdev->dev, "Missing ibm,opal-id property !\n");
> + return -EIO;
> + }
> + adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
devm_kzalloc?
> + if (!adapter)
> + return -ENOMEM;
> + adapter->algo = &i2c_opal_algo;
> + adapter->algo_data = (void *)(unsigned long)opal_id;
double cast?
> + adapter->dev.parent = &pdev->dev;
> + adapter->dev.of_node = of_node_get(pdev->dev.of_node);
> + pname = of_get_property(pdev->dev.of_node, "port-name", NULL);
I have never seen this binding before, it looks fishy. Where is it documented?
> + if (pname)
> + strlcpy(adapter->name, pname, sizeof(adapter->name));
> + else
> + strlcpy(adapter->name, "opal", sizeof(adapter->name));
> +
> + platform_set_drvdata(pdev, adapter);
> + rc = i2c_add_adapter(adapter);
> + if (rc)
> + dev_err(&pdev->dev, "Failed to register the i2c adapter\n");
Leaking 'adapter' here.
> +
> + return rc;
> +}
> +
> +static int i2c_opal_remove(struct platform_device *pdev)
> +{
> + struct i2c_adapter *adapter = platform_get_drvdata(pdev);
> +
> + i2c_del_adapter(adapter);
> +
> + kfree(adapter);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id i2c_opal_of_match[] = {
> + {
> + .compatible = "ibm,power8-i2c-port",
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, i2c_opal_of_match);
> +
> +static struct platform_driver i2c_opal_driver = {
> + .probe = i2c_opal_probe,
> + .remove = i2c_opal_remove,
> + .driver = {
> + .name = "i2c-opal",
> + .owner = THIS_MODULE,
Not needed.
> + .of_match_table = i2c_opal_of_match,
> + },
> +};
> +
> +static int __init i2c_opal_init(void)
> +{
> + if (!firmware_has_feature(FW_FEATURE_OPAL))
> + return -ENODEV;
> +
> + return platform_driver_register(&i2c_opal_driver);
> +}
> +
> +static void __exit i2c_opal_exit(void)
> +{
> + return platform_driver_unregister(&i2c_opal_driver);
> +}
> +
> +MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
> +MODULE_DESCRIPTION("IBM OPAL I2C driver");
> +MODULE_LICENSE("GPL");
> +
> +module_init(i2c_opal_init);
> +module_exit(i2c_opal_exit);
Please put thos right below the functions it references.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
next prev parent reply other threads:[~2014-11-13 7:58 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-10 6:05 [PATCH] i2c: Driver to expose PowerNV platform i2c busses Neelesh Gupta
2014-11-10 6:05 ` Neelesh Gupta
[not found] ` <20141110060424.9407.2498.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2014-11-12 6:07 ` Benjamin Herrenschmidt
2014-11-12 6:07 ` Benjamin Herrenschmidt
[not found] ` <1415772441.5124.39.camel-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
2014-11-13 5:36 ` Michael Ellerman
2014-11-13 5:36 ` Michael Ellerman
2014-11-13 7:58 ` Wolfram Sang [this message]
2014-11-13 7:58 ` Wolfram Sang
2014-11-13 10:56 ` Benjamin Herrenschmidt
2014-11-13 10:56 ` Benjamin Herrenschmidt
2014-11-13 12:40 ` Benjamin Herrenschmidt
2014-11-13 12:40 ` Benjamin Herrenschmidt
[not found] ` <1415882455.666.4.camel-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
2014-11-13 18:08 ` Neelesh Gupta
2014-11-13 18:08 ` Neelesh Gupta
[not found] ` <1415876169.666.2.camel-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
2014-11-13 13:10 ` Wolfram Sang
2014-11-13 13:10 ` Wolfram Sang
2014-11-13 20:53 ` Benjamin Herrenschmidt
2014-11-13 20:53 ` Benjamin Herrenschmidt
[not found] ` <1415912020.666.17.camel-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
2014-11-14 5:17 ` Benjamin Herrenschmidt
2014-11-14 5:17 ` Benjamin Herrenschmidt
2014-11-14 16:10 ` Neelesh Gupta
2014-11-14 16:10 ` Neelesh Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20141113075817.GA1288@katana \
--to=wsa-z923lk4zbo2bacvfa/9k2g@public.gmane.org \
--cc=benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linuxppc-dev-mnsaURCQ41sdnm+yROfE0A@public.gmane.org \
--cc=neelegup-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.