1 // SPDX-License-Identifier: GPL-2.0-only
3 * Ampere Computing SoC's SMpro Misc Driver
5 * Copyright (c) 2022, Ampere Computing LLC
7 #include <linux/mod_devicetable.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/regmap.h>
12 /* Boot Stage/Progress Registers */
13 #define BOOTSTAGE 0xB0
14 #define BOOTSTAGE_LO 0xB1
15 #define CUR_BOOTSTAGE 0xB2
16 #define BOOTSTAGE_HI 0xB3
18 /* SOC State Registers */
19 #define SOC_POWER_LIMIT 0xE5
22 struct regmap
*regmap
;
25 static ssize_t
boot_progress_show(struct device
*dev
, struct device_attribute
*da
, char *buf
)
27 struct smpro_misc
*misc
= dev_get_drvdata(dev
);
28 u16 boot_progress
[3] = { 0 };
36 /* Read current boot stage */
37 ret
= regmap_read(misc
->regmap
, CUR_BOOTSTAGE
, ®
);
41 cur_stage
= reg
& 0xff;
43 ret
= regmap_read(misc
->regmap
, BOOTSTAGE
, &bootstage
);
47 boot_stage
= (bootstage
>> 8) & 0xff;
49 if (boot_stage
> cur_stage
)
52 ret
= regmap_read(misc
->regmap
, BOOTSTAGE_LO
, ®_lo
);
54 ret
= regmap_read(misc
->regmap
, BOOTSTAGE_HI
, ®
);
58 /* Firmware to report new boot stage next time */
59 if (boot_stage
< cur_stage
) {
60 ret
= regmap_write(misc
->regmap
, BOOTSTAGE
, ((bootstage
& 0xff00) | 0x1));
65 boot_progress
[0] = bootstage
;
66 boot_progress
[1] = swab16(reg
);
67 boot_progress
[2] = swab16(reg_lo
);
69 return sysfs_emit(buf
, "%*phN\n", (int)sizeof(boot_progress
), boot_progress
);
72 static DEVICE_ATTR_RO(boot_progress
);
74 static ssize_t
soc_power_limit_show(struct device
*dev
, struct device_attribute
*da
, char *buf
)
76 struct smpro_misc
*misc
= dev_get_drvdata(dev
);
80 ret
= regmap_read(misc
->regmap
, SOC_POWER_LIMIT
, &value
);
84 return sysfs_emit(buf
, "%d\n", value
);
87 static ssize_t
soc_power_limit_store(struct device
*dev
, struct device_attribute
*da
,
88 const char *buf
, size_t count
)
90 struct smpro_misc
*misc
= dev_get_drvdata(dev
);
94 ret
= kstrtoul(buf
, 0, &val
);
98 ret
= regmap_write(misc
->regmap
, SOC_POWER_LIMIT
, (unsigned int)val
);
105 static DEVICE_ATTR_RW(soc_power_limit
);
107 static struct attribute
*smpro_misc_attrs
[] = {
108 &dev_attr_boot_progress
.attr
,
109 &dev_attr_soc_power_limit
.attr
,
113 ATTRIBUTE_GROUPS(smpro_misc
);
115 static int smpro_misc_probe(struct platform_device
*pdev
)
117 struct smpro_misc
*misc
;
119 misc
= devm_kzalloc(&pdev
->dev
, sizeof(struct smpro_misc
), GFP_KERNEL
);
123 platform_set_drvdata(pdev
, misc
);
125 misc
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
132 static struct platform_driver smpro_misc_driver
= {
133 .probe
= smpro_misc_probe
,
135 .name
= "smpro-misc",
136 .dev_groups
= smpro_misc_groups
,
140 module_platform_driver(smpro_misc_driver
);
142 MODULE_AUTHOR("Tung Nguyen <tungnguyen@os.amperecomputing.com>");
143 MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
144 MODULE_DESCRIPTION("Ampere Altra SMpro Misc driver");
145 MODULE_LICENSE("GPL");