[PATCH 2/3] soc: samsung: Add a driver for Samsung SPEEDY host controller
Krzysztof Kozlowski
krzk at kernel.org
Fri Dec 13 05:55:38 PST 2024
On 13/12/2024 10:42, Markuss Broks wrote:
> Hi Krzysztof,
>
> On 12/13/24 9:49 AM, Krzysztof Kozlowski wrote:
>> On 12/12/2024 22:09, Markuss Broks wrote:
>>> Add a driver for Samsung SPEEDY serial bus host controller.
>>> SPEEDY is a proprietary 1 wire serial bus used by Samsung
>>> in various devices (usually mobile), like Samsung Galaxy
>>> phones. It is usually used for connecting PMIC or various
>>> other peripherals, like audio codecs or RF components.
>>>
>>> This bus can address at most 1MiB (4 bit device address,
>>> 8 bit registers per device, 8 bit wide registers:
>>> 256*256*16 = 1MiB of address space.
>>>
>>> Co-developed-by: Maksym Holovach <nergzd at nergzd723.xyz>
>>> Signed-off-by: Maksym Holovach <nergzd at nergzd723.xyz>
>>> Signed-off-by: Markuss Broks <markuss.broks at gmail.com>
>>> ---
>>> drivers/soc/samsung/Kconfig | 13 +
>>> drivers/soc/samsung/Makefile | 2 +
>>> drivers/soc/samsung/exynos-speedy.c | 457 ++++++++++++++++++++++++++++++
>>> include/linux/soc/samsung/exynos-speedy.h | 56 ++++
>>> 4 files changed, 528 insertions(+)
>>>
>>> diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
>>> index 1a5dfdc978dc4069eb71c4e8eada7ff1913b86b3..a38150fc9999ded1e1e93e2a9ef43b88175d34bd 100644
>>> --- a/drivers/soc/samsung/Kconfig
>>> +++ b/drivers/soc/samsung/Kconfig
>>> @@ -49,6 +49,19 @@ config EXYNOS_PMU_ARM_DRIVERS
>>> bool "Exynos PMU ARMv7-specific driver extensions" if COMPILE_TEST
>>> depends on EXYNOS_PMU
>>>
>>> +config EXYNOS_SPEEDY
>>> + tristate "Exynos SPEEDY host controller driver"
>>> + depends on ARCH_EXYNOS || COMPILE_TEST
>>> + depends on OF
>>> + depends on REGMAP_MMIO
>>> + help
>>> + Enable support for Exynos SPEEDY host controller block.
>>> + SPEEDY is a 1 wire proprietary Samsung serial bus, found in
>>> + modern Samsung Exynos SoCs, like Exynos8895 and newer.
>>
>> I did not check that much but this looks like 1wire for which we have
>> subsystem. Please investigate more and figure out the differences.
>
> This is not compatible with Dallas Semi 1-Wire bus. There are several
> differences but the phy level is not compatible, looking at the Samsung
> patent. [1] The most obvious difference is that 1-Wire is discoverable,
> and this bus isn't. I'm pretty sure this is Samsung's own solution to a
> serial interface through only one wire.
>
It's fine then.
>>
>>> +
>>> + Select this if you have a Samsung Exynos device which uses
>>> + SPEEDY bus.
>>> +
>>
>>> +
>>> +/* SPEEDY_PACKET_GAP_TIME register bits */
>>> +#define SPEEDY_FIFO_TX_ALMOST_EMPTY (1 << 4)
>>> +#define SPEEDY_FIFO_RX_ALMOST_FULL (1 << 8)
>>> +#define SPEEDY_FSM_INIT (1 << 1)
>>> +#define SPEEDY_FSM_TX_CMD (1 << 2)
>>> +#define SPEEDY_FSM_STANDBY (1 << 3)
>>> +#define SPEEDY_FSM_DATA (1 << 4)
>>> +#define SPEEDY_FSM_TIMEOUT (1 << 5)
>>> +#define SPEEDY_FSM_TRANS_DONE (1 << 6)
>>> +#define SPEEDY_FSM_IO_RX_STAT_MASK (3 << 7)
>>> +#define SPEEDY_FSM_IO_TX_IDLE (1 << 9)
>>> +#define SPEEDY_FSM_IO_TX_GET_PACKET (1 << 10)
>>> +#define SPEEDY_FSM_IO_TX_PACKET (1 << 11)
>>> +#define SPEEDY_FSM_IO_TX_DONE (1 << 12)
>>> +
>>> +#define SPEEDY_RX_LENGTH(n) ((n) << 0)
>>> +#define SPEEDY_TX_LENGTH(n) ((n) << 8)
>>> +
>>> +#define SPEEDY_DEVICE(x) ((x & 0xf) << 15)
>>> +#define SPEEDY_ADDRESS(x) ((x & 0xff) << 7)
>>> +
>>> +static const struct of_device_id speedy_match[] = {
>>> + { .compatible = "samsung,exynos9810-speedy" },
>>> + { /* Sentinel */ }
>>> +};
>>> +MODULE_DEVICE_TABLE(of, speedy_match);
>> This is never at top of the file, but immediately before driver
>> structure. Look at other drivers.
> The function speedy_get_device uses this to match the compatible, do I
> just leave the prototype here?
1. Entire speedy_get_device() is unused so it will be removed.
2. Even if it stays, speedy_get_device() is not supposed to match
anything. How are you supposed to use Samsung PMIC on different
controller? These things should not be tied.
>>
>>> +
>>> +static const struct regmap_config speedy_map_cfg = {
>>> + .reg_bits = 32,
>>> + .val_bits = 32,
>>> +};
...
>>> + cmd = SPEEDY_ACCESS_RANDOM | SPEEDY_DIRECTION_READ |
>>> + SPEEDY_DEVICE(reg) | SPEEDY_ADDRESS(addr);
>>> +
>>> + int_ctl = SPEEDY_TRANSFER_DONE_EN | SPEEDY_FIFO_RX_ALMOST_FULL_EN |
>>> + SPEEDY_RX_FIFO_INT_TRAILER_EN | SPEEDY_RX_MODEBIT_ERR_EN |
>>> + SPEEDY_RX_GLITCH_ERR_EN | SPEEDY_RX_ENDBIT_ERR_EN |
>>> + SPEEDY_REMOTE_RESET_REQ_EN;
>>> +
>>> + ret = speedy_int_clear(speedy);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = regmap_write(speedy->map, SPEEDY_INT_ENABLE, int_ctl);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = regmap_write(speedy->map, SPEEDY_CMD, cmd);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + /* Wait for xfer done */
>>> + ret = regmap_read_poll_timeout(speedy->map, SPEEDY_INT_STATUS, int_status,
>>> + int_status & SPEEDY_TRANSFER_DONE, 5000, 50000);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = regmap_read(speedy->map, SPEEDY_RX_DATA, val);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = speedy_int_clear(speedy);
>>> +
>>> + mutex_unlock(&speedy->io_lock);
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +int exynos_speedy_read(const struct speedy_device *device, u32 addr, u32 *val)
>>> +{
>>> + return _speedy_read(device->speedy, device->reg, addr, val);
>>> +}
>>> +EXPORT_SYMBOL_GPL(exynos_speedy_read);
>> Nope, drop, unused.
> This is intended to be used with other device drivers, this driver in
> itself doesn't do anything, it only configures the controller and makes
> it ready for transmitting data, it's other drivers that will come (e.g.
> S2MPS18 PMIC, which uses SPEEDY for communication with the SoC) that
> will utilize those functions.
Post entire series, so we see users of this API. If you post API without
users, it won't be accepted simply because there are no users and we do
not want dead, unused code.
Anyway we must see how you intend to use that interface to properly
review it.
>>
>>> +
>>> +/**
>>> + * _speedy_write() - internal speedy write operation
>>> + * @speedy: pointer to speedy controller struct
>>> + * @reg: address of device on the bus
>>> + * @addr: address to write
>>> + * @val: value to write
>>> + *
...
>>> +}
>>> +
>>> +static struct platform_driver speedy_driver = {
>>> + .probe = speedy_probe,
>>> + .driver = {
>>> + .name = "exynos-speedy",
>>> + .of_match_table = speedy_match,
>>> + },
>>> +};
>>> +
>>> +module_platform_driver(speedy_driver);
>>> +
>>> +MODULE_DESCRIPTION("Samsung Exynos SPEEDY host controller driver");
>>> +MODULE_AUTHOR("Markuss Broks <markuss.broks at gmail.com>");
>>> +MODULE_LICENSE("GPL");
>>> diff --git a/include/linux/soc/samsung/exynos-speedy.h b/include/linux/soc/samsung/exynos-speedy.h
>>> new file mode 100644
>>> index 0000000000000000000000000000000000000000..b2857d65d3b50927373866dd8ae1c47e98af6d7b
>>> --- /dev/null
>>> +++ b/include/linux/soc/samsung/exynos-speedy.h
>> Drop the header, not used.
> Same here, please clarify how this should be handled. This driver
> implements the devm_speedy_get_device and read/write functions for its
> child devices in that header, future drivers for e.g. PMIC would use
> this header and call devm_speedy_get_device to get a speedy_device
> pointer and then use read/write functions to read/write from the bus.
This needs to be proper bus with proper speedy_driver clients. See how
other buses - struct bus_type. Recent example of bus using platform
drivers for devices would be pwrseq (power/sequence). Not so old other
bus using its own xxx_driver for devices could be cxl or ffa (arm_ffa).
This current non-bus approach, could also work if this is really Samsung
specific. See memory/ for examples of MMIO buses and MMIO clients.
I don't know good examples of non-MMIO buses not using bus_type and I am
not sure whether this is accepted in general. I'll ask on IRC, maybe
someone will give some hints.
Best regards,
Krzysztof
More information about the linux-arm-kernel
mailing list