forked from mirrors/linux
		
	spi: amd: Configure device speed
Number of clock frequencies are supported by AMD controller which are mentioned in the amd_spi_freq structure table. Create mechanism to configure device clock frequency such that it is strictly less than the requested frequency. Give priority to the device transfer speed and in case it is not set then use the max clock speed supported by the device. Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com> Co-developed-by: Shreeya Patel <shreeya.patel@collabora.com> Signed-off-by: Shreeya Patel <shreeya.patel@collabora.com> Link: https://lore.kernel.org/r/20220825143132.253224-1-shreeya.patel@collabora.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
		
							parent
							
								
									d294e99cdc
								
							
						
					
					
						commit
						3fe26121dc
					
				
					 1 changed files with 97 additions and 0 deletions
				
			
		| 
						 | 
					@ -36,6 +36,18 @@
 | 
				
			||||||
#define AMD_SPI_FIFO_SIZE	70
 | 
					#define AMD_SPI_FIFO_SIZE	70
 | 
				
			||||||
#define AMD_SPI_MEM_SIZE	200
 | 
					#define AMD_SPI_MEM_SIZE	200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AMD_SPI_ENA_REG		0x20
 | 
				
			||||||
 | 
					#define AMD_SPI_ALT_SPD_SHIFT	20
 | 
				
			||||||
 | 
					#define AMD_SPI_ALT_SPD_MASK	GENMASK(23, AMD_SPI_ALT_SPD_SHIFT)
 | 
				
			||||||
 | 
					#define AMD_SPI_SPI100_SHIFT	0
 | 
				
			||||||
 | 
					#define AMD_SPI_SPI100_MASK	GENMASK(AMD_SPI_SPI100_SHIFT, AMD_SPI_SPI100_SHIFT)
 | 
				
			||||||
 | 
					#define AMD_SPI_SPEED_REG	0x6C
 | 
				
			||||||
 | 
					#define AMD_SPI_SPD7_SHIFT	8
 | 
				
			||||||
 | 
					#define AMD_SPI_SPD7_MASK	GENMASK(13, AMD_SPI_SPD7_SHIFT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AMD_SPI_MAX_HZ		100000000
 | 
				
			||||||
 | 
					#define AMD_SPI_MIN_HZ		800000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * enum amd_spi_versions - SPI controller versions
 | 
					 * enum amd_spi_versions - SPI controller versions
 | 
				
			||||||
 * @AMD_SPI_V1:		AMDI0061 hardware version
 | 
					 * @AMD_SPI_V1:		AMDI0061 hardware version
 | 
				
			||||||
