Commit | Line | Data |
---|---|---|
e2f05d60 EJ |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // Copyright IBM Corp 2019 | |
5b5513b8 EJ |
3 | |
4 | #include <linux/device.h> | |
5 | #include <linux/errno.h> | |
88be37c0 | 6 | #include <linux/fsi-occ.h> |
5b5513b8 EJ |
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 | { | |
88be37c0 EJ |
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; | |
5b5513b8 EJ |
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 | ||
c10e753d | 73 | occ->powr_sample_time_us = 500; |
5b5513b8 EJ |
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; | |
df04ced6 | 90 | occ_shutdown(occ); |
5b5513b8 EJ |
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"); |