1 // SPDX-License-Identifier: GPL-2.0+ 2 // Copyright IBM Corp 2019 3 4 #include <linux/device.h> 5 #include <linux/errno.h> 6 #include <linux/fsi-occ.h> 7 #include <linux/module.h> 8 #include <linux/platform_device.h> 9 10 #include "common.h" 11 12 struct p9_sbe_occ { 13 struct occ occ; 14 struct device *sbe; 15 }; 16 17 #define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ) 18 19 static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd) 20 { 21 struct occ_response *resp = &occ->resp; 22 struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ); 23 size_t resp_len = sizeof(*resp); 24 int rc; 25 26 rc = fsi_occ_submit(ctx->sbe, cmd, 8, resp, &resp_len); 27 if (rc < 0) 28 return rc; 29 30 switch (resp->return_status) { 31 case OCC_RESP_CMD_IN_PRG: 32 rc = -ETIMEDOUT; 33 break; 34 case OCC_RESP_SUCCESS: 35 rc = 0; 36 break; 37 case OCC_RESP_CMD_INVAL: 38 case OCC_RESP_CMD_LEN_INVAL: 39 case OCC_RESP_DATA_INVAL: 40 case OCC_RESP_CHKSUM_ERR: 41 rc = -EINVAL; 42 break; 43 case OCC_RESP_INT_ERR: 44 case OCC_RESP_BAD_STATE: 45 case OCC_RESP_CRIT_EXCEPT: 46 case OCC_RESP_CRIT_INIT: 47 case OCC_RESP_CRIT_WATCHDOG: 48 case OCC_RESP_CRIT_OCB: 49 case OCC_RESP_CRIT_HW: 50 rc = -EREMOTEIO; 51 break; 52 default: 53 rc = -EPROTO; 54 } 55 56 return rc; 57 } 58 59 static int p9_sbe_occ_probe(struct platform_device *pdev) 60 { 61 int rc; 62 struct occ *occ; 63 struct p9_sbe_occ *ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), 64 GFP_KERNEL); 65 if (!ctx) 66 return -ENOMEM; 67 68 ctx->sbe = pdev->dev.parent; 69 occ = &ctx->occ; 70 occ->bus_dev = &pdev->dev; 71 platform_set_drvdata(pdev, occ); 72 73 occ->powr_sample_time_us = 500; 74 occ->poll_cmd_data = 0x20; /* P9 OCC poll data */ 75 occ->send_cmd = p9_sbe_occ_send_cmd; 76 77 rc = occ_setup(occ, "p9_occ"); 78 if (rc == -ESHUTDOWN) 79 rc = -ENODEV; /* Host is shutdown, don't spew errors */ 80 81 return rc; 82 } 83 84 static int p9_sbe_occ_remove(struct platform_device *pdev) 85 { 86 struct occ *occ = platform_get_drvdata(pdev); 87 struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ); 88 89 ctx->sbe = NULL; 90 occ_shutdown(occ); 91 92 return 0; 93 } 94 95 static struct platform_driver p9_sbe_occ_driver = { 96 .driver = { 97 .name = "occ-hwmon", 98 }, 99 .probe = p9_sbe_occ_probe, 100 .remove = p9_sbe_occ_remove, 101 }; 102 103 module_platform_driver(p9_sbe_occ_driver); 104 105 MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>"); 106 MODULE_DESCRIPTION("BMC P9 OCC hwmon driver"); 107 MODULE_LICENSE("GPL"); 108