* [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller
@ 2023-01-03 7:00 Binbin Zhou
2023-01-03 7:00 ` [PATCH V9 1/4] i2c: gpio: Add support on ACPI-based system Binbin Zhou
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Binbin Zhou @ 2023-01-03 7:00 UTC (permalink / raw)
To: Wolfram Sang, Wolfram Sang, Andy Shevchenko, Mika Westerberg,
linux-i2c
Cc: loongarch, devicetree, Huacai Chen, WANG Xuerui, Andy Shevchenko,
Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv,
Binbin Zhou
Hi all:
This patch series adds support for the I2C module found on various
Loongson systems with the Loongson-2K SoC or the Loongson LS7A bridge chip.
For now, the I2C driver is suitable for DT-based or ACPI-based systems.
I have tested on Loongson-3A5000LA+LS7A1000/LS7A2000, Loongson-2K1000LA
and Loongson-2K0500.
Thanks.
Changes since V8:
- patch (3/4)
- Refactor the error handling process of the ls2x_i2c_xfer_one();
- Split comment and code.
Changes since V7:
- patch (3/4)
- I2C_LS2X should be added to the Kconfig/Makefile in Latin
alphabetical order.
- To avoid repeated type conversions, 'struct ls2x_i2c_priv *priv'
replaces 'struct i2c_adapter *adap' as a function parameter, e.g.
ls2x_i2c_start();
- Refactor ls2x_i2c_stop() with readb_poll_timeout(), mainly with
LS2X_SR_BUSY to indicate the status (success/timeout) of the stop
command;
- Remove extra parentheses;
- For consistency, the variable 'r' in ls2x_i2c_probe() is renamed to
'ret'.
Changes since V6:
- patch (1/4)
- Add Reviewed-by tag.
- patch (3/4)
- GPL-2.0 -> GPL-2.0-only;
- Add property.h;
- writew() should be used to operate I2C_LS2X_PRER, and drop the
suffix of I2C_LS2X_PRER_LO/I2C_LS2X_PRER_HI;
- Drop ls2x_i2c_priv->dev, for it can be completely replaced by
'adapter.dev.parent';
- Reasonable return value handling in ls2x_i2c_xfer_one();
- Dropping the I2C_M_STOP flag judgment, the stop parameter of
ls2x_i2c_xfer_one() represents the last msg;
- Add comments for subsys_initcall();
- Code formatting, such as dropping unnecessary blank lines.
Changes since V5:
- patch (1/4)
- Add property.h.
- patch (3/4)
- Put the ls2x_i2c_reginit() in front of irq requst;
- Refact ls2x_i2c_adjust_bus_speed: discard the magic value of
the divider register and LS2X_I2C_FREQ_STD is used to calculate
the frequency;
- Drop useless parameters: priv->suspended, and also disable I2C
interrupts during suspend;
- Drop ls2x_i2c_remove(), for the adapter will be auto deleted on
driver detach;
- Drop MODULE_ALIAS;
- Code formatting, such as alignment.
Thanks Andy for your comments.
Changes since V4:
- patch (1/4)
- Drop unneeded headers: of.h;
- xxx_props -> xxx_properties.
- patch (2/4)
- Add interrupt headers to fix syntax error found by Rob.
- patch (3/4)
- Drop atmoic loop in ls2x_i2c_master_xfer(), I have tested it on the
appropriate environment with no problems;
- Define the corresponding bits in I2C_LS2X_CTR to avoid magic
numbers;
- dev_get_drvdata() is used to get ls2x_i2c_priv() in
ls2x_i2c_suspend();
- i2c_add_adapter() -> devm_i2c_add_adapter();
- SET_SYSTEM_SLEEP_PM_OPS() -> DEFINE_RUNTIME_DEV_PM_OPS();
- Code formatting, such as alignment.
Details: https://lore.kernel.org/all/Y4e%2F6KewuHjAluSZ@smile.fi.intel.com/
Changes since V3:
- Addressed all review comments from v3
- Change the changelog text to make it clearer (1/5);
- Fix some minor bugs, such as formatting issues (2/5);
- Fix some formatting issues (3/5);
- Deep refactoring of code for clarity (4/5).
Details: https://lore.kernel.org/all/Y4S2cnlAm3YYvZ8E@smile.fi.intel.com/
Thanks to all for their suggestions.
Changes since V2:
- Addressed all review comments from v2
- Drop of_match_ptr() in i2c-gpio to avoid potential unused warnings
(1/5);
- Introduce i2c_gpio_get_props() function as the generic interface
to get i2c-gpio props from DT or ACPI table (2/5);
- Refact ls2x i2c code, similar to removing excessive goto tags (4/5).
Thanks to Andy and Mika for their suggestions.
Changes since V1:
- Remove the function of getting the static i2c bus number from ACPI "_UID";
- Fix build warning from kernel test robot.
Binbin Zhou (4):
i2c: gpio: Add support on ACPI-based system
dt-bindings: i2c: add Loongson LS2X I2C controller
i2c: ls2x: Add driver for Loongson-2K/LS7A I2C controller
LoongArch: Enable LS2X I2C in loongson3_defconfig
.../bindings/i2c/loongson,ls2x-i2c.yaml | 51 +++
arch/loongarch/configs/loongson3_defconfig | 1 +
drivers/i2c/busses/Kconfig | 11 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-gpio.c | 28 +-
drivers/i2c/busses/i2c-ls2x.c | 381 ++++++++++++++++++
6 files changed, 463 insertions(+), 10 deletions(-)
create mode 100644 Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
create mode 100644 drivers/i2c/busses/i2c-ls2x.c
--
2.31.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH V9 1/4] i2c: gpio: Add support on ACPI-based system 2023-01-03 7:00 [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller Binbin Zhou @ 2023-01-03 7:00 ` Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 2/4] dt-bindings: i2c: Add Loongson LS2X I2C controller Binbin Zhou ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Binbin Zhou @ 2023-01-03 7:00 UTC (permalink / raw) To: Wolfram Sang, Wolfram Sang, Andy Shevchenko, Mika Westerberg, linux-i2c Cc: loongarch, devicetree, Huacai Chen, WANG Xuerui, Andy Shevchenko, Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv, Binbin Zhou Add support for the ACPI-based device registration, so that the driver can be also enabled through ACPI table. Reviewed-by: Andy Shevchenko <andy@kernel.org> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> --- drivers/i2c/busses/i2c-gpio.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 0e4385a9bcf7..680936234ef8 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -13,9 +13,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_data/i2c-gpio.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/slab.h> struct i2c_gpio_private_data { @@ -300,22 +300,23 @@ static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} #endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ -static void of_i2c_gpio_get_props(struct device_node *np, - struct i2c_gpio_platform_data *pdata) +/* Get i2c-gpio properties from DT or ACPI table */ +static void i2c_gpio_get_properties(struct device *dev, + struct i2c_gpio_platform_data *pdata) { u32 reg; - of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); + device_property_read_u32(dev, "i2c-gpio,delay-us", &pdata->udelay); - if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) + if (!device_property_read_u32(dev, "i2c-gpio,timeout-ms", ®)) pdata->timeout = msecs_to_jiffies(reg); pdata->sda_is_open_drain = - of_property_read_bool(np, "i2c-gpio,sda-open-drain"); + device_property_read_bool(dev, "i2c-gpio,sda-open-drain"); pdata->scl_is_open_drain = - of_property_read_bool(np, "i2c-gpio,scl-open-drain"); + device_property_read_bool(dev, "i2c-gpio,scl-open-drain"); pdata->scl_is_output_only = - of_property_read_bool(np, "i2c-gpio,scl-output-only"); + device_property_read_bool(dev, "i2c-gpio,scl-output-only"); } static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, @@ -373,8 +374,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) bit_data = &priv->bit_data; pdata = &priv->pdata; - if (np) { - of_i2c_gpio_get_props(np, pdata); + if (dev_fwnode(dev)) { + i2c_gpio_get_properties(dev, pdata); } else { /* * If all platform data settings are zero it is OK @@ -489,10 +490,17 @@ static const struct of_device_id i2c_gpio_dt_ids[] = { MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); +static const struct acpi_device_id i2c_gpio_acpi_match[] = { + { "LOON0005" }, /* LoongArch */ + { } +}; +MODULE_DEVICE_TABLE(acpi, i2c_gpio_acpi_match); + static struct platform_driver i2c_gpio_driver = { .driver = { .name = "i2c-gpio", .of_match_table = i2c_gpio_dt_ids, + .acpi_match_table = i2c_gpio_acpi_match, }, .probe = i2c_gpio_probe, .remove = i2c_gpio_remove, -- 2.31.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH V9 2/4] dt-bindings: i2c: Add Loongson LS2X I2C controller 2023-01-03 7:00 [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 1/4] i2c: gpio: Add support on ACPI-based system Binbin Zhou @ 2023-01-03 7:00 ` Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A " Binbin Zhou 2023-01-03 7:01 ` [PATCH V9 4/4] LoongArch: Enable LS2X I2C in loongson3_defconfig Binbin Zhou 3 siblings, 0 replies; 6+ messages in thread From: Binbin Zhou @ 2023-01-03 7:00 UTC (permalink / raw) To: Wolfram Sang, Wolfram Sang, Andy Shevchenko, Mika Westerberg, linux-i2c Cc: loongarch, devicetree, Huacai Chen, WANG Xuerui, Andy Shevchenko, Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv, Binbin Zhou, Krzysztof Kozlowski Add Loongson LS2X I2C controller binding with DT schema format using json-schema. Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> --- .../bindings/i2c/loongson,ls2x-i2c.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml diff --git a/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml new file mode 100644 index 000000000000..67882ec6e06a --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/loongson,ls2x-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson LS2X I2C Controller + +maintainers: + - Binbin Zhou <zhoubinbin@loongson.cn> + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + enum: + - loongson,ls2k-i2c + - loongson,ls7a-i2c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + i2c0: i2c@1fe21000 { + compatible = "loongson,ls2k-i2c"; + reg = <0x1fe21000 0x8>; + interrupt-parent = <&extioiic>; + interrupts = <22 IRQ_TYPE_LEVEL_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@57 { + compatible = "atmel,24c16"; + reg = <0x57>; + pagesize = <16>; + }; + }; -- 2.31.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A I2C controller 2023-01-03 7:00 [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 1/4] i2c: gpio: Add support on ACPI-based system Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 2/4] dt-bindings: i2c: Add Loongson LS2X I2C controller Binbin Zhou @ 2023-01-03 7:00 ` Binbin Zhou 2023-01-03 12:12 ` Andy Shevchenko 2023-01-03 7:01 ` [PATCH V9 4/4] LoongArch: Enable LS2X I2C in loongson3_defconfig Binbin Zhou 3 siblings, 1 reply; 6+ messages in thread From: Binbin Zhou @ 2023-01-03 7:00 UTC (permalink / raw) To: Wolfram Sang, Wolfram Sang, Andy Shevchenko, Mika Westerberg, linux-i2c Cc: loongarch, devicetree, Huacai Chen, WANG Xuerui, Andy Shevchenko, Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv, Binbin Zhou This I2C module is integrated into the Loongson-2K SoCs and Loongson LS7A bridge chip. Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> --- drivers/i2c/busses/Kconfig | 11 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-ls2x.c | 381 ++++++++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 drivers/i2c/busses/i2c-ls2x.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index e50f9603d189..d80c938142f5 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -761,6 +761,17 @@ config I2C_LPC2K This driver can also be built as a module. If so, the module will be called i2c-lpc2k. +config I2C_LS2X + tristate "Loongson LS2X I2C adapter" + depends on MACH_LOONGSON64 || COMPILE_TEST + help + If you say yes to this option, support will be included for the + I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge + chip. + + This driver can also be built as a module. If so, the module + will be called i2c-ls2x. + config I2C_MLXBF tristate "Mellanox BlueField I2C controller" depends on MELLANOX_PLATFORM && ARM64 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e73cdb1d2b5a..0584fe160824 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o +obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c new file mode 100644 index 000000000000..2215aa04233b --- /dev/null +++ b/drivers/i2c/busses/i2c-ls2x.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Loongson-2K/Loongson LS7A I2C master mode driver + * + * Copyright (C) 2013 Loongson Technology Corporation Limited. + * Copyright (C) 2014-2017 Lemote, Inc. + * Copyright (C) 2018-2022 Loongson Technology Corporation Limited. + * + * Originally written by liushaozong + * Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn> + */ + +#include <linux/bits.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/iopoll.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/units.h> + +/* I2C Registers */ +#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */ +#define I2C_LS2X_CTR 0x2 /* Control Register */ +#define I2C_LS2X_TXR 0x3 /* Transport Data Register */ +#define I2C_LS2X_RXR 0x3 /* Receive Data Register */ +#define I2C_LS2X_CR 0x4 /* Command Control Register */ +#define I2C_LS2X_SR 0x4 /* State Register */ + +/* Command Control Register Bit */ +#define LS2X_CR_START BIT(7) /* Start signal */ +#define LS2X_CR_STOP BIT(6) /* Stop signal */ +#define LS2X_CR_READ BIT(5) /* Read signal */ +#define LS2X_CR_WRITE BIT(4) /* Write signal */ +#define LS2X_CR_ACK BIT(3) /* Response signal */ +#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */ + +/* State Register Bit */ +#define LS2X_SR_NOACK BIT(7) /* Receive NACK */ +#define LS2X_SR_BUSY BIT(6) /* Bus busy state */ +#define LS2X_SR_AL BIT(5) /* Arbitration lost */ +#define LS2X_SR_TIP BIT(1) /* Transmission state */ +#define LS2X_SR_IF BIT(0) /* Interrupt flag */ + +/* Control Register Bit */ +#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */ +#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */ +#define LS2X_CTR_MST BIT(5) /* 0: Slave mode 1: Master mode */ +#define CTR_FREQ_MASK GENMASK(7, 6) +#define CTR_READY_MASK GENMASK(7, 5) + +/* The PCLK frequency from LPB */ +#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ) + +/* The default bus frequency, which is an empirical value */ +#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ) + +struct ls2x_i2c_priv { + struct i2c_adapter adapter; + void __iomem *base; + struct i2c_timings i2c_t; + struct completion cmd_complete; +}; + +/* + * Interrupt service routine. + * This gets called whenever an I2C interrupt occurs. + */ +static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id) +{ + struct ls2x_i2c_priv *priv = dev_id; + + if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF)) + return IRQ_NONE; + + writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR); + complete(&priv->cmd_complete); + return IRQ_HANDLED; +} + +/* + * The ls2x i2c controller supports standard mode and fast mode, so the + * maximum bus frequency is '400kHz'. + * The bus frequency is set to the empirical value of '33KHz' by default, + * but it can also be taken from ACPI or FDT for compatibility with more + * devices. + */ +static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) +{ + struct i2c_timings *t = &priv->i2c_t; + struct device *dev = priv->adapter.dev.parent; + u32 acpi_speed = i2c_acpi_find_bus_speed(dev); + + i2c_parse_fw_timings(dev, t, false); + + if (acpi_speed || t->bus_freq_hz) + t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); + else + t->bus_freq_hz = LS2X_I2C_FREQ_STD; + + /* Calculate and set i2c frequency. */ + writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1, + priv->base + I2C_LS2X_PRER); +} + +static void ls2x_i2c_init(struct ls2x_i2c_priv *priv) +{ + /* Set i2c frequency setting mode and disable interrupts. */ + writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK, + priv->base + I2C_LS2X_CTR); + + ls2x_i2c_adjust_bus_speed(priv); + + /* Set i2c normal operating mode and enable interrupts. */ + writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK, + priv->base + I2C_LS2X_CTR); +} + +static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap) +{ + u8 rxdata; + unsigned long time_left; + + writeb(txdata, priv->base + I2C_LS2X_CR); + + time_left = wait_for_completion_timeout(&priv->cmd_complete, + priv->adapter.timeout); + if (!time_left) + return -ETIMEDOUT; + + rxdata = readb(priv->base + I2C_LS2X_SR); + if (rxdatap) + *rxdatap = rxdata; + + return 0; +} + +static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata) +{ + int ret; + u8 rxdata; + + ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata); + if (ret) + return ret; + + if (rxdata & LS2X_SR_AL) + return -EAGAIN; + + if (rxdata & LS2X_SR_NOACK) + return -ENXIO; + + return 0; +} + +static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv) +{ + u8 value; + + writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR); + return readb_poll_timeout(priv->base + I2C_LS2X_SR, value, + !(value & LS2X_SR_BUSY), 100, + jiffies_to_usecs(priv->adapter.timeout)); +} + +static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs) +{ + reinit_completion(&priv->cmd_complete); + + writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR); + return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE); +} + +static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) +{ + int ret; + u8 rxdata, *buf = msg->buf; + u16 len = msg->len; + + /* Contains steps to send start condition and address. */ + ret = ls2x_i2c_start(priv, msg); + if (ret) + return ret; + + while (len--) { + ret = ls2x_i2c_xfer_byte(priv, + LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK), + &rxdata); + if (ret) + return ret; + + *buf++ = readb(priv->base + I2C_LS2X_RXR); + } + + return 0; +} + +static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) +{ + int ret; + u8 *buf = msg->buf; + u16 len = msg->len; + + /* Contains steps to send start condition and address. */ + ret = ls2x_i2c_start(priv, msg); + if (ret) + return ret; + + while (len--) { + writeb(*buf++, priv->base + I2C_LS2X_TXR); + + ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE); + if (ret) + return ret; + } + + return 0; +} + +static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv, + struct i2c_msg *msg, bool stop) +{ + int ret; + + if (msg->flags & I2C_M_RD) + ret = ls2x_i2c_rx(priv, msg); + else + ret = ls2x_i2c_tx(priv, msg); + + if (ret < 0) { + /* Fatel error. Needs reinit. */ + if (ret == -ETIMEDOUT) + ls2x_i2c_init(priv); + + return ret; + } + + if (stop) { + /* Failed to issue STOP. Needs reinit. */ + ret = ls2x_i2c_stop(priv); + if (ret) + ls2x_i2c_init(priv); + } + + return ret; +} + +static int ls2x_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + int ret; + struct i2c_msg *msg, *emsg = msgs + num; + struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap); + + for (msg = msgs; msg < emsg; msg++) { + ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1); + if (ret) + return ret; + } + + return num; +} + +static unsigned int ls2x_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ls2x_i2c_algo = { + .master_xfer = ls2x_i2c_master_xfer, + .functionality = ls2x_i2c_func, +}; + +static int ls2x_i2c_probe(struct platform_device *pdev) +{ + int ret, irq; + struct i2c_adapter *adap; + struct ls2x_i2c_priv *priv; + struct device *dev = &pdev->dev; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Map hardware registers */ + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Add the i2c adapter */ + adap = &priv->adapter; + adap->retries = 5; + adap->nr = pdev->id; + adap->dev.parent = dev; + adap->owner = THIS_MODULE; + adap->algo = &ls2x_i2c_algo; + adap->timeout = msecs_to_jiffies(100); + device_set_node(&adap->dev, dev_fwnode(dev)); + i2c_set_adapdata(adap, priv); + strscpy(adap->name, pdev->name, sizeof(adap->name)); + init_completion(&priv->cmd_complete); + platform_set_drvdata(pdev, priv); + + ls2x_i2c_init(priv); + + ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c", + priv); + if (ret < 0) + return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + + return devm_i2c_add_adapter(dev, adap); +} + +static int ls2x_i2c_suspend(struct device *dev) +{ + struct ls2x_i2c_priv *priv = dev_get_drvdata(dev); + + /* Disable interrupts */ + writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN, + priv->base + I2C_LS2X_CTR); + + return 0; +} + +static int ls2x_i2c_resume(struct device *dev) +{ + ls2x_i2c_init(dev_get_drvdata(dev)); + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops, + ls2x_i2c_suspend, ls2x_i2c_resume, NULL); + +static const struct of_device_id ls2x_i2c_id_table[] = { + { .compatible = "loongson,ls2k-i2c" }, + { .compatible = "loongson,ls7a-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table); + +static const struct acpi_device_id ls2x_i2c_acpi_match[] = { + { "LOON0004" }, /* Loongson LS7A */ + { } +}; +MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match); + +static struct platform_driver ls2x_i2c_driver = { + .probe = ls2x_i2c_probe, + .driver = { + .name = "ls2x-i2c", + .pm = pm_sleep_ptr(&ls2x_i2c_pm_ops), + .of_match_table = ls2x_i2c_id_table, + .acpi_match_table = ls2x_i2c_acpi_match, + }, +}; + +/* The DC subsystem depends on it, we should initialize it earlier. */ +static int __init ls2x_i2c_init_driver(void) +{ + return platform_driver_register(&ls2x_i2c_driver); +} +subsys_initcall(ls2x_i2c_init_driver); + +static void __exit ls2x_i2c_exit_driver(void) +{ + platform_driver_unregister(&ls2x_i2c_driver); +} +module_exit(ls2x_i2c_exit_driver); + +MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); -- 2.31.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A I2C controller 2023-01-03 7:00 ` [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A " Binbin Zhou @ 2023-01-03 12:12 ` Andy Shevchenko 0 siblings, 0 replies; 6+ messages in thread From: Andy Shevchenko @ 2023-01-03 12:12 UTC (permalink / raw) To: Binbin Zhou Cc: Wolfram Sang, Wolfram Sang, Mika Westerberg, linux-i2c, loongarch, devicetree, Huacai Chen, WANG Xuerui, Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv On Tue, Jan 03, 2023 at 03:00:47PM +0800, Binbin Zhou wrote: > This I2C module is integrated into the Loongson-2K SoCs and Loongson > LS7A bridge chip. I believe that you have tested this on real hardware and it works as expected. From the code perspective it is good to me, Reviewed-by: Andy Shevchenko <andy@kernel.org> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> > --- > drivers/i2c/busses/Kconfig | 11 + > drivers/i2c/busses/Makefile | 1 + > drivers/i2c/busses/i2c-ls2x.c | 381 ++++++++++++++++++++++++++++++++++ > 3 files changed, 393 insertions(+) > create mode 100644 drivers/i2c/busses/i2c-ls2x.c > > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig > index e50f9603d189..d80c938142f5 100644 > --- a/drivers/i2c/busses/Kconfig > +++ b/drivers/i2c/busses/Kconfig > @@ -761,6 +761,17 @@ config I2C_LPC2K > This driver can also be built as a module. If so, the module > will be called i2c-lpc2k. > > +config I2C_LS2X > + tristate "Loongson LS2X I2C adapter" > + depends on MACH_LOONGSON64 || COMPILE_TEST > + help > + If you say yes to this option, support will be included for the > + I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge > + chip. > + > + This driver can also be built as a module. If so, the module > + will be called i2c-ls2x. > + > config I2C_MLXBF > tristate "Mellanox BlueField I2C controller" > depends on MELLANOX_PLATFORM && ARM64 > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile > index e73cdb1d2b5a..0584fe160824 100644 > --- a/drivers/i2c/busses/Makefile > +++ b/drivers/i2c/busses/Makefile > @@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o > obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o > obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o > obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o > +obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o > obj-$(CONFIG_I2C_MESON) += i2c-meson.o > obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o > obj-$(CONFIG_I2C_MPC) += i2c-mpc.o > diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c > new file mode 100644 > index 000000000000..2215aa04233b > --- /dev/null > +++ b/drivers/i2c/busses/i2c-ls2x.c > @@ -0,0 +1,382 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Loongson-2K/Loongson LS7A I2C master mode driver > + * > + * Copyright (C) 2013 Loongson Technology Corporation Limited. > + * Copyright (C) 2014-2017 Lemote, Inc. > + * Copyright (C) 2018-2022 Loongson Technology Corporation Limited. > + * > + * Originally written by liushaozong > + * Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn> > + */ > + > +#include <linux/bits.h> > +#include <linux/completion.h> > +#include <linux/device.h> > +#include <linux/iopoll.h> > +#include <linux/i2c.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/pm_runtime.h> > +#include <linux/platform_device.h> > +#include <linux/property.h> > +#include <linux/units.h> > + > +/* I2C Registers */ > +#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */ > +#define I2C_LS2X_CTR 0x2 /* Control Register */ > +#define I2C_LS2X_TXR 0x3 /* Transport Data Register */ > +#define I2C_LS2X_RXR 0x3 /* Receive Data Register */ > +#define I2C_LS2X_CR 0x4 /* Command Control Register */ > +#define I2C_LS2X_SR 0x4 /* State Register */ > + > +/* Command Control Register Bit */ > +#define LS2X_CR_START BIT(7) /* Start signal */ > +#define LS2X_CR_STOP BIT(6) /* Stop signal */ > +#define LS2X_CR_READ BIT(5) /* Read signal */ > +#define LS2X_CR_WRITE BIT(4) /* Write signal */ > +#define LS2X_CR_ACK BIT(3) /* Response signal */ > +#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */ > + > +/* State Register Bit */ > +#define LS2X_SR_NOACK BIT(7) /* Receive NACK */ > +#define LS2X_SR_BUSY BIT(6) /* Bus busy state */ > +#define LS2X_SR_AL BIT(5) /* Arbitration lost */ > +#define LS2X_SR_TIP BIT(1) /* Transmission state */ > +#define LS2X_SR_IF BIT(0) /* Interrupt flag */ > + > +/* Control Register Bit */ > +#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */ > +#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */ > +#define LS2X_CTR_MST BIT(5) /* 0: Slave mode 1: Master mode */ > +#define CTR_FREQ_MASK GENMASK(7, 6) > +#define CTR_READY_MASK GENMASK(7, 5) > + > +/* The PCLK frequency from LPB */ > +#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ) > + > +/* The default bus frequency, which is an empirical value */ > +#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ) > + > +struct ls2x_i2c_priv { > + struct i2c_adapter adapter; > + void __iomem *base; > + struct i2c_timings i2c_t; > + struct completion cmd_complete; > +}; > + > +/* > + * Interrupt service routine. > + * This gets called whenever an I2C interrupt occurs. > + */ > +static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id) > +{ > + struct ls2x_i2c_priv *priv = dev_id; > + > + if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF)) > + return IRQ_NONE; > + > + writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR); > + complete(&priv->cmd_complete); > + return IRQ_HANDLED; > +} > + > +/* > + * The ls2x i2c controller supports standard mode and fast mode, so the > + * maximum bus frequency is '400kHz'. > + * The bus frequency is set to the empirical value of '33KHz' by default, > + * but it can also be taken from ACPI or FDT for compatibility with more > + * devices. > + */ > +static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) > +{ > + struct i2c_timings *t = &priv->i2c_t; > + struct device *dev = priv->adapter.dev.parent; > + u32 acpi_speed = i2c_acpi_find_bus_speed(dev); > + > + i2c_parse_fw_timings(dev, t, false); > + > + if (acpi_speed || t->bus_freq_hz) > + t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); > + else > + t->bus_freq_hz = LS2X_I2C_FREQ_STD; > + > + /* Calculate and set i2c frequency. */ > + writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1, > + priv->base + I2C_LS2X_PRER); > +} > + > +static void ls2x_i2c_init(struct ls2x_i2c_priv *priv) > +{ > + /* Set i2c frequency setting mode and disable interrupts. */ > + writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK, > + priv->base + I2C_LS2X_CTR); > + > + ls2x_i2c_adjust_bus_speed(priv); > + > + /* Set i2c normal operating mode and enable interrupts. */ > + writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK, > + priv->base + I2C_LS2X_CTR); > +} > + > +static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap) > +{ > + u8 rxdata; > + unsigned long time_left; > + > + writeb(txdata, priv->base + I2C_LS2X_CR); > + > + time_left = wait_for_completion_timeout(&priv->cmd_complete, > + priv->adapter.timeout); > + if (!time_left) > + return -ETIMEDOUT; > + > + rxdata = readb(priv->base + I2C_LS2X_SR); > + if (rxdatap) > + *rxdatap = rxdata; > + > + return 0; > +} > + > +static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata) > +{ > + int ret; > + u8 rxdata; > + > + ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata); > + if (ret) > + return ret; > + > + if (rxdata & LS2X_SR_AL) > + return -EAGAIN; > + > + if (rxdata & LS2X_SR_NOACK) > + return -ENXIO; > + > + return 0; > +} > + > +static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv) > +{ > + u8 value; > + > + writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR); > + return readb_poll_timeout(priv->base + I2C_LS2X_SR, value, > + !(value & LS2X_SR_BUSY), 100, > + jiffies_to_usecs(priv->adapter.timeout)); > +} > + > +static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs) > +{ > + reinit_completion(&priv->cmd_complete); > + > + writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR); > + return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE); > +} > + > +static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) > +{ > + int ret; > + u8 rxdata, *buf = msg->buf; > + u16 len = msg->len; > + > + /* Contains steps to send start condition and address. */ > + ret = ls2x_i2c_start(priv, msg); > + if (ret) > + return ret; > + > + while (len--) { > + ret = ls2x_i2c_xfer_byte(priv, > + LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK), > + &rxdata); > + if (ret) > + return ret; > + > + *buf++ = readb(priv->base + I2C_LS2X_RXR); > + } > + > + return 0; > +} > + > +static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) > +{ > + int ret; > + u8 *buf = msg->buf; > + u16 len = msg->len; > + > + /* Contains steps to send start condition and address. */ > + ret = ls2x_i2c_start(priv, msg); > + if (ret) > + return ret; > + > + while (len--) { > + writeb(*buf++, priv->base + I2C_LS2X_TXR); > + > + ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv, > + struct i2c_msg *msg, bool stop) > +{ > + int ret; > + > + if (msg->flags & I2C_M_RD) > + ret = ls2x_i2c_rx(priv, msg); > + else > + ret = ls2x_i2c_tx(priv, msg); > + > + if (ret < 0) { > + /* Fatel error. Needs reinit. */ > + if (ret == -ETIMEDOUT) > + ls2x_i2c_init(priv); > + > + return ret; > + } > + > + if (stop) { > + /* Failed to issue STOP. Needs reinit. */ > + ret = ls2x_i2c_stop(priv); > + if (ret) > + ls2x_i2c_init(priv); > + } > + > + return ret; > +} > + > +static int ls2x_i2c_master_xfer(struct i2c_adapter *adap, > + struct i2c_msg *msgs, int num) > +{ > + int ret; > + struct i2c_msg *msg, *emsg = msgs + num; > + struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap); > + > + for (msg = msgs; msg < emsg; msg++) { > + ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1); > + if (ret) > + return ret; > + } > + > + return num; > +} > + > +static unsigned int ls2x_i2c_func(struct i2c_adapter *adap) > +{ > + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; > +} > + > +static const struct i2c_algorithm ls2x_i2c_algo = { > + .master_xfer = ls2x_i2c_master_xfer, > + .functionality = ls2x_i2c_func, > +}; > + > +static int ls2x_i2c_probe(struct platform_device *pdev) > +{ > + int ret, irq; > + struct i2c_adapter *adap; > + struct ls2x_i2c_priv *priv; > + struct device *dev = &pdev->dev; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + /* Map hardware registers */ > + priv->base = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(priv->base)) > + return PTR_ERR(priv->base); > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) > + return irq; > + > + /* Add the i2c adapter */ > + adap = &priv->adapter; > + adap->retries = 5; > + adap->nr = pdev->id; > + adap->dev.parent = dev; > + adap->owner = THIS_MODULE; > + adap->algo = &ls2x_i2c_algo; > + adap->timeout = msecs_to_jiffies(100); > + device_set_node(&adap->dev, dev_fwnode(dev)); > + i2c_set_adapdata(adap, priv); > + strscpy(adap->name, pdev->name, sizeof(adap->name)); > + init_completion(&priv->cmd_complete); > + platform_set_drvdata(pdev, priv); > + > + ls2x_i2c_init(priv); > + > + ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c", > + priv); > + if (ret < 0) > + return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); > + > + return devm_i2c_add_adapter(dev, adap); > +} > + > +static int ls2x_i2c_suspend(struct device *dev) > +{ > + struct ls2x_i2c_priv *priv = dev_get_drvdata(dev); > + > + /* Disable interrupts */ > + writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN, > + priv->base + I2C_LS2X_CTR); > + > + return 0; > +} > + > +static int ls2x_i2c_resume(struct device *dev) > +{ > + ls2x_i2c_init(dev_get_drvdata(dev)); > + return 0; > +} > + > +static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops, > + ls2x_i2c_suspend, ls2x_i2c_resume, NULL); > + > +static const struct of_device_id ls2x_i2c_id_table[] = { > + { .compatible = "loongson,ls2k-i2c" }, > + { .compatible = "loongson,ls7a-i2c" }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table); > + > +static const struct acpi_device_id ls2x_i2c_acpi_match[] = { > + { "LOON0004" }, /* Loongson LS7A */ > + { } > +}; > +MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match); > + > +static struct platform_driver ls2x_i2c_driver = { > + .probe = ls2x_i2c_probe, > + .driver = { > + .name = "ls2x-i2c", > + .pm = pm_sleep_ptr(&ls2x_i2c_pm_ops), > + .of_match_table = ls2x_i2c_id_table, > + .acpi_match_table = ls2x_i2c_acpi_match, > + }, > +}; > + > +/* The DC subsystem depends on it, we should initialize it earlier. */ > +static int __init ls2x_i2c_init_driver(void) > +{ > + return platform_driver_register(&ls2x_i2c_driver); > +} > +subsys_initcall(ls2x_i2c_init_driver); > + > +static void __exit ls2x_i2c_exit_driver(void) > +{ > + platform_driver_unregister(&ls2x_i2c_driver); > +} > +module_exit(ls2x_i2c_exit_driver); > + > +MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver"); > +MODULE_AUTHOR("Loongson Technology Corporation Limited"); > +MODULE_LICENSE("GPL"); > -- > 2.31.1 > -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH V9 4/4] LoongArch: Enable LS2X I2C in loongson3_defconfig 2023-01-03 7:00 [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller Binbin Zhou ` (2 preceding siblings ...) 2023-01-03 7:00 ` [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A " Binbin Zhou @ 2023-01-03 7:01 ` Binbin Zhou 3 siblings, 0 replies; 6+ messages in thread From: Binbin Zhou @ 2023-01-03 7:01 UTC (permalink / raw) To: Wolfram Sang, Wolfram Sang, Andy Shevchenko, Mika Westerberg, linux-i2c Cc: loongarch, devicetree, Huacai Chen, WANG Xuerui, Andy Shevchenko, Arnd Bergmann, Rob Herring, Krzysztof Kozlowski, Jianmin Lv, Binbin Zhou This is now supported, enable for Loongson-3 systems. Other systems are unaffected. Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> --- arch/loongarch/configs/loongson3_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig index cb52774c80e8..5677c4f8576e 100644 --- a/arch/loongarch/configs/loongson3_defconfig +++ b/arch/loongarch/configs/loongson3_defconfig @@ -602,6 +602,7 @@ CONFIG_HW_RANDOM_VIRTIO=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_PIIX4=y CONFIG_I2C_GPIO=y +CONFIG_I2C_LS2X=y CONFIG_SPI=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_LOONGSON=y -- 2.31.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-01-03 12:13 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-01-03 7:00 [PATCH V9 0/4] i2c: ls2x: Add support for the Loongson-2K/LS7A I2C controller Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 1/4] i2c: gpio: Add support on ACPI-based system Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 2/4] dt-bindings: i2c: Add Loongson LS2X I2C controller Binbin Zhou 2023-01-03 7:00 ` [PATCH V9 3/4] i2c: ls2x: Add driver for Loongson-2K/LS7A " Binbin Zhou 2023-01-03 12:12 ` Andy Shevchenko 2023-01-03 7:01 ` [PATCH V9 4/4] LoongArch: Enable LS2X I2C in loongson3_defconfig Binbin Zhou
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox