162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TSA driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2022 CS GROUP France 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Herve Codina <herve.codina@bootlin.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "tsa.h" 1162306a36Sopenharmony_ci#include <dt-bindings/soc/cpm1-fsl,tsa.h> 1262306a36Sopenharmony_ci#include <linux/clk.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/of_platform.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* TSA SI RAM routing tables entry */ 2262306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_LAST (1 << 16) 2362306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_BYTE (1 << 17) 2462306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CNT(x) (((x) & 0x0f) << 18) 2562306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_MASK (0x7 << 22) 2662306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_NU (0x0 << 22) 2762306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_SCC2 (0x2 << 22) 2862306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_SCC3 (0x3 << 22) 2962306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_SCC4 (0x4 << 22) 3062306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_SMC1 (0x5 << 22) 3162306a36Sopenharmony_ci#define TSA_SIRAM_ENTRY_CSEL_SMC2 (0x6 << 22) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* SI mode register (32 bits) */ 3462306a36Sopenharmony_ci#define TSA_SIMODE 0x00 3562306a36Sopenharmony_ci#define TSA_SIMODE_SMC2 0x80000000 3662306a36Sopenharmony_ci#define TSA_SIMODE_SMC1 0x00008000 3762306a36Sopenharmony_ci#define TSA_SIMODE_TDMA(x) ((x) << 0) 3862306a36Sopenharmony_ci#define TSA_SIMODE_TDMB(x) ((x) << 16) 3962306a36Sopenharmony_ci#define TSA_SIMODE_TDM_MASK 0x0fff 4062306a36Sopenharmony_ci#define TSA_SIMODE_TDM_SDM_MASK 0x0c00 4162306a36Sopenharmony_ci#define TSA_SIMODE_TDM_SDM_NORM 0x0000 4262306a36Sopenharmony_ci#define TSA_SIMODE_TDM_SDM_ECHO 0x0400 4362306a36Sopenharmony_ci#define TSA_SIMODE_TDM_SDM_INTL_LOOP 0x0800 4462306a36Sopenharmony_ci#define TSA_SIMODE_TDM_SDM_LOOP_CTRL 0x0c00 4562306a36Sopenharmony_ci#define TSA_SIMODE_TDM_RFSD(x) ((x) << 8) 4662306a36Sopenharmony_ci#define TSA_SIMODE_TDM_DSC 0x0080 4762306a36Sopenharmony_ci#define TSA_SIMODE_TDM_CRT 0x0040 4862306a36Sopenharmony_ci#define TSA_SIMODE_TDM_STZ 0x0020 4962306a36Sopenharmony_ci#define TSA_SIMODE_TDM_CE 0x0010 5062306a36Sopenharmony_ci#define TSA_SIMODE_TDM_FE 0x0008 5162306a36Sopenharmony_ci#define TSA_SIMODE_TDM_GM 0x0004 5262306a36Sopenharmony_ci#define TSA_SIMODE_TDM_TFSD(x) ((x) << 0) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* SI global mode register (8 bits) */ 5562306a36Sopenharmony_ci#define TSA_SIGMR 0x04 5662306a36Sopenharmony_ci#define TSA_SIGMR_ENB (1<<3) 5762306a36Sopenharmony_ci#define TSA_SIGMR_ENA (1<<2) 5862306a36Sopenharmony_ci#define TSA_SIGMR_RDM_MASK 0x03 5962306a36Sopenharmony_ci#define TSA_SIGMR_RDM_STATIC_TDMA 0x00 6062306a36Sopenharmony_ci#define TSA_SIGMR_RDM_DYN_TDMA 0x01 6162306a36Sopenharmony_ci#define TSA_SIGMR_RDM_STATIC_TDMAB 0x02 6262306a36Sopenharmony_ci#define TSA_SIGMR_RDM_DYN_TDMAB 0x03 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* SI status register (8 bits) */ 6562306a36Sopenharmony_ci#define TSA_SISTR 0x06 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* SI command register (8 bits) */ 6862306a36Sopenharmony_ci#define TSA_SICMR 0x07 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* SI clock route register (32 bits) */ 7162306a36Sopenharmony_ci#define TSA_SICR 0x0C 7262306a36Sopenharmony_ci#define TSA_SICR_SCC2(x) ((x) << 8) 7362306a36Sopenharmony_ci#define TSA_SICR_SCC3(x) ((x) << 16) 7462306a36Sopenharmony_ci#define TSA_SICR_SCC4(x) ((x) << 24) 7562306a36Sopenharmony_ci#define TSA_SICR_SCC_MASK 0x0ff 7662306a36Sopenharmony_ci#define TSA_SICR_SCC_GRX (1 << 7) 7762306a36Sopenharmony_ci#define TSA_SICR_SCC_SCX_TSA (1 << 6) 7862306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_MASK (0x7 << 3) 7962306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_BRG1 (0x0 << 3) 8062306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_BRG2 (0x1 << 3) 8162306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_BRG3 (0x2 << 3) 8262306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_BRG4 (0x3 << 3) 8362306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_CLK15 (0x4 << 3) 8462306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_CLK26 (0x5 << 3) 8562306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_CLK37 (0x6 << 3) 8662306a36Sopenharmony_ci#define TSA_SICR_SCC_RXCS_CLK48 (0x7 << 3) 8762306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_MASK (0x7 << 0) 8862306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_BRG1 (0x0 << 0) 8962306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_BRG2 (0x1 << 0) 9062306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_BRG3 (0x2 << 0) 9162306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_BRG4 (0x3 << 0) 9262306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_CLK15 (0x4 << 0) 9362306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_CLK26 (0x5 << 0) 9462306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_CLK37 (0x6 << 0) 9562306a36Sopenharmony_ci#define TSA_SICR_SCC_TXCS_CLK48 (0x7 << 0) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Serial interface RAM pointer register (32 bits) */ 9862306a36Sopenharmony_ci#define TSA_SIRP 0x10 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct tsa_entries_area { 10162306a36Sopenharmony_ci void __iomem *entries_start; 10262306a36Sopenharmony_ci void __iomem *entries_next; 10362306a36Sopenharmony_ci void __iomem *last_entry; 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct tsa_tdm { 10762306a36Sopenharmony_ci bool is_enable; 10862306a36Sopenharmony_ci struct clk *l1rclk_clk; 10962306a36Sopenharmony_ci struct clk *l1rsync_clk; 11062306a36Sopenharmony_ci struct clk *l1tclk_clk; 11162306a36Sopenharmony_ci struct clk *l1tsync_clk; 11262306a36Sopenharmony_ci u32 simode_tdm; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define TSA_TDMA 0 11662306a36Sopenharmony_ci#define TSA_TDMB 1 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct tsa { 11962306a36Sopenharmony_ci struct device *dev; 12062306a36Sopenharmony_ci void __iomem *si_regs; 12162306a36Sopenharmony_ci void __iomem *si_ram; 12262306a36Sopenharmony_ci resource_size_t si_ram_sz; 12362306a36Sopenharmony_ci spinlock_t lock; 12462306a36Sopenharmony_ci int tdms; /* TSA_TDMx ORed */ 12562306a36Sopenharmony_ci struct tsa_tdm tdm[2]; /* TDMa and TDMb */ 12662306a36Sopenharmony_ci struct tsa_serial { 12762306a36Sopenharmony_ci unsigned int id; 12862306a36Sopenharmony_ci struct tsa_serial_info info; 12962306a36Sopenharmony_ci } serials[6]; 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline struct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci /* The serials table is indexed by the serial id */ 13562306a36Sopenharmony_ci return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline void tsa_write32(void __iomem *addr, u32 val) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci iowrite32be(val, addr); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic inline void tsa_write8(void __iomem *addr, u32 val) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci iowrite8(val, addr); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline u32 tsa_read32(void __iomem *addr) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci return ioread32be(addr); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline void tsa_clrbits32(void __iomem *addr, u32 clr) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci tsa_write32(addr, tsa_read32(addr) & ~clr); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci tsa_write32(addr, (tsa_read32(addr) & ~clr) | set); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciint tsa_serial_connect(struct tsa_serial *tsa_serial) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); 16662306a36Sopenharmony_ci unsigned long flags; 16762306a36Sopenharmony_ci u32 clear; 16862306a36Sopenharmony_ci u32 set; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci switch (tsa_serial->id) { 17162306a36Sopenharmony_ci case FSL_CPM_TSA_SCC2: 17262306a36Sopenharmony_ci clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); 17362306a36Sopenharmony_ci set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA); 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case FSL_CPM_TSA_SCC3: 17662306a36Sopenharmony_ci clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK); 17762306a36Sopenharmony_ci set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA); 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case FSL_CPM_TSA_SCC4: 18062306a36Sopenharmony_ci clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK); 18162306a36Sopenharmony_ci set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci default: 18462306a36Sopenharmony_ci dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); 18562306a36Sopenharmony_ci return -EINVAL; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci spin_lock_irqsave(&tsa->lock, flags); 18962306a36Sopenharmony_ci tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set); 19062306a36Sopenharmony_ci spin_unlock_irqrestore(&tsa->lock, flags); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ciEXPORT_SYMBOL(tsa_serial_connect); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciint tsa_serial_disconnect(struct tsa_serial *tsa_serial) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); 19962306a36Sopenharmony_ci unsigned long flags; 20062306a36Sopenharmony_ci u32 clear; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (tsa_serial->id) { 20362306a36Sopenharmony_ci case FSL_CPM_TSA_SCC2: 20462306a36Sopenharmony_ci clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case FSL_CPM_TSA_SCC3: 20762306a36Sopenharmony_ci clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK); 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case FSL_CPM_TSA_SCC4: 21062306a36Sopenharmony_ci clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK); 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci default: 21362306a36Sopenharmony_ci dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); 21462306a36Sopenharmony_ci return -EINVAL; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci spin_lock_irqsave(&tsa->lock, flags); 21862306a36Sopenharmony_ci tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0); 21962306a36Sopenharmony_ci spin_unlock_irqrestore(&tsa->lock, flags); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ciEXPORT_SYMBOL(tsa_serial_disconnect); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciint tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci memcpy(info, &tsa_serial->info, sizeof(*info)); 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ciEXPORT_SYMBOL(tsa_serial_get_info); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, 23362306a36Sopenharmony_ci u32 tdms, u32 tdm_id, bool is_rx) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci resource_size_t quarter; 23662306a36Sopenharmony_ci resource_size_t half; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci quarter = tsa->si_ram_sz/4; 23962306a36Sopenharmony_ci half = tsa->si_ram_sz/2; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (tdms == BIT(TSA_TDMA)) { 24262306a36Sopenharmony_ci /* Only TDMA */ 24362306a36Sopenharmony_ci if (is_rx) { 24462306a36Sopenharmony_ci /* First half of si_ram */ 24562306a36Sopenharmony_ci area->entries_start = tsa->si_ram; 24662306a36Sopenharmony_ci area->entries_next = area->entries_start + half; 24762306a36Sopenharmony_ci area->last_entry = NULL; 24862306a36Sopenharmony_ci } else { 24962306a36Sopenharmony_ci /* Second half of si_ram */ 25062306a36Sopenharmony_ci area->entries_start = tsa->si_ram + half; 25162306a36Sopenharmony_ci area->entries_next = area->entries_start + half; 25262306a36Sopenharmony_ci area->last_entry = NULL; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } else { 25562306a36Sopenharmony_ci /* Only TDMB or both TDMs */ 25662306a36Sopenharmony_ci if (tdm_id == TSA_TDMA) { 25762306a36Sopenharmony_ci if (is_rx) { 25862306a36Sopenharmony_ci /* First half of first half of si_ram */ 25962306a36Sopenharmony_ci area->entries_start = tsa->si_ram; 26062306a36Sopenharmony_ci area->entries_next = area->entries_start + quarter; 26162306a36Sopenharmony_ci area->last_entry = NULL; 26262306a36Sopenharmony_ci } else { 26362306a36Sopenharmony_ci /* First half of second half of si_ram */ 26462306a36Sopenharmony_ci area->entries_start = tsa->si_ram + (2 * quarter); 26562306a36Sopenharmony_ci area->entries_next = area->entries_start + quarter; 26662306a36Sopenharmony_ci area->last_entry = NULL; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci if (is_rx) { 27062306a36Sopenharmony_ci /* Second half of first half of si_ram */ 27162306a36Sopenharmony_ci area->entries_start = tsa->si_ram + quarter; 27262306a36Sopenharmony_ci area->entries_next = area->entries_start + quarter; 27362306a36Sopenharmony_ci area->last_entry = NULL; 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci /* Second half of second half of si_ram */ 27662306a36Sopenharmony_ci area->entries_start = tsa->si_ram + (3 * quarter); 27762306a36Sopenharmony_ci area->entries_next = area->entries_start + quarter; 27862306a36Sopenharmony_ci area->last_entry = NULL; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci switch (serial_id) { 28762306a36Sopenharmony_ci case FSL_CPM_TSA_NU: return "Not used"; 28862306a36Sopenharmony_ci case FSL_CPM_TSA_SCC2: return "SCC2"; 28962306a36Sopenharmony_ci case FSL_CPM_TSA_SCC3: return "SCC3"; 29062306a36Sopenharmony_ci case FSL_CPM_TSA_SCC4: return "SCC4"; 29162306a36Sopenharmony_ci case FSL_CPM_TSA_SMC1: return "SMC1"; 29262306a36Sopenharmony_ci case FSL_CPM_TSA_SMC2: return "SMC2"; 29362306a36Sopenharmony_ci default: 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci return NULL; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic u32 tsa_serial_id2csel(struct tsa *tsa, u32 serial_id) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci switch (serial_id) { 30262306a36Sopenharmony_ci case FSL_CPM_TSA_SCC2: return TSA_SIRAM_ENTRY_CSEL_SCC2; 30362306a36Sopenharmony_ci case FSL_CPM_TSA_SCC3: return TSA_SIRAM_ENTRY_CSEL_SCC3; 30462306a36Sopenharmony_ci case FSL_CPM_TSA_SCC4: return TSA_SIRAM_ENTRY_CSEL_SCC4; 30562306a36Sopenharmony_ci case FSL_CPM_TSA_SMC1: return TSA_SIRAM_ENTRY_CSEL_SMC1; 30662306a36Sopenharmony_ci case FSL_CPM_TSA_SMC2: return TSA_SIRAM_ENTRY_CSEL_SMC2; 30762306a36Sopenharmony_ci default: 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci return TSA_SIRAM_ENTRY_CSEL_NU; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, 31462306a36Sopenharmony_ci u32 count, u32 serial_id) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci void __iomem *addr; 31762306a36Sopenharmony_ci u32 left; 31862306a36Sopenharmony_ci u32 val; 31962306a36Sopenharmony_ci u32 cnt; 32062306a36Sopenharmony_ci u32 nb; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci addr = area->last_entry ? area->last_entry + 4 : area->entries_start; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci nb = DIV_ROUND_UP(count, 8); 32562306a36Sopenharmony_ci if ((addr + (nb * 4)) > area->entries_next) { 32662306a36Sopenharmony_ci dev_err(tsa->dev, "si ram area full\n"); 32762306a36Sopenharmony_ci return -ENOSPC; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (area->last_entry) { 33162306a36Sopenharmony_ci /* Clear last flag */ 33262306a36Sopenharmony_ci tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci left = count; 33662306a36Sopenharmony_ci while (left) { 33762306a36Sopenharmony_ci val = TSA_SIRAM_ENTRY_BYTE | tsa_serial_id2csel(tsa, serial_id); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (left > 16) { 34062306a36Sopenharmony_ci cnt = 16; 34162306a36Sopenharmony_ci } else { 34262306a36Sopenharmony_ci cnt = left; 34362306a36Sopenharmony_ci val |= TSA_SIRAM_ENTRY_LAST; 34462306a36Sopenharmony_ci area->last_entry = addr; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci val |= TSA_SIRAM_ENTRY_CNT(cnt - 1); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci tsa_write32(addr, val); 34962306a36Sopenharmony_ci addr += 4; 35062306a36Sopenharmony_ci left -= cnt; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np, 35762306a36Sopenharmony_ci u32 tdms, u32 tdm_id, bool is_rx) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct tsa_entries_area area; 36062306a36Sopenharmony_ci const char *route_name; 36162306a36Sopenharmony_ci u32 serial_id; 36262306a36Sopenharmony_ci int len, i; 36362306a36Sopenharmony_ci u32 count; 36462306a36Sopenharmony_ci const char *serial_name; 36562306a36Sopenharmony_ci struct tsa_serial_info *serial_info; 36662306a36Sopenharmony_ci struct tsa_tdm *tdm; 36762306a36Sopenharmony_ci int ret; 36862306a36Sopenharmony_ci u32 ts; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes"; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci len = of_property_count_u32_elems(tdm_np, route_name); 37362306a36Sopenharmony_ci if (len < 0) { 37462306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name); 37562306a36Sopenharmony_ci return len; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci if (len % 2 != 0) { 37862306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name); 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx); 38362306a36Sopenharmony_ci ts = 0; 38462306a36Sopenharmony_ci for (i = 0; i < len; i += 2) { 38562306a36Sopenharmony_ci of_property_read_u32_index(tdm_np, route_name, i, &count); 38662306a36Sopenharmony_ci of_property_read_u32_index(tdm_np, route_name, i + 1, &serial_id); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (serial_id >= ARRAY_SIZE(tsa->serials)) { 38962306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: invalid serial id (%u)\n", 39062306a36Sopenharmony_ci tdm_np, serial_id); 39162306a36Sopenharmony_ci return -EINVAL; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci serial_name = tsa_serial_id2name(tsa, serial_id); 39562306a36Sopenharmony_ci if (!serial_name) { 39662306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: unsupported serial id (%u)\n", 39762306a36Sopenharmony_ci tdm_np, serial_id); 39862306a36Sopenharmony_ci return -EINVAL; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n", 40262306a36Sopenharmony_ci tdm_id, route_name, ts, ts+count-1, serial_name); 40362306a36Sopenharmony_ci ts += count; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = tsa_add_entry(tsa, &area, count, serial_id); 40662306a36Sopenharmony_ci if (ret) 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci serial_info = &tsa->serials[serial_id].info; 41062306a36Sopenharmony_ci tdm = &tsa->tdm[tdm_id]; 41162306a36Sopenharmony_ci if (is_rx) { 41262306a36Sopenharmony_ci serial_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk); 41362306a36Sopenharmony_ci serial_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk); 41462306a36Sopenharmony_ci serial_info->nb_rx_ts += count; 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci serial_info->tx_fs_rate = tdm->l1tsync_clk ? 41762306a36Sopenharmony_ci clk_get_rate(tdm->l1tsync_clk) : 41862306a36Sopenharmony_ci clk_get_rate(tdm->l1rsync_clk); 41962306a36Sopenharmony_ci serial_info->tx_bit_rate = tdm->l1tclk_clk ? 42062306a36Sopenharmony_ci clk_get_rate(tdm->l1tclk_clk) : 42162306a36Sopenharmony_ci clk_get_rate(tdm->l1rclk_clk); 42262306a36Sopenharmony_ci serial_info->nb_tx_ts += count; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa, 42962306a36Sopenharmony_ci struct device_node *tdm_np, 43062306a36Sopenharmony_ci u32 tdms, u32 tdm_id) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa, 43662306a36Sopenharmony_ci struct device_node *tdm_np, 43762306a36Sopenharmony_ci u32 tdms, u32 tdm_id) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct device_node *tdm_np; 44562306a36Sopenharmony_ci struct tsa_tdm *tdm; 44662306a36Sopenharmony_ci struct clk *clk; 44762306a36Sopenharmony_ci u32 tdm_id, val; 44862306a36Sopenharmony_ci int ret; 44962306a36Sopenharmony_ci int i; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci tsa->tdms = 0; 45262306a36Sopenharmony_ci tsa->tdm[0].is_enable = false; 45362306a36Sopenharmony_ci tsa->tdm[1].is_enable = false; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci for_each_available_child_of_node(np, tdm_np) { 45662306a36Sopenharmony_ci ret = of_property_read_u32(tdm_np, "reg", &tdm_id); 45762306a36Sopenharmony_ci if (ret) { 45862306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np); 45962306a36Sopenharmony_ci of_node_put(tdm_np); 46062306a36Sopenharmony_ci return ret; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci switch (tdm_id) { 46362306a36Sopenharmony_ci case 0: 46462306a36Sopenharmony_ci tsa->tdms |= BIT(TSA_TDMA); 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci case 1: 46762306a36Sopenharmony_ci tsa->tdms |= BIT(TSA_TDMB); 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci default: 47062306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np, 47162306a36Sopenharmony_ci tdm_id); 47262306a36Sopenharmony_ci of_node_put(tdm_np); 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci for_each_available_child_of_node(np, tdm_np) { 47862306a36Sopenharmony_ci ret = of_property_read_u32(tdm_np, "reg", &tdm_id); 47962306a36Sopenharmony_ci if (ret) { 48062306a36Sopenharmony_ci dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np); 48162306a36Sopenharmony_ci of_node_put(tdm_np); 48262306a36Sopenharmony_ci return ret; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci tdm = &tsa->tdm[tdm_id]; 48662306a36Sopenharmony_ci tdm->simode_tdm = TSA_SIMODE_TDM_SDM_NORM; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci val = 0; 48962306a36Sopenharmony_ci ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits", 49062306a36Sopenharmony_ci &val); 49162306a36Sopenharmony_ci if (ret && ret != -EINVAL) { 49262306a36Sopenharmony_ci dev_err(tsa->dev, 49362306a36Sopenharmony_ci "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n", 49462306a36Sopenharmony_ci tdm_np); 49562306a36Sopenharmony_ci of_node_put(tdm_np); 49662306a36Sopenharmony_ci return ret; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci if (val > 3) { 49962306a36Sopenharmony_ci dev_err(tsa->dev, 50062306a36Sopenharmony_ci "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n", 50162306a36Sopenharmony_ci tdm_np, val); 50262306a36Sopenharmony_ci of_node_put(tdm_np); 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci val = 0; 50862306a36Sopenharmony_ci ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits", 50962306a36Sopenharmony_ci &val); 51062306a36Sopenharmony_ci if (ret && ret != -EINVAL) { 51162306a36Sopenharmony_ci dev_err(tsa->dev, 51262306a36Sopenharmony_ci "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n", 51362306a36Sopenharmony_ci tdm_np); 51462306a36Sopenharmony_ci of_node_put(tdm_np); 51562306a36Sopenharmony_ci return ret; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci if (val > 3) { 51862306a36Sopenharmony_ci dev_err(tsa->dev, 51962306a36Sopenharmony_ci "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n", 52062306a36Sopenharmony_ci tdm_np, val); 52162306a36Sopenharmony_ci of_node_put(tdm_np); 52262306a36Sopenharmony_ci return -EINVAL; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins")) 52762306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_CRT; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge")) 53062306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_CE; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge")) 53362306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_FE; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (of_property_read_bool(tdm_np, "fsl,double-speed-clock")) 53662306a36Sopenharmony_ci tdm->simode_tdm |= TSA_SIMODE_TDM_DSC; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci clk = of_clk_get_by_name(tdm_np, "l1rsync"); 53962306a36Sopenharmony_ci if (IS_ERR(clk)) { 54062306a36Sopenharmony_ci ret = PTR_ERR(clk); 54162306a36Sopenharmony_ci of_node_put(tdm_np); 54262306a36Sopenharmony_ci goto err; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 54562306a36Sopenharmony_ci if (ret) { 54662306a36Sopenharmony_ci clk_put(clk); 54762306a36Sopenharmony_ci of_node_put(tdm_np); 54862306a36Sopenharmony_ci goto err; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci tdm->l1rsync_clk = clk; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci clk = of_clk_get_by_name(tdm_np, "l1rclk"); 55362306a36Sopenharmony_ci if (IS_ERR(clk)) { 55462306a36Sopenharmony_ci ret = PTR_ERR(clk); 55562306a36Sopenharmony_ci of_node_put(tdm_np); 55662306a36Sopenharmony_ci goto err; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 55962306a36Sopenharmony_ci if (ret) { 56062306a36Sopenharmony_ci clk_put(clk); 56162306a36Sopenharmony_ci of_node_put(tdm_np); 56262306a36Sopenharmony_ci goto err; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci tdm->l1rclk_clk = clk; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) { 56762306a36Sopenharmony_ci clk = of_clk_get_by_name(tdm_np, "l1tsync"); 56862306a36Sopenharmony_ci if (IS_ERR(clk)) { 56962306a36Sopenharmony_ci ret = PTR_ERR(clk); 57062306a36Sopenharmony_ci of_node_put(tdm_np); 57162306a36Sopenharmony_ci goto err; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 57462306a36Sopenharmony_ci if (ret) { 57562306a36Sopenharmony_ci clk_put(clk); 57662306a36Sopenharmony_ci of_node_put(tdm_np); 57762306a36Sopenharmony_ci goto err; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci tdm->l1tsync_clk = clk; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci clk = of_clk_get_by_name(tdm_np, "l1tclk"); 58262306a36Sopenharmony_ci if (IS_ERR(clk)) { 58362306a36Sopenharmony_ci ret = PTR_ERR(clk); 58462306a36Sopenharmony_ci of_node_put(tdm_np); 58562306a36Sopenharmony_ci goto err; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 58862306a36Sopenharmony_ci if (ret) { 58962306a36Sopenharmony_ci clk_put(clk); 59062306a36Sopenharmony_ci of_node_put(tdm_np); 59162306a36Sopenharmony_ci goto err; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci tdm->l1tclk_clk = clk; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id); 59762306a36Sopenharmony_ci if (ret) { 59862306a36Sopenharmony_ci of_node_put(tdm_np); 59962306a36Sopenharmony_ci goto err; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id); 60362306a36Sopenharmony_ci if (ret) { 60462306a36Sopenharmony_ci of_node_put(tdm_np); 60562306a36Sopenharmony_ci goto err; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci tdm->is_enable = true; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cierr: 61362306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 61462306a36Sopenharmony_ci if (tsa->tdm[i].l1rsync_clk) { 61562306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); 61662306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rsync_clk); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci if (tsa->tdm[i].l1rclk_clk) { 61962306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); 62062306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rclk_clk); 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci if (tsa->tdm[i].l1tsync_clk) { 62362306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); 62462306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rsync_clk); 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci if (tsa->tdm[i].l1tclk_clk) { 62762306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); 62862306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rclk_clk); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic void tsa_init_si_ram(struct tsa *tsa) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci resource_size_t i; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Fill all entries as the last one */ 63962306a36Sopenharmony_ci for (i = 0; i < tsa->si_ram_sz; i += 4) 64062306a36Sopenharmony_ci tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int tsa_probe(struct platform_device *pdev) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 64662306a36Sopenharmony_ci struct resource *res; 64762306a36Sopenharmony_ci struct tsa *tsa; 64862306a36Sopenharmony_ci unsigned int i; 64962306a36Sopenharmony_ci u32 val; 65062306a36Sopenharmony_ci int ret; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL); 65362306a36Sopenharmony_ci if (!tsa) 65462306a36Sopenharmony_ci return -ENOMEM; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci tsa->dev = &pdev->dev; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tsa->serials); i++) 65962306a36Sopenharmony_ci tsa->serials[i].id = i; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci spin_lock_init(&tsa->lock); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs"); 66462306a36Sopenharmony_ci if (IS_ERR(tsa->si_regs)) 66562306a36Sopenharmony_ci return PTR_ERR(tsa->si_regs); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram"); 66862306a36Sopenharmony_ci if (!res) { 66962306a36Sopenharmony_ci dev_err(tsa->dev, "si_ram resource missing\n"); 67062306a36Sopenharmony_ci return -EINVAL; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci tsa->si_ram_sz = resource_size(res); 67362306a36Sopenharmony_ci tsa->si_ram = devm_ioremap_resource(&pdev->dev, res); 67462306a36Sopenharmony_ci if (IS_ERR(tsa->si_ram)) 67562306a36Sopenharmony_ci return PTR_ERR(tsa->si_ram); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci tsa_init_si_ram(tsa); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ret = tsa_of_parse_tdms(tsa, np); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci return ret; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Set SIMODE */ 68462306a36Sopenharmony_ci val = 0; 68562306a36Sopenharmony_ci if (tsa->tdm[0].is_enable) 68662306a36Sopenharmony_ci val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm); 68762306a36Sopenharmony_ci if (tsa->tdm[1].is_enable) 68862306a36Sopenharmony_ci val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE, 69162306a36Sopenharmony_ci TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) | 69262306a36Sopenharmony_ci TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK), 69362306a36Sopenharmony_ci val); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Set SIGMR */ 69662306a36Sopenharmony_ci val = (tsa->tdms == BIT(TSA_TDMA)) ? 69762306a36Sopenharmony_ci TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB; 69862306a36Sopenharmony_ci if (tsa->tdms & BIT(TSA_TDMA)) 69962306a36Sopenharmony_ci val |= TSA_SIGMR_ENA; 70062306a36Sopenharmony_ci if (tsa->tdms & BIT(TSA_TDMB)) 70162306a36Sopenharmony_ci val |= TSA_SIGMR_ENB; 70262306a36Sopenharmony_ci tsa_write8(tsa->si_regs + TSA_SIGMR, val); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci platform_set_drvdata(pdev, tsa); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int tsa_remove(struct platform_device *pdev) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct tsa *tsa = platform_get_drvdata(pdev); 71262306a36Sopenharmony_ci int i; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 71562306a36Sopenharmony_ci if (tsa->tdm[i].l1rsync_clk) { 71662306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); 71762306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rsync_clk); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci if (tsa->tdm[i].l1rclk_clk) { 72062306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); 72162306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rclk_clk); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci if (tsa->tdm[i].l1tsync_clk) { 72462306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rsync_clk); 72562306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rsync_clk); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci if (tsa->tdm[i].l1tclk_clk) { 72862306a36Sopenharmony_ci clk_disable_unprepare(tsa->tdm[i].l1rclk_clk); 72962306a36Sopenharmony_ci clk_put(tsa->tdm[i].l1rclk_clk); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic const struct of_device_id tsa_id_table[] = { 73662306a36Sopenharmony_ci { .compatible = "fsl,cpm1-tsa" }, 73762306a36Sopenharmony_ci {} /* sentinel */ 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tsa_id_table); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic struct platform_driver tsa_driver = { 74262306a36Sopenharmony_ci .driver = { 74362306a36Sopenharmony_ci .name = "fsl-tsa", 74462306a36Sopenharmony_ci .of_match_table = of_match_ptr(tsa_id_table), 74562306a36Sopenharmony_ci }, 74662306a36Sopenharmony_ci .probe = tsa_probe, 74762306a36Sopenharmony_ci .remove = tsa_remove, 74862306a36Sopenharmony_ci}; 74962306a36Sopenharmony_cimodule_platform_driver(tsa_driver); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistruct tsa_serial *tsa_serial_get_byphandle(struct device_node *np, 75262306a36Sopenharmony_ci const char *phandle_name) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct of_phandle_args out_args; 75562306a36Sopenharmony_ci struct platform_device *pdev; 75662306a36Sopenharmony_ci struct tsa_serial *tsa_serial; 75762306a36Sopenharmony_ci struct tsa *tsa; 75862306a36Sopenharmony_ci int ret; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, &out_args); 76162306a36Sopenharmony_ci if (ret < 0) 76262306a36Sopenharmony_ci return ERR_PTR(ret); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (!of_match_node(tsa_driver.driver.of_match_table, out_args.np)) { 76562306a36Sopenharmony_ci of_node_put(out_args.np); 76662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci pdev = of_find_device_by_node(out_args.np); 77062306a36Sopenharmony_ci of_node_put(out_args.np); 77162306a36Sopenharmony_ci if (!pdev) 77262306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci tsa = platform_get_drvdata(pdev); 77562306a36Sopenharmony_ci if (!tsa) { 77662306a36Sopenharmony_ci platform_device_put(pdev); 77762306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (out_args.args_count != 1) { 78162306a36Sopenharmony_ci platform_device_put(pdev); 78262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (out_args.args[0] >= ARRAY_SIZE(tsa->serials)) { 78662306a36Sopenharmony_ci platform_device_put(pdev); 78762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci tsa_serial = &tsa->serials[out_args.args[0]]; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* 79362306a36Sopenharmony_ci * Be sure that the serial id matches the phandle arg. 79462306a36Sopenharmony_ci * The tsa_serials table is indexed by serial ids. The serial id is set 79562306a36Sopenharmony_ci * during the probe() call and needs to be coherent. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci if (WARN_ON(tsa_serial->id != out_args.args[0])) { 79862306a36Sopenharmony_ci platform_device_put(pdev); 79962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return tsa_serial; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ciEXPORT_SYMBOL(tsa_serial_get_byphandle); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_civoid tsa_serial_put(struct tsa_serial *tsa_serial) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci put_device(tsa->dev); 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ciEXPORT_SYMBOL(tsa_serial_put); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void devm_tsa_serial_release(struct device *dev, void *res) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct tsa_serial **tsa_serial = res; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci tsa_serial_put(*tsa_serial); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistruct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev, 82262306a36Sopenharmony_ci struct device_node *np, 82362306a36Sopenharmony_ci const char *phandle_name) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct tsa_serial *tsa_serial; 82662306a36Sopenharmony_ci struct tsa_serial **dr; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci dr = devres_alloc(devm_tsa_serial_release, sizeof(*dr), GFP_KERNEL); 82962306a36Sopenharmony_ci if (!dr) 83062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci tsa_serial = tsa_serial_get_byphandle(np, phandle_name); 83362306a36Sopenharmony_ci if (!IS_ERR(tsa_serial)) { 83462306a36Sopenharmony_ci *dr = tsa_serial; 83562306a36Sopenharmony_ci devres_add(dev, dr); 83662306a36Sopenharmony_ci } else { 83762306a36Sopenharmony_ci devres_free(dr); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return tsa_serial; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ciEXPORT_SYMBOL(devm_tsa_serial_get_byphandle); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ciMODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 84562306a36Sopenharmony_ciMODULE_DESCRIPTION("CPM TSA driver"); 84662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 847