brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 418b71a Raw
181 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Power-source driver for Bay Trail Crystal Cove PMIC4 *5 * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com>6 *7 * Based on intel_crystalcove_pwrsrc.c from Android kernel sources, which is:8 * Copyright (C) 2013 Intel Corporation9 */10 11#include <linux/debugfs.h>12#include <linux/mfd/intel_soc_pmic.h>13#include <linux/module.h>14#include <linux/platform_device.h>15#include <linux/regmap.h>16 17#define CRYSTALCOVE_SPWRSRC_REG		0x1E18#define CRYSTALCOVE_RESETSRC0_REG	0x2019#define CRYSTALCOVE_RESETSRC1_REG	0x2120#define CRYSTALCOVE_WAKESRC_REG		0x2221 22struct crc_pwrsrc_data {23	struct regmap *regmap;24	struct dentry *debug_dentry;25	unsigned int resetsrc0;26	unsigned int resetsrc1;27	unsigned int wakesrc;28};29 30static const char * const pwrsrc_pwrsrc_info[] = {31	/* bit 0 */ "USB",32	/* bit 1 */ "DC in",33	/* bit 2 */ "Battery",34	NULL,35};36 37static const char * const pwrsrc_resetsrc0_info[] = {38	/* bit 0 */ "SOC reporting a thermal event",39	/* bit 1 */ "critical PMIC temperature",40	/* bit 2 */ "critical system temperature",41	/* bit 3 */ "critical battery temperature",42	/* bit 4 */ "VSYS under voltage",43	/* bit 5 */ "VSYS over voltage",44	/* bit 6 */ "battery removal",45	NULL,46};47 48static const char * const pwrsrc_resetsrc1_info[] = {49	/* bit 0 */ "VCRIT threshold",50	/* bit 1 */ "BATID reporting battery removal",51	/* bit 2 */ "user pressing the power button",52	NULL,53};54 55static const char * const pwrsrc_wakesrc_info[] = {56	/* bit 0 */ "user pressing the power button",57	/* bit 1 */ "a battery insertion",58	/* bit 2 */ "a USB charger insertion",59	/* bit 3 */ "an adapter insertion",60	NULL,61};62 63static void crc_pwrsrc_log(struct seq_file *seq, const char *prefix,64			   const char * const *info, unsigned int reg_val)65{66	int i;67 68	for (i = 0; info[i]; i++) {69		if (reg_val & BIT(i))70			seq_printf(seq, "%s by %s\n", prefix, info[i]);71	}72}73 74static int pwrsrc_show(struct seq_file *seq, void *unused)75{76	struct crc_pwrsrc_data *data = seq->private;77	unsigned int reg_val;78	int ret;79 80	ret = regmap_read(data->regmap, CRYSTALCOVE_SPWRSRC_REG, &reg_val);81	if (ret)82		return ret;83 84	crc_pwrsrc_log(seq, "System powered", pwrsrc_pwrsrc_info, reg_val);85	return 0;86}87 88static int resetsrc_show(struct seq_file *seq, void *unused)89{90	struct crc_pwrsrc_data *data = seq->private;91 92	crc_pwrsrc_log(seq, "Last shutdown caused", pwrsrc_resetsrc0_info, data->resetsrc0);93	crc_pwrsrc_log(seq, "Last shutdown caused", pwrsrc_resetsrc1_info, data->resetsrc1);94	return 0;95}96 97static int wakesrc_show(struct seq_file *seq, void *unused)98{99	struct crc_pwrsrc_data *data = seq->private;100 101	crc_pwrsrc_log(seq, "Last wake caused", pwrsrc_wakesrc_info, data->wakesrc);102	return 0;103}104 105DEFINE_SHOW_ATTRIBUTE(pwrsrc);106DEFINE_SHOW_ATTRIBUTE(resetsrc);107DEFINE_SHOW_ATTRIBUTE(wakesrc);108 109static int crc_pwrsrc_read_and_clear(struct crc_pwrsrc_data *data,110				     unsigned int reg, unsigned int *val)111{112	int ret;113 114	ret = regmap_read(data->regmap, reg, val);115	if (ret)116		return ret;117 118	return regmap_write(data->regmap, reg, *val);119}120 121static int crc_pwrsrc_probe(struct platform_device *pdev)122{123	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);124	struct crc_pwrsrc_data *data;125	int ret;126 127	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);128	if (!data)129		return -ENOMEM;130 131	data->regmap = pmic->regmap;132 133	/*134	 * Read + clear resetsrc0/1 and wakesrc now, so that they get135	 * cleared even if the debugfs interface is never used.136	 *137	 * Properly clearing the wakesrc is important, leaving bit 0 of it138	 * set turns reboot into poweroff on some tablets.139	 */140	ret = crc_pwrsrc_read_and_clear(data, CRYSTALCOVE_RESETSRC0_REG, &data->resetsrc0);141	if (ret)142		return ret;143 144	ret = crc_pwrsrc_read_and_clear(data, CRYSTALCOVE_RESETSRC1_REG, &data->resetsrc1);145	if (ret)146		return ret;147 148	ret = crc_pwrsrc_read_and_clear(data, CRYSTALCOVE_WAKESRC_REG, &data->wakesrc);149	if (ret)150		return ret;151 152	data->debug_dentry = debugfs_create_dir(KBUILD_MODNAME, NULL);153	debugfs_create_file("pwrsrc", 0444, data->debug_dentry, data, &pwrsrc_fops);154	debugfs_create_file("resetsrc", 0444, data->debug_dentry, data, &resetsrc_fops);155	debugfs_create_file("wakesrc", 0444, data->debug_dentry, data, &wakesrc_fops);156 157	platform_set_drvdata(pdev, data);158	return 0;159}160 161static void crc_pwrsrc_remove(struct platform_device *pdev)162{163	struct crc_pwrsrc_data *data = platform_get_drvdata(pdev);164 165	debugfs_remove_recursive(data->debug_dentry);166}167 168static struct platform_driver crc_pwrsrc_driver = {169	.probe = crc_pwrsrc_probe,170	.remove_new = crc_pwrsrc_remove,171	.driver = {172		.name = "crystal_cove_pwrsrc",173	},174};175module_platform_driver(crc_pwrsrc_driver);176 177MODULE_ALIAS("platform:crystal_cove_pwrsrc");178MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");179MODULE_DESCRIPTION("Power-source driver for Bay Trail Crystal Cove PMIC");180MODULE_LICENSE("GPL");181