Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2018, Nuvoton Corporation.
0004  * Copyright (c) 2018, Intel Corporation.
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  * 7.2.4 Core KCS Registers
0051  * Registers in this module are 8 bits. An 8-bit register must be accessed
0052  * by an 8-bit read or write.
0053  *
0054  * sts: KCS Channel n Status Register (KCSnST).
0055  * dob: KCS Channel n Data Out Buffer Register (KCSnDO).
0056  * dib: KCS Channel n Data In Buffer Register (KCSnDI).
0057  * ctl: KCS Channel n Control Register (KCSnCTL).
0058  * ie : KCS Channel n  Interrupt Enable Register (KCSnIE).
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");