1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, Nuvoton Corporation.
4 * Copyright (c) 2018, Intel Corporation.
7 #define pr_fmt(fmt) "nuvoton-kcs-bmc: " fmt
9 #include <linux/atomic.h>
10 #include <linux/errno.h>
11 #include <linux/interrupt.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/slab.h>
22 #define DEVICE_NAME "npcm-kcs-bmc"
23 #define KCS_CHANNEL_MAX 3
40 #define KCS_CTL_IBFIE BIT(0)
45 #define KCS_IE_IRQE BIT(0)
46 #define KCS_IE_HIRQE BIT(3)
49 * 7.2.4 Core KCS Registers
50 * Registers in this module are 8 bits. An 8-bit register must be accessed
51 * by an 8-bit read or write.
53 * sts: KCS Channel n Status Register (KCSnST).
54 * dob: KCS Channel n Data Out Buffer Register (KCSnDO).
55 * dib: KCS Channel n Data In Buffer Register (KCSnDI).
56 * ctl: KCS Channel n Control Register (KCSnCTL).
57 * ie : KCS Channel n Interrupt Enable Register (KCSnIE).
59 struct npcm7xx_kcs_reg
{
67 struct npcm7xx_kcs_bmc
{
70 const struct npcm7xx_kcs_reg
*reg
;
73 static const struct npcm7xx_kcs_reg npcm7xx_kcs_reg_tbl
[KCS_CHANNEL_MAX
] = {
74 { .sts
= KCS1ST
, .dob
= KCS1DO
, .dib
= KCS1DI
, .ctl
= KCS1CTL
, .ie
= KCS1IE
},
75 { .sts
= KCS2ST
, .dob
= KCS2DO
, .dib
= KCS2DI
, .ctl
= KCS2CTL
, .ie
= KCS2IE
},
76 { .sts
= KCS3ST
, .dob
= KCS3DO
, .dib
= KCS3DI
, .ctl
= KCS3CTL
, .ie
= KCS3IE
},
79 static u8
npcm7xx_kcs_inb(struct kcs_bmc
*kcs_bmc
, u32 reg
)
81 struct npcm7xx_kcs_bmc
*priv
= kcs_bmc_priv(kcs_bmc
);
85 rc
= regmap_read(priv
->map
, reg
, &val
);
86 WARN(rc
!= 0, "regmap_read() failed: %d\n", rc
);
88 return rc
== 0 ? (u8
)val
: 0;
91 static void npcm7xx_kcs_outb(struct kcs_bmc
*kcs_bmc
, u32 reg
, u8 data
)
93 struct npcm7xx_kcs_bmc
*priv
= kcs_bmc_priv(kcs_bmc
);
96 rc
= regmap_write(priv
->map
, reg
, data
);
97 WARN(rc
!= 0, "regmap_write() failed: %d\n", rc
);
100 static void npcm7xx_kcs_enable_channel(struct kcs_bmc
*kcs_bmc
, bool enable
)
102 struct npcm7xx_kcs_bmc
*priv
= kcs_bmc_priv(kcs_bmc
);
104 regmap_update_bits(priv
->map
, priv
->reg
->ctl
, KCS_CTL_IBFIE
,
105 enable
? KCS_CTL_IBFIE
: 0);
107 regmap_update_bits(priv
->map
, priv
->reg
->ie
, KCS_IE_IRQE
| KCS_IE_HIRQE
,
108 enable
? KCS_IE_IRQE
| KCS_IE_HIRQE
: 0);
111 static irqreturn_t
npcm7xx_kcs_irq(int irq
, void *arg
)
113 struct kcs_bmc
*kcs_bmc
= arg
;
115 if (!kcs_bmc_handle_event(kcs_bmc
))
121 static int npcm7xx_kcs_config_irq(struct kcs_bmc
*kcs_bmc
,
122 struct platform_device
*pdev
)
124 struct device
*dev
= &pdev
->dev
;
127 irq
= platform_get_irq(pdev
, 0);
131 return devm_request_irq(dev
, irq
, npcm7xx_kcs_irq
, IRQF_SHARED
,
132 dev_name(dev
), kcs_bmc
);
135 static int npcm7xx_kcs_probe(struct platform_device
*pdev
)
137 struct device
*dev
= &pdev
->dev
;
138 struct npcm7xx_kcs_bmc
*priv
;
139 struct kcs_bmc
*kcs_bmc
;
143 rc
= of_property_read_u32(dev
->of_node
, "kcs_chan", &chan
);
144 if (rc
!= 0 || chan
== 0 || chan
> KCS_CHANNEL_MAX
) {
145 dev_err(dev
, "no valid 'kcs_chan' configured\n");
149 kcs_bmc
= kcs_bmc_alloc(dev
, sizeof(*priv
), chan
);
153 priv
= kcs_bmc_priv(kcs_bmc
);
154 priv
->map
= syscon_node_to_regmap(dev
->parent
->of_node
);
155 if (IS_ERR(priv
->map
)) {
156 dev_err(dev
, "Couldn't get regmap\n");
159 priv
->reg
= &npcm7xx_kcs_reg_tbl
[chan
- 1];
161 kcs_bmc
->ioreg
.idr
= priv
->reg
->dib
;
162 kcs_bmc
->ioreg
.odr
= priv
->reg
->dob
;
163 kcs_bmc
->ioreg
.str
= priv
->reg
->sts
;
164 kcs_bmc
->io_inputb
= npcm7xx_kcs_inb
;
165 kcs_bmc
->io_outputb
= npcm7xx_kcs_outb
;
167 dev_set_drvdata(dev
, kcs_bmc
);
169 npcm7xx_kcs_enable_channel(kcs_bmc
, true);
170 rc
= npcm7xx_kcs_config_irq(kcs_bmc
, pdev
);
174 rc
= misc_register(&kcs_bmc
->miscdev
);
176 dev_err(dev
, "Unable to register device\n");
180 pr_info("channel=%u idr=0x%x odr=0x%x str=0x%x\n",
182 kcs_bmc
->ioreg
.idr
, kcs_bmc
->ioreg
.odr
, kcs_bmc
->ioreg
.str
);
187 static int npcm7xx_kcs_remove(struct platform_device
*pdev
)
189 struct kcs_bmc
*kcs_bmc
= dev_get_drvdata(&pdev
->dev
);
191 misc_deregister(&kcs_bmc
->miscdev
);
196 static const struct of_device_id npcm_kcs_bmc_match
[] = {
197 { .compatible
= "nuvoton,npcm750-kcs-bmc" },
200 MODULE_DEVICE_TABLE(of
, npcm_kcs_bmc_match
);
202 static struct platform_driver npcm_kcs_bmc_driver
= {
205 .of_match_table
= npcm_kcs_bmc_match
,
207 .probe
= npcm7xx_kcs_probe
,
208 .remove
= npcm7xx_kcs_remove
,
210 module_platform_driver(npcm_kcs_bmc_driver
);
212 MODULE_LICENSE("GPL v2");
213 MODULE_AUTHOR("Avi Fishman <avifishman70@gmail.com>");
214 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
215 MODULE_DESCRIPTION("NPCM7xx device interface to the KCS BMC device");