| 
						 | 
					@ -46,14 +58,41 @@ enum amd_spi_versions {
 | 
				
			||||||
	AMD_SPI_V2,
 | 
						AMD_SPI_V2,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum amd_spi_speed {
 | 
				
			||||||
 | 
						F_66_66MHz,
 | 
				
			||||||
 | 
						F_33_33MHz,
 | 
				
			||||||
 | 
						F_22_22MHz,
 | 
				
			||||||
 | 
						F_16_66MHz,
 | 
				
			||||||
 | 
						F_100MHz,
 | 
				
			||||||
 | 
						F_800KHz,
 | 
				
			||||||
 | 
						SPI_SPD7,
 | 
				
			||||||
 | 
						F_50MHz = 0x4,
 | 
				
			||||||
 | 
						F_4MHz = 0x32,
 | 
				
			||||||
 | 
						F_3_17MHz = 0x3F
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct amd_spi_freq - Matches device speed with values to write in regs
 | 
				
			||||||
 | 
					 * @speed_hz: Device frequency
 | 
				
			||||||
 | 
					 * @enable_val: Value to be written to "enable register"
 | 
				
			||||||
 | 
					 * @spd7_val: Some frequencies requires to have a value written at SPISPEED register
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct amd_spi_freq {
 | 
				
			||||||
 | 
						u32 speed_hz;
 | 
				
			||||||
 | 
						u32 enable_val;
 | 
				
			||||||
 | 
						u32 spd7_val;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct amd_spi - SPI driver instance
 | 
					 * struct amd_spi - SPI driver instance
 | 
				
			||||||
 * @io_remap_addr:	Start address of the SPI controller registers
 | 
					 * @io_remap_addr:	Start address of the SPI controller registers
 | 
				
			||||||
 * @version:		SPI controller hardware version
 | 
					 * @version:		SPI controller hardware version
 | 
				
			||||||
 | 
					 * @speed_hz:		Device frequency
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct amd_spi {
 | 
					struct amd_spi {
 | 
				
			||||||
	void __iomem *io_remap_addr;
 | 
						void __iomem *io_remap_addr;
 | 
				
			||||||
	enum amd_spi_versions version;
 | 
						enum amd_spi_versions version;
 | 
				
			||||||
 | 
						unsigned int speed_hz;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
 | 
					static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
 | 
				
			||||||
| 
						 | 
					@ -185,11 +224,62 @@ static int amd_spi_master_setup(struct spi_device *spi)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct amd_spi_freq amd_spi_freq[] = {
 | 
				
			||||||
 | 
						{ AMD_SPI_MAX_HZ,   F_100MHz,         0},
 | 
				
			||||||
 | 
						{       66660000, F_66_66MHz,         0},
 | 
				
			||||||
 | 
						{       50000000,   SPI_SPD7,   F_50MHz},
 | 
				
			||||||
 | 
						{       33330000, F_33_33MHz,         0},
 | 
				
			||||||
 | 
						{       22220000, F_22_22MHz,         0},
 | 
				
			||||||
 | 
						{       16660000, F_16_66MHz,         0},
 | 
				
			||||||
 | 
						{        4000000,   SPI_SPD7,    F_4MHz},
 | 
				
			||||||
 | 
						{        3170000,   SPI_SPD7, F_3_17MHz},
 | 
				
			||||||
 | 
						{ AMD_SPI_MIN_HZ,   F_800KHz,         0},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i, spd7_val, alt_spd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (speed_hz == amd_spi->speed_hz)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (speed_hz < AMD_SPI_MIN_HZ)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++)
 | 
				
			||||||
 | 
							if (speed_hz >= amd_spi_freq[i].speed_hz)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (speed_hz == amd_spi_freq[i].speed_hz)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						amd_spi->speed_hz = amd_spi_freq[i].speed_hz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alt_spd = (amd_spi_freq[i].enable_val << AMD_SPI_ALT_SPD_SHIFT)
 | 
				
			||||||
 | 
							   & AMD_SPI_ALT_SPD_MASK;
 | 
				
			||||||
 | 
						amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, alt_spd,
 | 
				
			||||||
 | 
								       AMD_SPI_ALT_SPD_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (amd_spi->speed_hz == AMD_SPI_MAX_HZ)
 | 
				
			||||||
 | 
							amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, 1,
 | 
				
			||||||
 | 
									       AMD_SPI_SPI100_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (amd_spi_freq[i].spd7_val) {
 | 
				
			||||||
 | 
							spd7_val = (amd_spi_freq[i].spd7_val << AMD_SPI_SPD7_SHIFT)
 | 
				
			||||||
 | 
								    & AMD_SPI_SPD7_MASK;
 | 
				
			||||||
 | 
							amd_spi_setclear_reg32(amd_spi, AMD_SPI_SPEED_REG, spd7_val,
 | 
				
			||||||
 | 
									       AMD_SPI_SPD7_MASK);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
 | 
					static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
 | 
				
			||||||
				    struct spi_master *master,
 | 
									    struct spi_master *master,
 | 
				
			||||||
				    struct spi_message *message)
 | 
									    struct spi_message *message)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct spi_transfer *xfer = NULL;
 | 
						struct spi_transfer *xfer = NULL;
 | 
				
			||||||
 | 
						struct spi_device *spi = message->spi;
 | 
				
			||||||
	u8 cmd_opcode = 0, fifo_pos = AMD_SPI_FIFO_BASE;
 | 
						u8 cmd_opcode = 0, fifo_pos = AMD_SPI_FIFO_BASE;
 | 
				
			||||||
	u8 *buf = NULL;
 | 
						u8 *buf = NULL;
 | 
				
			||||||
	u32 i = 0;
 | 
						u32 i = 0;
 | 
				
			||||||
| 
						 | 
					@ -197,6 +287,11 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(xfer, &message->transfers,
 | 
						list_for_each_entry(xfer, &message->transfers,
 | 
				
			||||||
			    transfer_list) {
 | 
								    transfer_list) {
 | 
				
			||||||
 | 
							if (xfer->speed_hz)
 | 
				
			||||||
 | 
								amd_set_spi_freq(amd_spi, xfer->speed_hz);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								amd_set_spi_freq(amd_spi, spi->max_speed_hz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (xfer->tx_buf) {
 | 
							if (xfer->tx_buf) {
 | 
				
			||||||
			buf = (u8 *)xfer->tx_buf;
 | 
								buf = (u8 *)xfer->tx_buf;
 | 
				
			||||||
			if (!tx_len) {
 | 
								if (!tx_len) {
 | 
				
			||||||
| 
						 | 
					@ -313,6 +408,8 @@ static int amd_spi_probe(struct platform_device *pdev)
 | 
				
			||||||
	master->num_chipselect = 4;
 | 
						master->num_chipselect = 4;
 | 
				
			||||||
	master->mode_bits = 0;
 | 
						master->mode_bits = 0;
 | 
				
			||||||
	master->flags = SPI_MASTER_HALF_DUPLEX;
 | 
						master->flags = SPI_MASTER_HALF_DUPLEX;
 | 
				
			||||||
 | 
						master->max_speed_hz = AMD_SPI_MAX_HZ;
 | 
				
			||||||
 | 
						master->min_speed_hz = AMD_SPI_MIN_HZ;
 | 
				
			||||||
	master->setup = amd_spi_master_setup;
 | 
						master->setup = amd_spi_master_setup;
 | 
				
			||||||
	master->transfer_one_message = amd_spi_master_transfer;
 | 
						master->transfer_one_message = amd_spi_master_transfer;
 | 
				
			||||||
	master->max_transfer_size = amd_spi_max_transfer_size;
 | 
						master->max_transfer_size = amd_spi_max_transfer_size;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue