brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 9cac7ae Raw
179 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (c) 2023 Neil Armstrong <neil.armstrong@linaro.org>4 */5#include <linux/kernel.h>6#include <linux/init.h>7#include <linux/of.h>8#include <linux/platform_device.h>9#include <linux/mfd/rk808.h>10#include <linux/regmap.h>11#include <linux/module.h>12#include <linux/reboot.h>13#include <linux/i2c.h>14 15/*16 * The Odroid Go Ultra has 2 PMICs:17 * - RK818 (manages the battery and USB-C power supply)18 * - RK81719 * Both PMICs feeds power to the S922X SoC, so they must be powered-off in sequence.20 * Vendor does power-off the RK817 first, then the RK818 so here we follow this sequence.21 */22 23struct odroid_go_ultra_poweroff_data {24	struct device *dev;25	struct device *rk817;26	struct device *rk818;27};28 29static int odroid_go_ultra_poweroff_prepare(struct sys_off_data *data)30{31	struct odroid_go_ultra_poweroff_data *poweroff_data = data->cb_data;32	struct regmap *rk817, *rk818;33	int ret;34 35	/* RK817 Regmap */36	rk817 = dev_get_regmap(poweroff_data->rk817, NULL);37	if (!rk817) {38		dev_err(poweroff_data->dev, "failed to get rk817 regmap\n");39		return notifier_from_errno(-EINVAL);40	}41 42	/* RK818 Regmap */43	rk818 = dev_get_regmap(poweroff_data->rk818, NULL);44	if (!rk818) {45		dev_err(poweroff_data->dev, "failed to get rk818 regmap\n");46		return notifier_from_errno(-EINVAL);47	}48 49	dev_info(poweroff_data->dev, "Setting PMICs for power off");50 51	/* RK817 */52	ret = regmap_update_bits(rk817, RK817_SYS_CFG(3), DEV_OFF, DEV_OFF);53	if (ret) {54		dev_err(poweroff_data->dev, "failed to poweroff rk817\n");55		return notifier_from_errno(ret);56	}57 58	/* RK818 */59	ret = regmap_update_bits(rk818, RK818_DEVCTRL_REG, DEV_OFF, DEV_OFF);60	if (ret) {61		dev_err(poweroff_data->dev, "failed to poweroff rk818\n");62		return notifier_from_errno(ret);63	}64 65	return NOTIFY_OK;66}67 68static void odroid_go_ultra_poweroff_put_pmic_device(void *data)69{70	struct device *dev = data;71 72	put_device(dev);73}74 75static int odroid_go_ultra_poweroff_get_pmic_device(struct device *dev, const char *compatible,76						    struct device **pmic)77{78	struct device_node *pmic_node;79	struct i2c_client *pmic_client;80 81	pmic_node = of_find_compatible_node(NULL, NULL, compatible);82	if (!pmic_node)83		return -ENODEV;84 85	pmic_client = of_find_i2c_device_by_node(pmic_node);86	of_node_put(pmic_node);87	if (!pmic_client)88		return -EPROBE_DEFER;89 90	*pmic = &pmic_client->dev;91 92	return devm_add_action_or_reset(dev, odroid_go_ultra_poweroff_put_pmic_device, *pmic);93}94 95static int odroid_go_ultra_poweroff_probe(struct platform_device *pdev)96{97	struct odroid_go_ultra_poweroff_data *poweroff_data;98	int ret;99 100	poweroff_data = devm_kzalloc(&pdev->dev, sizeof(*poweroff_data), GFP_KERNEL);101	if (!poweroff_data)102		return -ENOMEM;103 104	dev_set_drvdata(&pdev->dev, poweroff_data);105 106	/* RK818 PMIC Device */107	ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk818",108						       &poweroff_data->rk818);109	if (ret)110		return dev_err_probe(&pdev->dev, ret, "failed to get rk818 mfd data\n");111 112	/* RK817 PMIC Device */113	ret = odroid_go_ultra_poweroff_get_pmic_device(&pdev->dev, "rockchip,rk817",114						       &poweroff_data->rk817);115	if (ret)116		return dev_err_probe(&pdev->dev, ret, "failed to get rk817 mfd data\n");117 118	/* Register as SYS_OFF_MODE_POWER_OFF_PREPARE because regmap_update_bits may sleep */119	ret = devm_register_sys_off_handler(&pdev->dev,120					    SYS_OFF_MODE_POWER_OFF_PREPARE,121					    SYS_OFF_PRIO_DEFAULT,122					    odroid_go_ultra_poweroff_prepare,123					    poweroff_data);124	if (ret)125		return dev_err_probe(&pdev->dev, ret, "failed to register sys-off handler\n");126 127	dev_info(&pdev->dev, "Registered Power-Off handler\n");128 129	return 0;130}131static struct platform_device *pdev;132 133static struct platform_driver odroid_go_ultra_poweroff_driver = {134	.driver = {135		.name	= "odroid-go-ultra-poweroff",136	},137	.probe = odroid_go_ultra_poweroff_probe,138};139 140static int __init odroid_go_ultra_poweroff_init(void)141{142	int ret;143 144	/* Only create when running on the Odroid Go Ultra device */145	if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))146		return -ENODEV;147 148	ret = platform_driver_register(&odroid_go_ultra_poweroff_driver);149	if (ret)150		return ret;151 152	pdev = platform_device_register_resndata(NULL, "odroid-go-ultra-poweroff", -1,153						 NULL, 0, NULL, 0);154 155	if (IS_ERR(pdev)) {156		platform_driver_unregister(&odroid_go_ultra_poweroff_driver);157		return PTR_ERR(pdev);158	}159 160	return 0;161}162 163static void __exit odroid_go_ultra_poweroff_exit(void)164{165	/* Only delete when running on the Odroid Go Ultra device */166	if (!of_device_is_compatible(of_root, "hardkernel,odroid-go-ultra"))167		return;168 169	platform_device_unregister(pdev);170	platform_driver_unregister(&odroid_go_ultra_poweroff_driver);171}172 173module_init(odroid_go_ultra_poweroff_init);174module_exit(odroid_go_ultra_poweroff_exit);175 176MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");177MODULE_DESCRIPTION("Odroid Go Ultra poweroff driver");178MODULE_LICENSE("GPL");179