162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2023 Code Construct
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Jeremy Kerr <jk@codeconstruct.com.au>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/i3c/master.h>
1062306a36Sopenharmony_ci#include <linux/reset.h>
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define DW_I3C_MAX_DEVS 32
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct dw_i3c_master_caps {
1662306a36Sopenharmony_ci	u8 cmdfifodepth;
1762306a36Sopenharmony_ci	u8 datafifodepth;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct dw_i3c_dat_entry {
2162306a36Sopenharmony_ci	u8 addr;
2262306a36Sopenharmony_ci	struct i3c_dev_desc *ibi_dev;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct dw_i3c_master {
2662306a36Sopenharmony_ci	struct i3c_master_controller base;
2762306a36Sopenharmony_ci	u16 maxdevs;
2862306a36Sopenharmony_ci	u16 datstartaddr;
2962306a36Sopenharmony_ci	u32 free_pos;
3062306a36Sopenharmony_ci	struct {
3162306a36Sopenharmony_ci		struct list_head list;
3262306a36Sopenharmony_ci		struct dw_i3c_xfer *cur;
3362306a36Sopenharmony_ci		spinlock_t lock;
3462306a36Sopenharmony_ci	} xferqueue;
3562306a36Sopenharmony_ci	struct dw_i3c_master_caps caps;
3662306a36Sopenharmony_ci	void __iomem *regs;
3762306a36Sopenharmony_ci	struct reset_control *core_rst;
3862306a36Sopenharmony_ci	struct clk *core_clk;
3962306a36Sopenharmony_ci	char version[5];
4062306a36Sopenharmony_ci	char type[5];
4162306a36Sopenharmony_ci	bool ibi_capable;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/*
4462306a36Sopenharmony_ci	 * Per-device hardware data, used to manage the device address table
4562306a36Sopenharmony_ci	 * (DAT)
4662306a36Sopenharmony_ci	 *
4762306a36Sopenharmony_ci	 * Locking: the devs array may be referenced in IRQ context while
4862306a36Sopenharmony_ci	 * processing an IBI. However, IBIs (for a specific device, which
4962306a36Sopenharmony_ci	 * implies a specific DAT entry) can only happen while interrupts are
5062306a36Sopenharmony_ci	 * requested for that device, which is serialised against other
5162306a36Sopenharmony_ci	 * insertions/removals from the array by the global i3c infrastructure.
5262306a36Sopenharmony_ci	 * So, devs_lock protects against concurrent updates to devs->ibi_dev
5362306a36Sopenharmony_ci	 * between request_ibi/free_ibi and the IBI irq event.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	struct dw_i3c_dat_entry devs[DW_I3C_MAX_DEVS];
5662306a36Sopenharmony_ci	spinlock_t devs_lock;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* platform-specific data */
5962306a36Sopenharmony_ci	const struct dw_i3c_platform_ops *platform_ops;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct dw_i3c_platform_ops {
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * Called on early bus init: the i3c has been set up, but before any
6562306a36Sopenharmony_ci	 * transactions have taken place. Platform implementations may use to
6662306a36Sopenharmony_ci	 * perform actual device enabling with the i3c core ready.
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	int (*init)(struct dw_i3c_master *i3c);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * Initialise a DAT entry to enable/disable IBIs. Allows the platform
7262306a36Sopenharmony_ci	 * to perform any device workarounds on the DAT entry before
7362306a36Sopenharmony_ci	 * inserting into the hardware table.
7462306a36Sopenharmony_ci	 *
7562306a36Sopenharmony_ci	 * Called with the DAT lock held; must not sleep.
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci	void (*set_dat_ibi)(struct dw_i3c_master *i3c,
7862306a36Sopenharmony_ci			    struct i3c_dev_desc *dev, bool enable, u32 *reg);
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciextern int dw_i3c_common_probe(struct dw_i3c_master *master,
8262306a36Sopenharmony_ci			       struct platform_device *pdev);
8362306a36Sopenharmony_ciextern void dw_i3c_common_remove(struct dw_i3c_master *master);
8462306a36Sopenharmony_ci
85