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