cregit-Linux how code gets into the kernel

Release 4.7 drivers/i2c/busses/i2c-opal.c

/*
 * 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/device.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include <asm/firmware.h>
#include <asm/opal.h>


static int i2c_opal_translate_error(int rc) { switch (rc) { case OPAL_NO_MEM: return -ENOMEM; case OPAL_PARAMETER: return -EINVAL; case OPAL_I2C_ARBT_LOST: return -EAGAIN; case OPAL_I2C_TIMEOUT: return -ETIMEDOUT; case OPAL_I2C_NACK_RCVD: return -ENXIO; case OPAL_I2C_STOP_ERR: return -EBUSY; default: return -EIO; } }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta62100.00%1100.00%
Total62100.00%1100.00%


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 = i2c_opal_translate_error(rc); goto exit; } rc = opal_async_wait_response(token, &msg); if (rc) goto exit; rc = be64_to_cpu(msg.params[1]); if (rc != OPAL_SUCCESS) { rc = i2c_opal_translate_error(rc); goto exit; } exit: opal_async_release_token(token); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta137100.00%1100.00%
Total137100.00%1100.00%


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 */ 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: req.type = (msgs[1].flags & I2C_M_RD) ? OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; 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 -EOPNOTSUPP; } rc = i2c_opal_send_request(opal_id, &req); if (rc) return rc; return num; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta289100.00%2100.00%
Total289100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta396100.00%1100.00%
Total396100.00%1100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta24100.00%1100.00%
Total24100.00%1100.00%

static const struct i2c_algorithm i2c_opal_algo = { .master_xfer = i2c_opal_master_xfer, .smbus_xfer = i2c_opal_smbus_xfer, .functionality = i2c_opal_func, }; /* * For two messages, we basically support simple smbus transactions of a * write-then-anything. */ static struct i2c_adapter_quirks i2c_opal_quirks = { .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR, .max_comb_1st_msg_len = 4, };
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; 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 = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL); if (!adapter) return -ENOMEM; adapter->algo = &i2c_opal_algo; adapter->algo_data = (void *)(unsigned long)opal_id; adapter->quirks = &i2c_opal_quirks; adapter->dev.parent = &pdev->dev; adapter->dev.of_node = of_node_get(pdev->dev.of_node); pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL); 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"); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta23397.08%150.00%
wolfram sangwolfram sang72.92%150.00%
Total240100.00%2100.00%


static int i2c_opal_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); i2c_del_adapter(adapter); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta29100.00%1100.00%
Total29100.00%1100.00%

static const struct of_device_id i2c_opal_of_match[] = { { .compatible = "ibm,opal-i2c", }, { } }; 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", .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); }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta28100.00%1100.00%
Total28100.00%1100.00%

module_init(i2c_opal_init);
static void __exit i2c_opal_exit(void) { return platform_driver_unregister(&i2c_opal_driver); }

Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta16100.00%1100.00%
Total16100.00%1100.00%

module_exit(i2c_opal_exit); MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>"); MODULE_DESCRIPTION("IBM OPAL I2C driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
neelesh guptaneelesh gupta135698.33%266.67%
wolfram sangwolfram sang231.67%133.33%
Total1379100.00%3100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}