Skip to content

Commit e9b56c6

Browse files
committed
Add Hasivo STC8 multi-function device (syscon)
Performs register passthrough with added OR'ing of execute bit if required. Signed-off-by: Bevan Weiss <[email protected]>
1 parent 6aaffdd commit e9b56c6

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# STC8 MFD binding for Hasivo switches
3+
# Defines properties for MFD regmap wrapper, LEDs, and PWM
4+
5+
title: "STC8 multi-function device"
6+
description: |
7+
This binding describes the Hasivo STC8 multi-function device.
8+
This is an STC8 microcontroller with custom firmware used by Hasivo to
9+
provide various functions on their managed switch products.
10+
The main known functionality currently is to allow for discrete GPIO control
11+
which turns on/off LEDs and controls PWM for fan speed.
12+
It is known that for the discrete IO however, the host must send an execute
13+
flag (0x40) along with the register write to have the STC8 apply the change.
14+
This binding allows for specifying which registers require this execute flag
15+
to be set automatically by the MFD driver.
16+
17+
maintainers:
18+
19+
20+
properties:
21+
compatible:
22+
description: >
23+
Must be "hasivo,stc8" for the MFD driver to bind.
24+
type: string
25+
required: true
26+
27+
reg:
28+
description: >
29+
I2C address of the STC8 device.
30+
type: array of integers
31+
required: true
32+
33+
reg-names:
34+
description: >
35+
Names of register blocks for the device.
36+
type: array of strings
37+
required: true
38+
39+
hasivo,execute-bit-regs:
40+
description: >
41+
Array of registers for which the execute-bit (0x40) should be
42+
automatically ORed on writes.
43+
type: array of integers
44+
required: false
45+
46+
children:
47+
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/module.h>
3+
#include <linux/platform_device.h>
4+
#include <linux/of_platform.h>
5+
#include <linux/mfd/syscon.h>
6+
#include <linux/regmap.h>
7+
#include <linux/slab.h>
8+
9+
struct stc8_hook {
10+
struct regmap *orig_map;
11+
int (*orig_write)(struct regmap *, unsigned int, unsigned int);
12+
u8 *execute_regs;
13+
int execute_count;
14+
};
15+
16+
struct stc8_mfd {
17+
struct device *dev;
18+
struct regmap *regmap;
19+
struct stc8_hook *hook;
20+
};
21+
22+
/* Hooked regmap_write */
23+
static int stc8_hooked_write(struct regmap *map, unsigned int reg, unsigned int val)
24+
{
25+
struct stc8_hook *hook = map->regmap_volatile_context;
26+
unsigned int new_val = val;
27+
28+
/* OR execute bit if reg matches DT list */
29+
for (int i = 0; i < hook->execute_count; i++) {
30+
if (reg == hook->execute_regs[i]) {
31+
new_val |= 0x40;
32+
break;
33+
}
34+
}
35+
36+
pr_info("%s: STC8 MFD write intercepted, reg=0x%x, orig_val=0x%x, new_val=0x%x\n", __func__, reg, val, new_val);
37+
/* Call original write */
38+
return hook->orig_write(hook->orig_map, reg, new_val);
39+
}
40+
41+
static int stc8_mfd_probe(struct platform_device *pdev)
42+
{
43+
struct device_node *np = pdev->dev.of_node;
44+
struct stc8_mfd *mfd;
45+
struct regmap *parent_map;
46+
const __be32 *regs;
47+
int count, i, ret;
48+
49+
mfd = devm_kzalloc(&pdev->dev, sizeof(*mfd), GFP_KERNEL);
50+
if (!mfd)
51+
return -ENOMEM;
52+
mfd->dev = &pdev->dev;
53+
54+
/* Get parent syscon regmap */
55+
parent_map = syscon_node_to_regmap(np);
56+
if (IS_ERR(parent_map))
57+
return PTR_ERR(parent_map);
58+
59+
mfd->regmap = parent_map;
60+
61+
/* Parse DT execute-bit registers */
62+
regs = of_get_property(np, "hasivo,execute-bit-regs", &count);
63+
if (!regs || count < 0)
64+
return -EINVAL;
65+
66+
count /= sizeof(u32);
67+
mfd->hook = devm_kzalloc(&pdev->dev, sizeof(*mfd->hook), GFP_KERNEL);
68+
if (!mfd->hook)
69+
return -ENOMEM;
70+
71+
mfd->hook->orig_map = parent_map;
72+
mfd->hook->orig_write = parent_map->regmap_write;
73+
mfd->hook->execute_count = count;
74+
mfd->hook->execute_regs = count > 0 ? devm_kmalloc(&pdev->dev, count, GFP_KERNEL) : NULL;
75+
if (!mfd->hook->execute_regs)
76+
return -ENOMEM;
77+
78+
for (i = 0; i < count; i++)
79+
mfd->hook->execute_regs[i] = be32_to_cpup(regs + i);
80+
81+
/* Overwrite parent regmap write pointer */
82+
parent_map->regmap_write = stc8_hooked_write;
83+
parent_map->regmap_volatile_context = mfd->hook; // hook context
84+
85+
/* Populate children (LEDs, PWM, etc) - children will use parent regmap */
86+
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
87+
if (ret) {
88+
dev_err(&pdev->dev, "Failed to populate child devices\n");
89+
return ret;
90+
}
91+
92+
dev_info(&pdev->dev, "STC8 MFD probe complete, execute-bit hooked\n");
93+
return 0;
94+
}
95+
96+
static const struct of_device_id stc8_mfd_of_match[] = {
97+
{ .compatible = "hasivo,stc8-mfd" },
98+
{ /* sentinel */ }
99+
};
100+
MODULE_DEVICE_TABLE(of, stc8_mfd_of_match);
101+
102+
static struct platform_driver stc8_mfd_driver = {
103+
.driver = {
104+
.name = "stc8-mfd",
105+
.of_match_table = stc8_mfd_of_match,
106+
},
107+
.probe = stc8_mfd_probe,
108+
};
109+
module_platform_driver(stc8_mfd_driver);
110+
111+
MODULE_LICENSE("GPL");
112+
MODULE_DESCRIPTION("STC8 MFD driver with regmap-write hook for execute-bit");
113+
MODULE_AUTHOR("Bevan Weiss <[email protected]>");
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
3+
--- a/drivers/mfd/Kconfig
4+
+++ b/drivers/mfd/Kconfig
5+
@@ -540,10 +540,21 @@
6+
config MFD_MX25_TSADC
7+
tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
8+
select REGMAP_MMIO
9+
depends on (SOC_IMX25 && OF) || COMPILE_TEST
10+
help
11+
Enable support for the integrated Touchscreen and ADC unit of the
12+
i.MX25 processors. They consist of a conversion queue for general
13+
purpose ADC and a queue for Touchscreens.
14+
+
15+
+config MFD_HASIVO_STC8
16+
+ tristate "Hasivo STC8 Multifunction Device"
17+
+ select MFD_CORE
18+
+ select REGMAP_I2C
19+
+ depends on I2C
20+
+ help
21+
+ Support for the Hasivo STC8 multifunction device over I2C.
22+
+ This driver provides common support for accessing the device,
23+
+ additional drivers must be enabled in order to use the
24+
+ functionality of the device.
25+
26+
config MFD_HI6421_PMIC
27+
28+
29+
---
30+
--- a/drivers/mfd/Makefile
31+
+++ b/drivers/mfd/Makefile
32+
@@ -291,2 +291,4 @@
33+
obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
34+
obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
35+
+
36+
+obj-$(CONFIG_MFD_HASIVO_STC8) += hasivo-stc8-mfd.o
37+
38+

0 commit comments

Comments
 (0)