0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) "nuvoton-kcs-bmc: " fmt
0008
0009 #include <linux/atomic.h>
0010 #include <linux/errno.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/io.h>
0013 #include <linux/mfd/syscon.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018 #include <linux/slab.h>
0019
0020 #include "kcs_bmc_device.h"
0021
0022 #define DEVICE_NAME "npcm-kcs-bmc"
0023 #define KCS_CHANNEL_MAX 3
0024
0025 #define KCS1ST 0x0C
0026 #define KCS2ST 0x1E
0027 #define KCS3ST 0x30
0028
0029 #define KCS1DO 0x0E
0030 #define KCS2DO 0x20
0031 #define KCS3DO 0x32
0032
0033 #define KCS1DI 0x10
0034 #define KCS2DI 0x22
0035 #define KCS3DI 0x34
0036
0037 #define KCS1CTL 0x18
0038 #define KCS2CTL 0x2A
0039 #define KCS3CTL 0x3C
0040 #define KCS_CTL_IBFIE BIT(0)
0041 #define KCS_CTL_OBEIE BIT(1)
0042
0043 #define KCS1IE 0x1C
0044 #define KCS2IE 0x2E
0045 #define KCS3IE 0x40
0046 #define KCS_IE_IRQE BIT(0)
0047 #define KCS_IE_HIRQE BIT(3)
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 struct npcm7xx_kcs_reg {
0061 u32 sts;
0062 u32 dob;
0063 u32 dib;
0064 u32 ctl;
0065 u32 ie;
0066 };
0067
0068 struct npcm7xx_kcs_bmc {
0069 struct kcs_bmc_device kcs_bmc;
0070
0071 struct regmap *map;
0072
0073 const struct npcm7xx_kcs_reg *reg;
0074 };
0075
0076 static const struct npcm7xx_kcs_reg npcm7xx_kcs_reg_tbl[KCS_CHANNEL_MAX] = {
0077 { .sts = KCS1ST, .dob = KCS1DO, .dib = KCS1DI, .ctl = KCS1CTL, .ie = KCS1IE },
0078 { .sts = KCS2ST, .dob = KCS2DO, .dib = KCS2DI, .ctl = KCS2CTL, .ie = KCS2IE },
0079 { .sts = KCS3ST, .dob = KCS3DO, .dib = KCS3DI, .ctl = KCS3CTL, .ie = KCS3IE },
0080 };
0081
0082 static inline struct npcm7xx_kcs_bmc *to_npcm7xx_kcs_bmc(struct kcs_bmc_device *kcs_bmc)
0083 {
0084 return container_of(kcs_bmc, struct npcm7xx_kcs_bmc, kcs_bmc);
0085 }
0086
0087 static u8 npcm7xx_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg)
0088 {
0089 struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
0090 u32 val = 0;
0091 int rc;
0092
0093 rc = regmap_read(priv->map, reg, &val);
0094 WARN(rc != 0, "regmap_read() failed: %d\n", rc);
0095
0096 return rc == 0 ? (u8)val : 0;
0097 }
0098
0099 static void npcm7xx_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data)
0100 {
0101 struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
0102 int rc;
0103
0104 rc = regmap_write(priv->map, reg, data);
0105 WARN(rc != 0, "regmap_write() failed: %d\n", rc);
0106 }
0107
0108 static void npcm7xx_kcs_updateb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 mask, u8 data)
0109 {
0110 struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
0111 int rc;
0112
0113 rc = regmap_update_bits(priv->map, reg, mask, data);
0114 WARN(rc != 0, "regmap_update_bits() failed: %d\n", rc);
0115 }
0116
0117 static void npcm7xx_kcs_enable_channel(struct kcs_bmc_device *kcs_bmc, bool enable)
0118 {
0119 struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
0120
0121 regmap_update_bits(priv->map, priv->reg->ie, KCS_IE_IRQE | KCS_IE_HIRQE,
0122 enable ? KCS_IE_IRQE | KCS_IE_HIRQE : 0);
0123 }
0124
0125 static void npcm7xx_kcs_irq_mask_update(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 state)
0126 {
0127 struct npcm7xx_kcs_bmc *priv = to_npcm7xx_kcs_bmc(kcs_bmc);
0128
0129 if (mask & KCS_BMC_EVENT_TYPE_OBE)
0130 regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_OBEIE,
0131 !!(state & KCS_BMC_EVENT_TYPE_OBE) * KCS_CTL_OBEIE);
0132
0133 if (mask & KCS_BMC_EVENT_TYPE_IBF)
0134 regmap_update_bits(priv->map, priv->reg->ctl, KCS_CTL_IBFIE,
0135 !!(state & KCS_BMC_EVENT_TYPE_IBF) * KCS_CTL_IBFIE);
0136 }
0137
0138 static irqreturn_t npcm7xx_kcs_irq(int irq, void *arg)
0139 {
0140 struct kcs_bmc_device *kcs_bmc = arg;
0141
0142 return kcs_bmc_handle_event(kcs_bmc);
0143 }
0144
0145 static int npcm7xx_kcs_config_irq(struct kcs_bmc_device *kcs_bmc,
0146 struct platform_device *pdev)
0147 {
0148 struct device *dev = &pdev->dev;
0149 int irq;
0150
0151 irq = platform_get_irq(pdev, 0);
0152 if (irq < 0)
0153 return irq;
0154
0155 return devm_request_irq(dev, irq, npcm7xx_kcs_irq, IRQF_SHARED,
0156 dev_name(dev), kcs_bmc);
0157 }
0158
0159 static const struct kcs_bmc_device_ops npcm7xx_kcs_ops = {
0160 .irq_mask_update = npcm7xx_kcs_irq_mask_update,
0161 .io_inputb = npcm7xx_kcs_inb,
0162 .io_outputb = npcm7xx_kcs_outb,
0163 .io_updateb = npcm7xx_kcs_updateb,
0164 };
0165
0166 static int npcm7xx_kcs_probe(struct platform_device *pdev)
0167 {
0168 struct device *dev = &pdev->dev;
0169 struct npcm7xx_kcs_bmc *priv;
0170 struct kcs_bmc_device *kcs_bmc;
0171 u32 chan;
0172 int rc;
0173
0174 rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
0175 if (rc != 0 || chan == 0 || chan > KCS_CHANNEL_MAX) {
0176 dev_err(dev, "no valid 'kcs_chan' configured\n");
0177 return -ENODEV;
0178 }
0179
0180 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0181 if (!priv)
0182 return -ENOMEM;
0183
0184 priv->map = syscon_node_to_regmap(dev->parent->of_node);
0185 if (IS_ERR(priv->map)) {
0186 dev_err(dev, "Couldn't get regmap\n");
0187 return -ENODEV;
0188 }
0189 priv->reg = &npcm7xx_kcs_reg_tbl[chan - 1];
0190
0191 kcs_bmc = &priv->kcs_bmc;
0192 kcs_bmc->dev = &pdev->dev;
0193 kcs_bmc->channel = chan;
0194 kcs_bmc->ioreg.idr = priv->reg->dib;
0195 kcs_bmc->ioreg.odr = priv->reg->dob;
0196 kcs_bmc->ioreg.str = priv->reg->sts;
0197 kcs_bmc->ops = &npcm7xx_kcs_ops;
0198
0199 platform_set_drvdata(pdev, priv);
0200
0201 rc = npcm7xx_kcs_config_irq(kcs_bmc, pdev);
0202 if (rc)
0203 return rc;
0204
0205 npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
0206 npcm7xx_kcs_enable_channel(kcs_bmc, true);
0207
0208 rc = kcs_bmc_add_device(kcs_bmc);
0209 if (rc) {
0210 dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc);
0211 return rc;
0212 }
0213
0214 pr_info("channel=%u idr=0x%x odr=0x%x str=0x%x\n",
0215 chan,
0216 kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
0217
0218 return 0;
0219 }
0220
0221 static int npcm7xx_kcs_remove(struct platform_device *pdev)
0222 {
0223 struct npcm7xx_kcs_bmc *priv = platform_get_drvdata(pdev);
0224 struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;
0225
0226 kcs_bmc_remove_device(kcs_bmc);
0227
0228 npcm7xx_kcs_enable_channel(kcs_bmc, false);
0229 npcm7xx_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0);
0230
0231 return 0;
0232 }
0233
0234 static const struct of_device_id npcm_kcs_bmc_match[] = {
0235 { .compatible = "nuvoton,npcm750-kcs-bmc" },
0236 { }
0237 };
0238 MODULE_DEVICE_TABLE(of, npcm_kcs_bmc_match);
0239
0240 static struct platform_driver npcm_kcs_bmc_driver = {
0241 .driver = {
0242 .name = DEVICE_NAME,
0243 .of_match_table = npcm_kcs_bmc_match,
0244 },
0245 .probe = npcm7xx_kcs_probe,
0246 .remove = npcm7xx_kcs_remove,
0247 };
0248 module_platform_driver(npcm_kcs_bmc_driver);
0249
0250 MODULE_LICENSE("GPL v2");
0251 MODULE_AUTHOR("Avi Fishman <avifishman70@gmail.com>");
0252 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
0253 MODULE_DESCRIPTION("NPCM7xx device interface to the KCS BMC device");