11539Srgrimes// SPDX-License-Identifier: GPL-2.0-or-later 21539Srgrimes/* 31539Srgrimes * IBM OPAL I2C driver 41539Srgrimes * Copyright (C) 2014 IBM 51539Srgrimes */ 61539Srgrimes 71539Srgrimes#include <linux/device.h> 81539Srgrimes#include <linux/i2c.h> 91539Srgrimes#include <linux/kernel.h> 101539Srgrimes#include <linux/mm.h> 111539Srgrimes#include <linux/module.h> 121539Srgrimes#include <linux/of.h> 131539Srgrimes#include <linux/platform_device.h> 141539Srgrimes#include <linux/slab.h> 151539Srgrimes 161539Srgrimes#include <asm/firmware.h> 171539Srgrimes#include <asm/opal.h> 181539Srgrimes 191539Srgrimesstatic int i2c_opal_translate_error(int rc) 201539Srgrimes{ 211539Srgrimes switch (rc) { 221539Srgrimes case OPAL_NO_MEM: 231539Srgrimes return -ENOMEM; 241539Srgrimes case OPAL_PARAMETER: 251539Srgrimes return -EINVAL; 261539Srgrimes case OPAL_I2C_ARBT_LOST: 271539Srgrimes return -EAGAIN; 281539Srgrimes case OPAL_I2C_TIMEOUT: 291539Srgrimes return -ETIMEDOUT; 301539Srgrimes case OPAL_I2C_NACK_RCVD: 311539Srgrimes return -ENXIO; 321539Srgrimes case OPAL_I2C_STOP_ERR: 331539Srgrimes return -EBUSY; 341539Srgrimes default: 351539Srgrimes return -EIO; 361539Srgrimes } 3719211Swosch} 381539Srgrimes 391539Srgrimesstatic int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req) 401539Srgrimes{ 411539Srgrimes struct opal_msg msg; 421539Srgrimes int token, rc; 431539Srgrimes 441539Srgrimes token = opal_async_get_token_interruptible(); 451539Srgrimes if (token < 0) { 461539Srgrimes if (token != -ERESTARTSYS) 471539Srgrimes pr_err("Failed to get the async token\n"); 481539Srgrimes 491539Srgrimes return token; 501539Srgrimes } 511539Srgrimes 521539Srgrimes rc = opal_i2c_request(token, bus_id, req); 531539Srgrimes if (rc != OPAL_ASYNC_COMPLETION) { 541539Srgrimes rc = i2c_opal_translate_error(rc); 551539Srgrimes goto exit; 561539Srgrimes } 571539Srgrimes 581539Srgrimes rc = opal_async_wait_response(token, &msg); 591539Srgrimes if (rc) 601539Srgrimes goto exit; 611539Srgrimes 621539Srgrimes rc = opal_get_async_rc(msg); 631539Srgrimes if (rc != OPAL_SUCCESS) { 641539Srgrimes rc = i2c_opal_translate_error(rc); 651539Srgrimes goto exit; 661539Srgrimes } 671539Srgrimes 681539Srgrimesexit: 691539Srgrimes opal_async_release_token(token); 701539Srgrimes return rc; 711539Srgrimes} 721539Srgrimes 731539Srgrimesstatic int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 741539Srgrimes int num) 751539Srgrimes{ 761539Srgrimes unsigned long opal_id = (unsigned long)adap->algo_data; 771539Srgrimes struct opal_i2c_request req; 781539Srgrimes int rc, i; 791539Srgrimes 801539Srgrimes /* We only support fairly simple combinations here of one 811539Srgrimes * or two messages 821539Srgrimes */ 831539Srgrimes memset(&req, 0, sizeof(req)); 841539Srgrimes switch(num) { 851539Srgrimes case 1: 861539Srgrimes req.type = (msgs[0].flags & I2C_M_RD) ? 871539Srgrimes OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; 881539Srgrimes req.addr = cpu_to_be16(msgs[0].addr); 891539Srgrimes req.size = cpu_to_be32(msgs[0].len); 901539Srgrimes req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf)); 911539Srgrimes break; 921539Srgrimes case 2: 931539Srgrimes req.type = (msgs[1].flags & I2C_M_RD) ? 941539Srgrimes OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; 951539Srgrimes req.addr = cpu_to_be16(msgs[0].addr); 961539Srgrimes req.subaddr_sz = msgs[0].len; 971539Srgrimes for (i = 0; i < msgs[0].len; i++) 981539Srgrimes req.subaddr = (req.subaddr << 8) | msgs[0].buf[i]; 991539Srgrimes req.subaddr = cpu_to_be32(req.subaddr); 1001539Srgrimes req.size = cpu_to_be32(msgs[1].len); 1011539Srgrimes req.buffer_ra = cpu_to_be64(__pa(msgs[1].buf)); 1021539Srgrimes break; 1031539Srgrimes } 1041539Srgrimes 1051539Srgrimes rc = i2c_opal_send_request(opal_id, &req); 1061539Srgrimes if (rc) 1071539Srgrimes return rc; 1081539Srgrimes 1091539Srgrimes return num; 1101539Srgrimes} 1111539Srgrimes 1121539Srgrimesstatic int i2c_opal_smbus_xfer(struct i2c_adapter *adap, u16 addr, 1131539Srgrimes unsigned short flags, char read_write, 1141539Srgrimes u8 command, int size, union i2c_smbus_data *data) 1151539Srgrimes{ 1161539Srgrimes unsigned long opal_id = (unsigned long)adap->algo_data; 1171539Srgrimes struct opal_i2c_request req; 1181539Srgrimes u8 local[2]; 1191539Srgrimes int rc; 1201539Srgrimes 1211539Srgrimes memset(&req, 0, sizeof(req)); 1221539Srgrimes 1231539Srgrimes req.addr = cpu_to_be16(addr); 1241539Srgrimes switch (size) { 1251539Srgrimes case I2C_SMBUS_BYTE: 1261539Srgrimes req.buffer_ra = cpu_to_be64(__pa(&data->byte)); 1271539Srgrimes req.size = cpu_to_be32(1); 1281539Srgrimes fallthrough; 1291539Srgrimes case I2C_SMBUS_QUICK: 1301539Srgrimes req.type = (read_write == I2C_SMBUS_READ) ? 1311539Srgrimes OPAL_I2C_RAW_READ : OPAL_I2C_RAW_WRITE; 1321539Srgrimes break; 1331539Srgrimes case I2C_SMBUS_BYTE_DATA: 1341539Srgrimes req.buffer_ra = cpu_to_be64(__pa(&data->byte)); 1351539Srgrimes req.size = cpu_to_be32(1); 1361539Srgrimes req.subaddr = cpu_to_be32(command); 1371539Srgrimes req.subaddr_sz = 1; 1381539Srgrimes req.type = (read_write == I2C_SMBUS_READ) ? 1391539Srgrimes OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; 1401539Srgrimes break; 1411539Srgrimes case I2C_SMBUS_WORD_DATA: 1421539Srgrimes if (!read_write) { 1431539Srgrimes local[0] = data->word & 0xff; 1441539Srgrimes local[1] = (data->word >> 8) & 0xff; 1451539Srgrimes } 1461539Srgrimes req.buffer_ra = cpu_to_be64(__pa(local)); 1471539Srgrimes req.size = cpu_to_be32(2); 1481539Srgrimes req.subaddr = cpu_to_be32(command); 1491539Srgrimes req.subaddr_sz = 1; 1501539Srgrimes req.type = (read_write == I2C_SMBUS_READ) ? 1511539Srgrimes OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; 1521539Srgrimes break; 1531539Srgrimes case I2C_SMBUS_I2C_BLOCK_DATA: 1541539Srgrimes req.buffer_ra = cpu_to_be64(__pa(&data->block[1])); 1551539Srgrimes req.size = cpu_to_be32(data->block[0]); 1561539Srgrimes req.subaddr = cpu_to_be32(command); 1571539Srgrimes req.subaddr_sz = 1; 1581539Srgrimes req.type = (read_write == I2C_SMBUS_READ) ? 1591539Srgrimes OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE; 1601539Srgrimes break; 1611539Srgrimes default: 1621539Srgrimes return -EINVAL; 1631539Srgrimes } 1641539Srgrimes 1651539Srgrimes rc = i2c_opal_send_request(opal_id, &req); 16613771Smpp if (!rc && read_write && size == I2C_SMBUS_WORD_DATA) { 16713771Smpp data->word = ((u16)local[1]) << 8; 1681539Srgrimes data->word |= local[0]; 1691539Srgrimes } 1701539Srgrimes 1711539Srgrimes return rc; 1721539Srgrimes} 1731539Srgrimes 1741539Srgrimesstatic u32 i2c_opal_func(struct i2c_adapter *adapter) 1751539Srgrimes{ 1761539Srgrimes return I2C_FUNC_I2C | I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 1771539Srgrimes I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 1781539Srgrimes I2C_FUNC_SMBUS_I2C_BLOCK; 1791539Srgrimes} 1801539Srgrimes 1811539Srgrimesstatic const struct i2c_algorithm i2c_opal_algo = { 1821539Srgrimes .master_xfer = i2c_opal_master_xfer, 1831539Srgrimes .smbus_xfer = i2c_opal_smbus_xfer, 1841539Srgrimes .functionality = i2c_opal_func, 1851539Srgrimes}; 1861539Srgrimes 1871539Srgrimes/* 1881539Srgrimes * For two messages, we basically support simple smbus transactions of a 1891539Srgrimes * write-then-anything. 1901539Srgrimes */ 1911539Srgrimesstatic const struct i2c_adapter_quirks i2c_opal_quirks = { 1921539Srgrimes .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR, 1931539Srgrimes .max_comb_1st_msg_len = 4, 1941539Srgrimes}; 1951539Srgrimes 1961539Srgrimesstatic int i2c_opal_probe(struct platform_device *pdev) 1971539Srgrimes{ 1981539Srgrimes struct i2c_adapter *adapter; 1991539Srgrimes const char *pname; 2001539Srgrimes u32 opal_id; 2011539Srgrimes int rc; 2021539Srgrimes 2031539Srgrimes if (!pdev->dev.of_node) 2041539Srgrimes return -ENODEV; 2051539Srgrimes 2061539Srgrimes rc = of_property_read_u32(pdev->dev.of_node, "ibm,opal-id", &opal_id); 2071539Srgrimes if (rc) { 2081539Srgrimes dev_err(&pdev->dev, "Missing ibm,opal-id property !\n"); 2091539Srgrimes return -EIO; 2101539Srgrimes } 2111539Srgrimes 2121539Srgrimes adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL); 2131539Srgrimes if (!adapter) 2141539Srgrimes return -ENOMEM; 2151539Srgrimes 2161539Srgrimes adapter->algo = &i2c_opal_algo; 2171539Srgrimes adapter->algo_data = (void *)(unsigned long)opal_id; 2181539Srgrimes adapter->quirks = &i2c_opal_quirks; 2191539Srgrimes adapter->dev.parent = &pdev->dev; 2201539Srgrimes adapter->dev.of_node = of_node_get(pdev->dev.of_node); 2211539Srgrimes pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL); 2221539Srgrimes if (pname) 2231539Srgrimes strscpy(adapter->name, pname, sizeof(adapter->name)); 2241539Srgrimes else 2251539Srgrimes strscpy(adapter->name, "opal", sizeof(adapter->name)); 2261539Srgrimes 2271539Srgrimes platform_set_drvdata(pdev, adapter); 22814791Spaul rc = i2c_add_adapter(adapter); 2291539Srgrimes if (rc) 2301539Srgrimes dev_err(&pdev->dev, "Failed to register the i2c adapter\n"); 2311539Srgrimes 2321539Srgrimes return rc; 2331539Srgrimes} 2341539Srgrimes 2351539Srgrimesstatic void i2c_opal_remove(struct platform_device *pdev) 2361539Srgrimes{ 2371539Srgrimes struct i2c_adapter *adapter = platform_get_drvdata(pdev); 23814791Spaul 2391539Srgrimes i2c_del_adapter(adapter); 2401539Srgrimes} 2411539Srgrimes 2421539Srgrimesstatic const struct of_device_id i2c_opal_of_match[] = { 2431539Srgrimes { 2446895Sphk .compatible = "ibm,opal-i2c", 2451539Srgrimes }, 2461539Srgrimes { } 2471539Srgrimes}; 2481539SrgrimesMODULE_DEVICE_TABLE(of, i2c_opal_of_match); 2491539Srgrimes 2501539Srgrimesstatic struct platform_driver i2c_opal_driver = { 2511539Srgrimes .probe = i2c_opal_probe, 2521539Srgrimes .remove_new = i2c_opal_remove, 2531539Srgrimes .driver = { 2541539Srgrimes .name = "i2c-opal", 2551539Srgrimes .of_match_table = i2c_opal_of_match, 2561539Srgrimes }, 2571539Srgrimes}; 2581539Srgrimes 2591539Srgrimesstatic int __init i2c_opal_init(void) 2601539Srgrimes{ 2611539Srgrimes if (!firmware_has_feature(FW_FEATURE_OPAL)) 2621539Srgrimes return -ENODEV; 2631539Srgrimes 2641539Srgrimes return platform_driver_register(&i2c_opal_driver); 2651539Srgrimes} 2661539Srgrimesmodule_init(i2c_opal_init); 2671539Srgrimes 2681539Srgrimesstatic void __exit i2c_opal_exit(void) 2691539Srgrimes{ 2701539Srgrimes return platform_driver_unregister(&i2c_opal_driver); 2711539Srgrimes} 27219211Swoschmodule_exit(i2c_opal_exit); 27319211Swosch 2741539SrgrimesMODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>"); 27519211SwoschMODULE_DESCRIPTION("IBM OPAL I2C driver"); 27619211SwoschMODULE_LICENSE("GPL"); 2771539Srgrimes