diff options
Diffstat (limited to 'drivers/mfd')
51 files changed, 579 insertions, 127 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index eaf9845633b4..a30e47b74327 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -583,7 +583,7 @@ out_init: return ret; } -static int pm800_remove(struct i2c_client *client) +static void pm800_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -592,8 +592,6 @@ static int pm800_remove(struct i2c_client *client) pm800_pages_exit(chip); pm80x_deinit(); - - return 0; } static struct i2c_driver pm800_driver = { diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index ada6c513302b..10d3637840c8 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -239,7 +239,7 @@ out_init: return ret; } -static int pm805_remove(struct i2c_client *client) +static void pm805_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -247,8 +247,6 @@ static int pm805_remove(struct i2c_client *client) device_irq_exit_805(chip); pm80x_deinit(); - - return 0; } static struct i2c_driver pm805_driver = { diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index b1e829ea909b..5dc86dd66202 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1201,7 +1201,7 @@ static int pm860x_probe(struct i2c_client *client) return 0; } -static int pm860x_remove(struct i2c_client *client) +static void pm860x_remove(struct i2c_client *client) { struct pm860x_chip *chip = i2c_get_clientdata(client); @@ -1210,7 +1210,6 @@ static int pm860x_remove(struct i2c_client *client) regmap_exit(chip->regmap_companion); i2c_unregister_device(chip->companion); } - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index abb58ab1a1a4..c3dd1fe8d8c9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -963,6 +963,27 @@ config MFD_MENF21BMC This driver can also be built as a module. If so the module will be called menf21bmc. +config MFD_OCELOT + tristate "Microsemi Ocelot External Control Support" + depends on SPI_MASTER + select MFD_CORE + select REGMAP_SPI + help + Ocelot is a family of networking chips that support multiple ethernet + and fibre interfaces. In addition to networking, they contain several + other functions, including pinctrl, MDIO, and communication with + external chips. While some chips have an internal processor capable of + running an OS, others don't. All chips can be controlled externally + through different interfaces, including SPI, I2C, and PCIe. + + Say yes here to add support for Ocelot chips (VSC7511, VSC7512, + VSC7513, VSC7514) controlled externally. + + To compile this driver as a module, choose M here: the module will be + called ocelot-soc. + + If unsure, say N. + config EZX_PCAP bool "Motorola EZXPCAP Support" depends on SPI_MASTER diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 858cacf659d6..0004b7e86220 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -120,6 +120,9 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o obj-$(CONFIG_MFD_CORE) += mfd-core.o +ocelot-soc-objs := ocelot-core.o ocelot-spi.o +obj-$(CONFIG_MFD_OCELOT) += ocelot-soc.o + obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c index 80c2fdd14fc4..7fd8b9988075 100644 --- a/drivers/mfd/acer-ec-a500.c +++ b/drivers/mfd/acer-ec-a500.c @@ -169,7 +169,7 @@ static int a500_ec_probe(struct i2c_client *client) return 0; } -static int a500_ec_remove(struct i2c_client *client) +static void a500_ec_remove(struct i2c_client *client) { if (of_device_is_system_power_controller(client->dev.of_node)) { if (pm_power_off == a500_ec_poweroff) @@ -177,8 +177,6 @@ static int a500_ec_remove(struct i2c_client *client) unregister_restart_handler(&a500_ec_restart_handler); } - - return 0; } static const struct of_device_id a500_ec_match[] = { diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 6d83e6b9a692..bfc7cf56ff2c 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -84,13 +84,11 @@ static int arizona_i2c_probe(struct i2c_client *i2c, return arizona_dev_init(arizona); } -static int arizona_i2c_remove(struct i2c_client *i2c) +static void arizona_i2c_remove(struct i2c_client *i2c) { struct arizona *arizona = dev_get_drvdata(&i2c->dev); arizona_dev_exit(arizona); - - return 0; } static const struct i2c_device_id arizona_i2c_id[] = { diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index 00ab48018d8d..8fd6727dc30a 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -50,13 +50,11 @@ static int axp20x_i2c_probe(struct i2c_client *i2c, return axp20x_device_probe(axp20x); } -static int axp20x_i2c_remove(struct i2c_client *i2c) +static void axp20x_i2c_remove(struct i2c_client *i2c) { struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); axp20x_device_remove(axp20x); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index a818fbb55988..3f8f6ad3a98c 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -532,12 +532,11 @@ static int da903x_probe(struct i2c_client *client, return da903x_add_subdevs(chip, pdata); } -static int da903x_remove(struct i2c_client *client) +static void da903x_remove(struct i2c_client *client) { struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); - return 0; } static struct i2c_driver da903x_driver = { diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 8de93db35f3a..5a74696c8704 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -168,12 +168,11 @@ static int da9052_i2c_probe(struct i2c_client *client, return da9052_device_init(da9052, id->driver_data); } -static int da9052_i2c_remove(struct i2c_client *client) +static void da9052_i2c_remove(struct i2c_client *client) { struct da9052 *da9052 = i2c_get_clientdata(client); da9052_device_exit(da9052); - return 0; } static struct i2c_driver da9052_i2c_driver = { diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index bc60433b68db..276c7d1c509e 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -41,13 +41,11 @@ static int da9055_i2c_probe(struct i2c_client *i2c, return da9055_device_init(da9055); } -static int da9055_i2c_remove(struct i2c_client *i2c) +static void da9055_i2c_remove(struct i2c_client *i2c) { struct da9055 *da9055 = i2c_get_clientdata(i2c); da9055_device_exit(da9055); - - return 0; } /* diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 2774b2cbaea6..0a80d82c6858 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -723,14 +723,12 @@ static int da9062_i2c_probe(struct i2c_client *i2c, return ret; } -static int da9062_i2c_remove(struct i2c_client *i2c) +static void da9062_i2c_remove(struct i2c_client *i2c) { struct da9062 *chip = i2c_get_clientdata(i2c); mfd_remove_devices(chip->dev); regmap_del_irq_chip(i2c->irq, chip->regmap_irq); - - return 0; } static const struct i2c_device_id da9062_i2c_id[] = { diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index 58009c8cb870..6ae56e46d24e 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c @@ -471,15 +471,13 @@ regmap_irq_fail: return ret; } -static int da9150_remove(struct i2c_client *client) +static void da9150_remove(struct i2c_client *client) { struct da9150 *da9150 = i2c_get_clientdata(client); regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); mfd_remove_devices(da9150->dev); i2c_unregister_device(da9150->core_qif); - - return 0; } static void da9150_shutdown(struct i2c_client *client) diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 54fb6cbd2aa0..759c59690680 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -375,11 +375,10 @@ static void dm355evm_power_off(void) dm355evm_command(MSP_COMMAND_POWEROFF); } -static int dm355evm_msp_remove(struct i2c_client *client) +static void dm355evm_msp_remove(struct i2c_client *client) { pm_power_off = NULL; msp430 = NULL; - return 0; } static int diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c index 1b73318d1f1f..3eff98e26bea 100644 --- a/drivers/mfd/ene-kb3930.c +++ b/drivers/mfd/ene-kb3930.c @@ -177,7 +177,7 @@ static int kb3930_probe(struct i2c_client *client) return 0; } -static int kb3930_remove(struct i2c_client *client) +static void kb3930_remove(struct i2c_client *client) { struct kb3930 *ddata = i2c_get_clientdata(client); @@ -187,8 +187,6 @@ static int kb3930_remove(struct i2c_client *client) unregister_restart_handler(&kb3930_restart_nb); } kb3930_power_off = NULL; - - return 0; } static const struct of_device_id kb3930_dt_ids[] = { diff --git a/drivers/mfd/gateworks-gsc.c b/drivers/mfd/gateworks-gsc.c index d87876747b91..9d7d870c44a8 100644 --- a/drivers/mfd/gateworks-gsc.c +++ b/drivers/mfd/gateworks-gsc.c @@ -255,11 +255,9 @@ static int gsc_probe(struct i2c_client *client) return 0; } -static int gsc_remove(struct i2c_client *client) +static void gsc_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &attr_group); - - return 0; } static struct i2c_driver gsc_driver = { diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 5e8c94e008ed..b824e15f4d22 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -81,7 +81,7 @@ err_del_irq_chip: return ret; } -static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) +static void intel_soc_pmic_i2c_remove(struct i2c_client *i2c) { struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev); @@ -91,8 +91,6 @@ static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); mfd_remove_devices(&i2c->dev); - - return 0; } static void intel_soc_pmic_shutdown(struct i2c_client *i2c) diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 575ab67e243d..1895fce25b06 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -1008,13 +1008,11 @@ static int iqs62x_probe(struct i2c_client *client) return ret; } -static int iqs62x_remove(struct i2c_client *client) +static void iqs62x_remove(struct i2c_client *client) { struct iqs62x_core *iqs62x = i2c_get_clientdata(client); wait_for_completion(&iqs62x->fw_done); - - return 0; } static int __maybe_unused iqs62x_suspend(struct device *dev) diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 5690768f3e63..be32ffc5af38 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -607,15 +607,13 @@ static int lm3533_i2c_probe(struct i2c_client *i2c, return lm3533_device_init(lm3533); } -static int lm3533_i2c_remove(struct i2c_client *i2c) +static void lm3533_i2c_remove(struct i2c_client *i2c) { struct lm3533 *lm3533 = i2c_get_clientdata(i2c); dev_dbg(&i2c->dev, "%s\n", __func__); lm3533_device_exit(lm3533); - - return 0; } static const struct i2c_device_id lm3533_i2c_ids[] = { diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index c223d2c6a363..e7c601bca9ef 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -199,13 +199,12 @@ static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); } -static int lp8788_remove(struct i2c_client *cl) +static void lp8788_remove(struct i2c_client *cl) { struct lp8788 *lp = i2c_get_clientdata(cl); mfd_remove_devices(lp->dev); lp8788_irq_exit(lp); - return 0; } static const struct i2c_device_id lp8788_ids[] = { diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c index 7df5b9ba5855..915d2f95bad3 100644 --- a/drivers/mfd/madera-i2c.c +++ b/drivers/mfd/madera-i2c.c @@ -112,13 +112,11 @@ static int madera_i2c_probe(struct i2c_client *i2c, return madera_dev_init(madera); } -static int madera_i2c_remove(struct i2c_client *i2c) +static void madera_i2c_remove(struct i2c_client *i2c) { struct madera *madera = dev_get_drvdata(&i2c->dev); madera_dev_exit(madera); - - return 0; } static const struct i2c_device_id madera_i2c_id[] = { diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 6c487fa14e9c..d44ad6f33742 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -463,7 +463,7 @@ err_max77836: return ret; } -static int max14577_i2c_remove(struct i2c_client *i2c) +static void max14577_i2c_remove(struct i2c_client *i2c) { struct max14577 *max14577 = i2c_get_clientdata(i2c); @@ -471,8 +471,6 @@ static int max14577_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(max14577->irq, max14577->irq_data); if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) max77836_remove(max14577); - - return 0; } static const struct i2c_device_id max14577_i2c_id[] = { diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 4e6244e17559..7088cb6f9174 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -294,7 +294,7 @@ err_i2c_haptic: return ret; } -static int max77693_i2c_remove(struct i2c_client *i2c) +static void max77693_i2c_remove(struct i2c_client *i2c) { struct max77693_dev *max77693 = i2c_get_clientdata(i2c); @@ -307,8 +307,6 @@ static int max77693_i2c_remove(struct i2c_client *i2c) i2c_unregister_device(max77693->i2c_muic); i2c_unregister_device(max77693->i2c_haptic); - - return 0; } static const struct i2c_device_id max77693_i2c_id[] = { diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 41f566e6a096..c340080971ce 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -282,7 +282,7 @@ err_alloc_drvdata: return ret; } -static int max8907_i2c_remove(struct i2c_client *i2c) +static void max8907_i2c_remove(struct i2c_client *i2c) { struct max8907 *max8907 = i2c_get_clientdata(i2c); @@ -293,8 +293,6 @@ static int max8907_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); i2c_unregister_device(max8907->i2c_rtc); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 114e905bef25..04101da42bd3 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -198,14 +198,13 @@ static int max8925_probe(struct i2c_client *client, return 0; } -static int max8925_remove(struct i2c_client *client) +static void max8925_remove(struct i2c_client *client) { struct max8925_chip *chip = i2c_get_clientdata(client); max8925_device_exit(chip); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index fb937f66277e..eb94f3004cf3 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c @@ -85,10 +85,9 @@ static int mc13xxx_i2c_probe(struct i2c_client *client, return mc13xxx_common_init(&client->dev); } -static int mc13xxx_i2c_remove(struct i2c_client *client) +static void mc13xxx_i2c_remove(struct i2c_client *client) { mc13xxx_common_exit(&client->dev); - return 0; } static struct i2c_driver mc13xxx_i2c_driver = { diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 07e0ca2e467c..eb08f69001f9 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1222,14 +1222,13 @@ fail: return err; } -static int menelaus_remove(struct i2c_client *client) +static void menelaus_remove(struct i2c_client *client) { struct menelaus_chip *menelaus = i2c_get_clientdata(client); free_irq(client->irq, menelaus); flush_work(&menelaus->work); the_menelaus = NULL; - return 0; } static const struct i2c_device_id menelaus_id[] = { diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index b711e73eedcb..e16a7a82a929 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -239,15 +239,13 @@ static int ntxec_probe(struct i2c_client *client) return res; } -static int ntxec_remove(struct i2c_client *client) +static void ntxec_remove(struct i2c_client *client) { if (client == poweroff_restart_client) { poweroff_restart_client = NULL; pm_power_off = NULL; unregister_restart_handler(&ntxec_restart_handler); } - - return 0; } static const struct of_device_id of_ntxec_match_table[] = { diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c new file mode 100644 index 000000000000..1816d52c65c5 --- /dev/null +++ b/drivers/mfd/ocelot-core.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Core driver for the Ocelot chip family. + * + * The VSC7511, 7512, 7513, and 7514 can be controlled internally via an + * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is + * intended to be the bus-agnostic glue between, for example, the SPI bus and + * the child devices. + * + * Copyright 2021-2022 Innovative Advantage Inc. + * + * Author: Colin Foster <colin.foster@in-advantage.com> + */ + +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/ocelot.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <soc/mscc/ocelot.h> + +#include "ocelot.h" + +#define REG_GCB_SOFT_RST 0x0008 + +#define BIT_SOFT_CHIP_RST BIT(0) + +#define VSC7512_MIIM0_RES_START 0x7107009c +#define VSC7512_MIIM1_RES_START 0x710700c0 +#define VSC7512_MIIM_RES_SIZE 0x024 + +#define VSC7512_PHY_RES_START 0x710700f0 +#define VSC7512_PHY_RES_SIZE 0x004 + +#define VSC7512_GPIO_RES_START 0x71070034 +#define VSC7512_GPIO_RES_SIZE 0x06c + +#define VSC7512_SIO_CTRL_RES_START 0x710700f8 +#define VSC7512_SIO_CTRL_RES_SIZE 0x100 + +#define VSC7512_GCB_RST_SLEEP_US 100 +#define VSC7512_GCB_RST_TIMEOUT_US 100000 + +static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata) +{ + int val, err; + + err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val); + if (err) + return err; + + return val; +} + +int ocelot_chip_reset(struct device *dev) +{ + struct ocelot_ddata *ddata = dev_get_drvdata(dev); + int ret, val; + + /* + * Reset the entire chip here to put it into a completely known state. + * Other drivers may want to reset their own subsystems. The register + * self-clears, so one write is all that is needed and wait for it to + * clear. + */ + ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST); + if (ret) + return ret; + + return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val, + VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US); +} +EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT); + +static const struct resource vsc7512_miim0_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), + DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"), +}; + +static const struct resource vsc7512_miim1_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"), +}; + +static const struct resource vsc7512_pinctrl_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"), +}; + +static const struct resource vsc7512_sgpio_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"), +}; + +static const struct mfd_cell vsc7512_devs[] = { + { + .name = "ocelot-pinctrl", + .of_compatible = "mscc,ocelot-pinctrl", + .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources), + .resources = vsc7512_pinctrl_resources, + }, { + .name = "ocelot-sgpio", + .of_compatible = "mscc,ocelot-sgpio", + .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources), + .resources = vsc7512_sgpio_resources, + }, { + .name = "ocelot-miim0", + .of_compatible = "mscc,ocelot-miim", + .of_reg = VSC7512_MIIM0_RES_START, + .use_of_reg = true, + .num_resources = ARRAY_SIZE(vsc7512_miim0_resources), + .resources = vsc7512_miim0_resources, + }, { + .name = "ocelot-miim1", + .of_compatible = "mscc,ocelot-miim", + .of_reg = VSC7512_MIIM1_RES_START, + .use_of_reg = true, + .num_resources = ARRAY_SIZE(vsc7512_miim1_resources), + .resources = vsc7512_miim1_resources, + }, +}; + +static void ocelot_core_try_add_regmap(struct device *dev, + const struct resource *res) +{ + if (dev_get_regmap(dev, res->name)) + return; + + ocelot_spi_init_regmap(dev, res); +} + +static void ocelot_core_try_add_regmaps(struct device *dev, + const struct mfd_cell *cell) +{ + int i; + + for (i = 0; i < cell->num_resources; i++) + ocelot_core_try_add_regmap(dev, &cell->resources[i]); +} + +int ocelot_core_init(struct device *dev) +{ + int i, ndevs; + + ndevs = ARRAY_SIZE(vsc7512_devs); + + for (i = 0; i < ndevs; i++) + ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); +} +EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT); + +MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver"); +MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(MFD_OCELOT_SPI); diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c new file mode 100644 index 000000000000..0f097f4829d1 --- /dev/null +++ b/drivers/mfd/ocelot-spi.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * SPI core driver for the Ocelot chip family. + * + * This driver will handle everything necessary to allow for communication over + * SPI to the VSC7511, VSC7512, VSC7513 and VSC7514 chips. The main functions + * are to prepare the chip's SPI interface for a specific bus speed, and a host + * processor's endianness. This will create and distribute regmaps for any + * children. + * + * Copyright 2021-2022 Innovative Advantage Inc. + * + * Author: Colin Foster <colin.foster@in-advantage.com> + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/ioport.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/units.h> + +#include "ocelot.h" + +#define REG_DEV_CPUORG_IF_CTRL 0x0000 +#define REG_DEV_CPUORG_IF_CFGSTAT 0x0004 + +#define CFGSTAT_IF_NUM_VCORE (0 << 24) +#define CFGSTAT_IF_NUM_VRAP (1 << 24) +#define CFGSTAT_IF_NUM_SI (2 << 24) +#define CFGSTAT_IF_NUM_MIIM (3 << 24) + +#define VSC7512_DEVCPU_ORG_RES_START 0x71000000 +#define VSC7512_DEVCPU_ORG_RES_SIZE 0x38 + +#define VSC7512_CHIP_REGS_RES_START 0x71070000 +#define VSC7512_CHIP_REGS_RES_SIZE 0x14 + +static const struct resource vsc7512_dev_cpuorg_resource = + DEFINE_RES_REG_NAMED(VSC7512_DEVCPU_ORG_RES_START, + VSC7512_DEVCPU_ORG_RES_SIZE, + "devcpu_org"); + +static const struct resource vsc7512_gcb_resource = + DEFINE_RES_REG_NAMED(VSC7512_CHIP_REGS_RES_START, + VSC7512_CHIP_REGS_RES_SIZE, + "devcpu_gcb_chip_regs"); + +static int ocelot_spi_initialize(struct device *dev) +{ + struct ocelot_ddata *ddata = dev_get_drvdata(dev); + u32 val, check; + int err; + + val = OCELOT_SPI_BYTE_ORDER; + + /* + * The SPI address must be big-endian, but we want the payload to match + * our CPU. These are two bits (0 and 1) but they're repeated such that + * the write from any configuration will be valid. The four + * configurations are: + * + * 0b00: little-endian, MSB first + * | 111111 | 22221111 | 33222222 | + * | 76543210 | 54321098 | 32109876 | 10987654 | + * + * 0b01: big-endian, MSB first + * | 33222222 | 22221111 | 111111 | | + * | 10987654 | 32109876 | 54321098 | 76543210 | + * + * 0b10: little-endian, LSB first + * | 111111 | 11112222 | 22222233 | + * | 01234567 | 89012345 | 67890123 | 45678901 | + * + * 0b11: big-endian, LSB first + * | 22222233 | 11112222 | 111111 | | + * | 45678901 | 67890123 | 89012345 | 01234567 | + */ + err = regmap_write(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CTRL, val); + if (err) + return err; + + /* + * Apply the number of padding bytes between a read request and the data + * payload. Some registers have access times of up to 1us, so if the + * first payload bit is shifted out too quickly, the read will fail. + */ + val = ddata->spi_padding_bytes; + err = regmap_write(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CFGSTAT, val); + if (err) + return err; + + /* + * After we write the interface configuration, read it back here. This + * will verify several different things. The first is that the number of + * padding bytes actually got written correctly. These are found in bits + * 0:3. + * + * The second is that bit 16 is cleared. Bit 16 is IF_CFGSTAT:IF_STAT, + * and will be set if the register access is too fast. This would be in + * the condition that the number of padding bytes is insufficient for + * the SPI bus frequency. + * + * The last check is for bits 31:24, which define the interface by which + * the registers are being accessed. Since we're accessing them via the + * serial interface, it must return IF_NUM_SI. + */ + check = val | CFGSTAT_IF_NUM_SI; + + err = regmap_read(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CFGSTAT, &val); + if (err) + return err; + + if (check != val) + return -ENODEV; + + return 0; +} + +static const struct regmap_config ocelot_spi_regmap_config = { + .reg_bits = 24, + .reg_stride = 4, + .reg_downshift = 2, + .val_bits = 32, + + .write_flag_mask = 0x80, + + .use_single_write = true, + .can_multi_write = false, + + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_NATIVE, +}; + +static int ocelot_spi_regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct spi_transfer xfers[3] = {0}; + struct device *dev = context; + struct ocelot_ddata *ddata; + struct spi_device *spi; + struct spi_message msg; + unsigned int index = 0; + + ddata = dev_get_drvdata(dev); + spi = to_spi_device(dev); + + xfers[index].tx_buf = reg; + xfers[index].len = reg_size; + index++; + + if (ddata->spi_padding_bytes) { + xfers[index].len = ddata->spi_padding_bytes; + xfers[index].tx_buf = ddata->dummy_buf; + xfers[index].dummy_data = 1; + index++; + } + + xfers[index].rx_buf = val; + xfers[index].len = val_size; + index++; + + spi_message_init_with_transfers(&msg, xfers, index); + + return spi_sync(spi, &msg); +} + +static int ocelot_spi_regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + + return spi_write(spi, data, count); +} + +static const struct regmap_bus ocelot_spi_regmap_bus = { + .write = ocelot_spi_regmap_bus_write, + .read = ocelot_spi_regmap_bus_read, +}; + +struct regmap *ocelot_spi_init_regmap(struct device *dev, const struct resource *res) +{ + struct regmap_config regmap_config; + + memcpy(®map_config, &ocelot_spi_regmap_config, sizeof(regmap_config)); + + regmap_config.name = res->name; + regmap_config.max_register = resource_size(res) - 1; + regmap_config.reg_base = res->start; + + return devm_regmap_init(dev, &ocelot_spi_regmap_bus, dev, ®map_config); +} +EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, MFD_OCELOT_SPI); + +static int ocelot_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ocelot_ddata *ddata; + struct regmap *r; + int err; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + spi_set_drvdata(spi, ddata); + + if (spi->max_speed_hz <= 500000) { + ddata->spi_padding_bytes = 0; + } else { + /* + * Calculation taken from the manual for IF_CFGSTAT:IF_CFG. + * Register access time is 1us, so we need to configure and send + * out enough padding bytes between the read request and data + * transmission that lasts at least 1 microsecond. + */ + ddata->spi_padding_bytes = 1 + (spi->max_speed_hz / HZ_PER_MHZ + 2) / 8; + + ddata->dummy_buf = devm_kzalloc(dev, ddata->spi_padding_bytes, GFP_KERNEL); + if (!ddata->dummy_buf) + return -ENOMEM; + } + + spi->bits_per_word = 8; + + err = spi_setup(spi); + if (err) + return dev_err_probe(&spi->dev, err, "Error performing SPI setup\n"); + + r = ocelot_spi_init_regmap(dev, &vsc7512_dev_cpuorg_resource); + if (IS_ERR(r)) + return PTR_ERR(r); + + ddata->cpuorg_regmap = r; + + r = ocelot_spi_init_regmap(dev, &vsc7512_gcb_resource); + if (IS_ERR(r)) + return PTR_ERR(r); + + ddata->gcb_regmap = r; + + /* + * The chip must be set up for SPI before it gets initialized and reset. + * This must be done before calling init, and after a chip reset is + * performed. + */ + err = ocelot_spi_initialize(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing SPI bus\n"); + + err = ocelot_chip_reset(dev); + if (err) + return dev_err_probe(dev, err, "Error resetting device\n"); + + /* + * A chip reset will clear the SPI configuration, so it needs to be done + * again before we can access any registers. + */ + err = ocelot_spi_initialize(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing SPI bus after reset\n"); + + err = ocelot_core_init(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing Ocelot core\n"); + + return 0; +} + +static const struct spi_device_id ocelot_spi_ids[] = { + { "vsc7512", 0 }, + { } +}; + +static const struct of_device_id ocelot_spi_of_match[] = { + { .compatible = "mscc,vsc7512" }, + { } +}; +MODULE_DEVICE_TABLE(of, ocelot_spi_of_match); + +static struct spi_driver ocelot_spi_driver = { + .driver = { + .name = "ocelot-soc", + .of_match_table = ocelot_spi_of_match, + }, + .id_table = ocelot_spi_ids, + .probe = ocelot_spi_probe, +}; +module_spi_driver(ocelot_spi_driver); + +MODULE_DESCRIPTION("SPI Controlled Ocelot Chip Driver"); +MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_IMPORT_NS(MFD_OCELOT); diff --git a/drivers/mfd/ocelot.h b/drivers/mfd/ocelot.h new file mode 100644 index 000000000000..b8bc2f1486e2 --- /dev/null +++ b/drivers/mfd/ocelot.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* Copyright 2021, 2022 Innovative Advantage Inc. */ + +#ifndef _MFD_OCELOT_H +#define _MFD_OCELOT_H + +#include <linux/kconfig.h> + +struct device; +struct regmap; +struct resource; + +/** + * struct ocelot_ddata - Private data for an external Ocelot chip + * @gcb_regmap: General Configuration Block regmap. Used for + * operations like chip reset. + * @cpuorg_regmap: CPU Device Origin Block regmap. Used for operations + * like SPI bus configuration. + * @spi_padding_bytes: Number of padding bytes that must be thrown out before + * read data gets returned. This is calculated during + * initialization based on bus speed. + * @dummy_buf: Zero-filled buffer of spi_padding_bytes size. The dummy + * bytes that will be sent out between the address and + * data of a SPI read operation. + */ +struct ocelot_ddata { + struct regmap *gcb_regmap; + struct regmap *cpuorg_regmap; + int spi_padding_bytes; + void *dummy_buf; +}; + +int ocelot_chip_reset(struct device *dev); +int ocelot_core_init(struct device *dev); + +/* SPI-specific routines that won't be necessary for other interfaces */ +struct regmap *ocelot_spi_init_regmap(struct device *dev, + const struct resource *res); + +#define OCELOT_SPI_BYTE_ORDER_LE 0x00000000 +#define OCELOT_SPI_BYTE_ORDER_BE 0x81818181 + +#ifdef __LITTLE_ENDIAN +#define OCELOT_SPI_BYTE_ORDER OCELOT_SPI_BYTE_ORDER_LE +#else +#define OCELOT_SPI_BYTE_ORDER OCELOT_SPI_BYTE_ORDER_BE +#endif + +#endif diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index f5b3fa973b13..8b7429bd2e3e 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -700,7 +700,7 @@ err_i2c: return ret; } -static int palmas_i2c_remove(struct i2c_client *i2c) +static void palmas_i2c_remove(struct i2c_client *i2c) { struct palmas *palmas = i2c_get_clientdata(i2c); int i; @@ -716,8 +716,6 @@ static int palmas_i2c_remove(struct i2c_client *i2c) pm_power_off = NULL; palmas_dev = NULL; } - - return 0; } static const struct i2c_device_id palmas_i2c_id[] = { diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index e9c565cf0f54..4ccc2c3e7681 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -273,7 +273,7 @@ err2: return ret; } -static int pcf50633_remove(struct i2c_client *client) +static void pcf50633_remove(struct i2c_client *client) { struct pcf50633 *pcf = i2c_get_clientdata(client); int i; @@ -289,8 +289,6 @@ static int pcf50633_remove(struct i2c_client *client) for (i = 0; i < PCF50633_NUM_REGULATORS; i++) platform_device_unregister(pcf->regulator_pdev[i]); - - return 0; } static const struct i2c_device_id pcf50633_id_table[] = { diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index c748fd29a220..3b5acf7ca39c 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -287,7 +287,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return 0; } -static int retu_remove(struct i2c_client *i2c) +static void retu_remove(struct i2c_client *i2c) { struct retu_dev *rdev = i2c_get_clientdata(i2c); @@ -297,8 +297,6 @@ static int retu_remove(struct i2c_client *i2c) } mfd_remove_devices(rdev->dev); regmap_del_irq_chip(i2c->irq, rdev->irq_data); - - return 0; } static const struct i2c_device_id retu_id[] = { diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 4142b638e5fa..d5d641efa077 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -778,7 +778,7 @@ err_irq: return ret; } -static int rk808_remove(struct i2c_client *client) +static void rk808_remove(struct i2c_client *client) { struct rk808 *rk808 = i2c_get_clientdata(client); @@ -792,8 +792,6 @@ static int rk808_remove(struct i2c_client *client) pm_power_off = NULL; unregister_restart_handler(&rk808_restart_handler); - - return 0; } static int __maybe_unused rk8xx_suspend(struct device *dev) diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 384acb459427..eb8005b4e58d 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -241,7 +241,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c) return rn5t618_irq_init(priv); } -static int rn5t618_i2c_remove(struct i2c_client *i2c) +static void rn5t618_i2c_remove(struct i2c_client *i2c) { if (i2c == rn5t618_pm_power_off) { rn5t618_pm_power_off = NULL; @@ -249,8 +249,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) } unregister_restart_handler(&rn5t618_restart_handler); - - return 0; } static int __maybe_unused rn5t618_i2c_suspend(struct device *dev) diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index dc001c9791c1..f716ab8039a0 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -146,13 +146,11 @@ static int rsmu_i2c_probe(struct i2c_client *client, return rsmu_core_init(rsmu); } -static int rsmu_i2c_remove(struct i2c_client *client) +static void rsmu_i2c_remove(struct i2c_client *client) { struct rsmu_ddata *rsmu = i2c_get_clientdata(client); rsmu_core_exit(rsmu); - - return 0; } static const struct i2c_device_id rsmu_i2c_id[] = { diff --git a/drivers/mfd/rt4831.c b/drivers/mfd/rt4831.c index fb3bd788a3eb..c6d34dc2b520 100644 --- a/drivers/mfd/rt4831.c +++ b/drivers/mfd/rt4831.c @@ -87,7 +87,7 @@ static int rt4831_probe(struct i2c_client *client) ARRAY_SIZE(rt4831_subdevs), NULL, 0, NULL); } -static int rt4831_remove(struct i2c_client *client) +static void rt4831_remove(struct i2c_client *client) { struct regmap *regmap = dev_get_regmap(&client->dev, NULL); int ret; @@ -96,8 +96,6 @@ static int rt4831_remove(struct i2c_client *client) 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)); - - return 0; } static const struct of_device_id __maybe_unused rt4831_of_match[] = { diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index a2635c2d9d1a..8166949b725c 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -835,7 +835,7 @@ free_gpio: return rval; } -static int si476x_core_remove(struct i2c_client *client) +static void si476x_core_remove(struct i2c_client *client) { struct si476x_core *core = i2c_get_clientdata(client); @@ -851,8 +851,6 @@ static int si476x_core_remove(struct i2c_client *client) if (gpio_is_valid(core->gpio_reset)) gpio_free(core->gpio_reset); - - return 0; } diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index 122f96094410..5dd7d9688459 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -467,13 +467,11 @@ err_chip_exit: return ret; } -static int stmfx_remove(struct i2c_client *client) +static void stmfx_remove(struct i2c_client *client) { stmfx_irq_exit(client); stmfx_chip_exit(client); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index d3eedf3d607e..4d55494a97c4 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -91,13 +91,11 @@ stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return stmpe_probe(&i2c_ci, partnum); } -static int stmpe_i2c_remove(struct i2c_client *i2c) +static void stmpe_i2c_remove(struct i2c_client *i2c) { struct stmpe *stmpe = dev_get_drvdata(&i2c->dev); stmpe_remove(stmpe); - - return 0; } static const struct i2c_device_id stmpe_i2c_id[] = { diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 13583cdb93b6..d5d0ec117acb 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -429,13 +429,11 @@ static int tc3589x_probe(struct i2c_client *i2c, return 0; } -static int tc3589x_remove(struct i2c_client *client) +static void tc3589x_remove(struct i2c_client *client) { struct tc3589x *tc3589x = i2c_get_clientdata(client); mfd_remove_devices(tc3589x->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index c906324d293e..b360568ea675 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -179,7 +179,7 @@ static int tps6105x_probe(struct i2c_client *client, return ret; } -static int tps6105x_remove(struct i2c_client *client) +static void tps6105x_remove(struct i2c_client *client) { struct tps6105x *tps6105x = i2c_get_clientdata(client); @@ -189,8 +189,6 @@ static int tps6105x_remove(struct i2c_client *client) regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_MODE_MASK, TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); - - return 0; } static const struct i2c_device_id tps6105x_id[] = { diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 7e7dbee58ca9..c2afa2e69f42 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -501,7 +501,7 @@ static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset) static struct tps65010 *the_tps; -static int tps65010_remove(struct i2c_client *client) +static void tps65010_remove(struct i2c_client *client) { struct tps65010 *tps = i2c_get_clientdata(client); struct tps65010_board *board = dev_get_platdata(&client->dev); @@ -517,7 +517,6 @@ static int tps65010_remove(struct i2c_client *client) cancel_delayed_work_sync(&tps->work); debugfs_remove(tps->file); the_tps = NULL; - return 0; } static int tps65010_probe(struct i2c_client *client, diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index cbae9777a24e..81a7360a87bb 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -111,14 +111,12 @@ static int tps65086_probe(struct i2c_client *client, return ret; } -static int tps65086_remove(struct i2c_client *client) +static void tps65086_remove(struct i2c_client *client) { struct tps65086 *tps = i2c_get_clientdata(client); if (tps->irq > 0) regmap_del_irq_chip(tps->irq, tps->irq_data); - - return 0; } static const struct i2c_device_id tps65086_id_table[] = { diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 8e8da204a02e..eebd60601b01 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -374,7 +374,7 @@ static int tps65217_probe(struct i2c_client *client) return 0; } -static int tps65217_remove(struct i2c_client *client) +static void tps65217_remove(struct i2c_client *client) { struct tps65217 *tps = i2c_get_clientdata(client); unsigned int virq; @@ -388,8 +388,6 @@ static int tps65217_remove(struct i2c_client *client) irq_domain_remove(tps->irq_domain); tps->irq_domain = NULL; - - return 0; } static const struct i2c_device_id tps65217_id_table[] = { diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index c9303d3d6602..fb340da64bbc 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -579,7 +579,7 @@ err_mfd_add: return ret; } -static int tps6586x_i2c_remove(struct i2c_client *client) +static void tps6586x_i2c_remove(struct i2c_client *client) { struct tps6586x *tps6586x = i2c_get_clientdata(client); @@ -587,7 +587,6 @@ static int tps6586x_i2c_remove(struct i2c_client *client) mfd_remove_devices(tps6586x->dev); if (client->irq) free_irq(client->irq, tps6586x); - return 0; } static int __maybe_unused tps6586x_i2c_suspend(struct device *dev) diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index afb7f7d97dc0..7e2b19efe867 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -43,13 +43,11 @@ static int tps65912_i2c_probe(struct i2c_client *client, return tps65912_device_init(tps); } -static int tps65912_i2c_remove(struct i2c_client *client) +static void tps65912_i2c_remove(struct i2c_client *client) { struct tps65912 *tps = i2c_get_clientdata(client); tps65912_device_exit(tps); - - return 0; } static const struct i2c_device_id tps65912_i2c_id_table[] = { diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 2cb9326f3e61..2679c41232e6 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -727,7 +727,7 @@ static void clocks_init(struct device *dev) /*----------------------------------------------------------------------*/ -static int twl_remove(struct i2c_client *client) +static void twl_remove(struct i2c_client *client) { unsigned i, num_slaves; @@ -745,7 +745,6 @@ static int twl_remove(struct i2c_client *client) twl->client = NULL; } twl_priv->ready = false; - return 0; } static struct of_dev_auxdata twl_auxdata_lookup[] = { diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index b9c6d94b4002..f429b8f00db6 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -808,7 +808,7 @@ gpio_err: return ret; } -static int twl6040_remove(struct i2c_client *client) +static void twl6040_remove(struct i2c_client *client) { struct twl6040 *twl6040 = i2c_get_clientdata(client); @@ -820,8 +820,6 @@ static int twl6040_remove(struct i2c_client *client) mfd_remove_devices(&client->dev); regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); - - return 0; } static const struct i2c_device_id twl6040_i2c_id[] = { diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 7b1d270722ba..7e88f5b0abe6 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -657,13 +657,11 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, return wm8994_device_init(wm8994, i2c->irq); } -static int wm8994_i2c_remove(struct i2c_client *i2c) +static void wm8994_i2c_remove(struct i2c_client *i2c) { struct wm8994 *wm8994 = i2c_get_clientdata(i2c); wm8994_device_exit(wm8994); - - return 0; } static const struct i2c_device_id wm8994_i2c_id[] = { |