ed5c2f5fd1
The value returned by an i2c driver's remove function is mostly ignored. (Only an error message is printed if the value is non-zero that the error is ignored.) So change the prototype of the remove function to return no value. This way driver authors are not tempted to assume that passing an error to the upper layer is a good idea. All drivers are adapted accordingly. There is no intended change of behaviour, all callbacks were prepared to return 0 before. Reviewed-by: Peter Senna Tschudin <peter.senna@gmail.com> Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au> Reviewed-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Crt Mori <cmo@melexis.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Marek Behún <kabel@kernel.org> # for leds-turris-omnia Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Petr Machata <petrm@nvidia.com> # for mlxsw Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> # for surface3_power Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> # for bmc150-accel-i2c + kxcjk-1013 Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> # for media/* + staging/media/* Acked-by: Miguel Ojeda <ojeda@kernel.org> # for auxdisplay/ht16k33 + auxdisplay/lcd2s Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # for versaclock5 Reviewed-by: Ajay Gupta <ajayg@nvidia.com> # for ucsi_ccg Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # for iio Acked-by: Peter Rosin <peda@axentia.se> # for i2c-mux-*, max9860 Acked-by: Adrien Grassein <adrien.grassein@gmail.com> # for lontium-lt8912b Reviewed-by: Jean Delvare <jdelvare@suse.de> # for hwmon, i2c-core and i2c/muxes Acked-by: Corey Minyard <cminyard@mvista.com> # for IPMI Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> # for drivers/power Acked-by: Krzysztof Hałasa <khalasa@piap.pl> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Wolfram Sang <wsa@kernel.org>
119 lines
3.1 KiB
C
119 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2021 Richtek Technology Corp.
|
|
*
|
|
* Author: ChiYuan Huang <cy_huang@richtek.com>
|
|
*/
|
|
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/module.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#define RT4831_REG_REVISION 0x01
|
|
#define RT4831_REG_ENABLE 0x08
|
|
#define RT4831_REG_I2CPROT 0x15
|
|
|
|
#define RICHTEK_VENDOR_ID 0x03
|
|
#define RT4831_VID_MASK GENMASK(1, 0)
|
|
#define RT4831_RESET_MASK BIT(7)
|
|
#define RT4831_I2CSAFETMR_MASK BIT(0)
|
|
|
|
static const struct mfd_cell rt4831_subdevs[] = {
|
|
MFD_CELL_OF("rt4831-backlight", NULL, NULL, 0, 0, "richtek,rt4831-backlight"),
|
|
MFD_CELL_NAME("rt4831-regulator")
|
|
};
|
|
|
|
static bool rt4831_is_accessible_reg(struct device *dev, unsigned int reg)
|
|
{
|
|
if (reg >= RT4831_REG_REVISION && reg <= RT4831_REG_I2CPROT)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static const struct regmap_config rt4831_regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
.max_register = RT4831_REG_I2CPROT,
|
|
|
|
.readable_reg = rt4831_is_accessible_reg,
|
|
.writeable_reg = rt4831_is_accessible_reg,
|
|
};
|
|
|
|
static int rt4831_probe(struct i2c_client *client)
|
|
{
|
|
struct gpio_desc *enable_gpio;
|
|
struct regmap *regmap;
|
|
unsigned int chip_id;
|
|
int ret;
|
|
|
|
enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
|
|
if (IS_ERR(enable_gpio)) {
|
|
dev_err(&client->dev, "Failed to get 'enable' GPIO\n");
|
|
return PTR_ERR(enable_gpio);
|
|
}
|
|
|
|
regmap = devm_regmap_init_i2c(client, &rt4831_regmap_config);
|
|
if (IS_ERR(regmap)) {
|
|
dev_err(&client->dev, "Failed to initialize regmap\n");
|
|
return PTR_ERR(regmap);
|
|
}
|
|
|
|
ret = regmap_read(regmap, RT4831_REG_REVISION, &chip_id);
|
|
if (ret) {
|
|
dev_err(&client->dev, "Failed to get H/W revision\n");
|
|
return ret;
|
|
}
|
|
|
|
if ((chip_id & RT4831_VID_MASK) != RICHTEK_VENDOR_ID) {
|
|
dev_err(&client->dev, "Chip vendor ID 0x%02x not matched\n", chip_id);
|
|
return -ENODEV;
|
|
}
|
|
|
|
/*
|
|
* Used to prevent the abnormal shutdown.
|
|
* If SCL/SDA both keep low for one second to reset HW.
|
|
*/
|
|
ret = regmap_update_bits(regmap, RT4831_REG_I2CPROT, RT4831_I2CSAFETMR_MASK,
|
|
RT4831_I2CSAFETMR_MASK);
|
|
if (ret) {
|
|
dev_err(&client->dev, "Failed to enable I2C safety timer\n");
|
|
return ret;
|
|
}
|
|
|
|
return devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, rt4831_subdevs,
|
|
ARRAY_SIZE(rt4831_subdevs), NULL, 0, NULL);
|
|
}
|
|
|
|
static void rt4831_remove(struct i2c_client *client)
|
|
{
|
|
struct regmap *regmap = dev_get_regmap(&client->dev, NULL);
|
|
int ret;
|
|
|
|
/* Disable WLED and DSV outputs */
|
|
ret = regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK);
|
|
if (ret)
|
|
dev_warn(&client->dev, "Failed to disable outputs (%pe)\n", ERR_PTR(ret));
|
|
}
|
|
|
|
static const struct of_device_id __maybe_unused rt4831_of_match[] = {
|
|
{ .compatible = "richtek,rt4831", },
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, rt4831_of_match);
|
|
|
|
static struct i2c_driver rt4831_driver = {
|
|
.driver = {
|
|
.name = "rt4831",
|
|
.of_match_table = rt4831_of_match,
|
|
},
|
|
.probe_new = rt4831_probe,
|
|
.remove = rt4831_remove,
|
|
};
|
|
module_i2c_driver(rt4831_driver);
|
|
|
|
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
|
|
MODULE_LICENSE("GPL v2");
|