1189 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * TSA driver4 *5 * Copyright 2022 CS GROUP France6 *7 * Author: Herve Codina <herve.codina@bootlin.com>8 */9 10#include "tsa.h"11#include <dt-bindings/soc/cpm1-fsl,tsa.h>12#include <dt-bindings/soc/qe-fsl,tsa.h>13#include <linux/bitfield.h>14#include <linux/clk.h>15#include <linux/io.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/of_platform.h>19#include <linux/platform_device.h>20#include <linux/slab.h>21#include <soc/fsl/qe/ucc.h>22 23/* TSA SI RAM routing tables entry (CPM1) */24#define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16)25#define TSA_CPM1_SIRAM_ENTRY_BYTE BIT(17)26#define TSA_CPM1_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18)27#define TSA_CPM1_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_CPM1_SIRAM_ENTRY_CNT_MASK, x)28#define TSA_CPM1_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22)29#define TSA_CPM1_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x0)30#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x2)31#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x3)32#define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x4)33#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x5)34#define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6)35 36/* TSA SI RAM routing tables entry (QE) */37#define TSA_QE_SIRAM_ENTRY_LAST BIT(0)38#define TSA_QE_SIRAM_ENTRY_BYTE BIT(1)39#define TSA_QE_SIRAM_ENTRY_CNT_MASK GENMASK(4, 2)40#define TSA_QE_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_QE_SIRAM_ENTRY_CNT_MASK, x)41#define TSA_QE_SIRAM_ENTRY_CSEL_MASK GENMASK(8, 5)42#define TSA_QE_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x0)43#define TSA_QE_SIRAM_ENTRY_CSEL_UCC5 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x1)44#define TSA_QE_SIRAM_ENTRY_CSEL_UCC1 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x9)45#define TSA_QE_SIRAM_ENTRY_CSEL_UCC2 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xa)46#define TSA_QE_SIRAM_ENTRY_CSEL_UCC3 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xb)47#define TSA_QE_SIRAM_ENTRY_CSEL_UCC4 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xc)48 49/*50 * SI mode register :51 * - CPM1: 32bit register split in 2*16bit (16bit TDM)52 * - QE: 4x16bit registers, one per TDM53 */54#define TSA_CPM1_SIMODE 0x0055#define TSA_QE_SIAMR 0x0056#define TSA_QE_SIBMR 0x0257#define TSA_QE_SICMR 0x0458#define TSA_QE_SIDMR 0x0659#define TSA_CPM1_SIMODE_SMC2 BIT(31)60#define TSA_CPM1_SIMODE_SMC1 BIT(15)61#define TSA_CPM1_SIMODE_TDMA_MASK GENMASK(11, 0)62#define TSA_CPM1_SIMODE_TDMA(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMA_MASK, x)63#define TSA_CPM1_SIMODE_TDMB_MASK GENMASK(27, 16)64#define TSA_CPM1_SIMODE_TDMB(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMB_MASK, x)65#define TSA_QE_SIMODE_TDM_SAD_MASK GENMASK(15, 12)66#define TSA_QE_SIMODE_TDM_SAD(x) FIELD_PREP(TSA_QE_SIMODE_TDM_SAD_MASK, x)67#define TSA_CPM1_SIMODE_TDM_MASK GENMASK(11, 0)68#define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10)69#define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0)70#define TSA_SIMODE_TDM_SDM_ECHO FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x1)71#define TSA_SIMODE_TDM_SDM_INTL_LOOP FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x2)72#define TSA_SIMODE_TDM_SDM_LOOP_CTRL FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x3)73#define TSA_SIMODE_TDM_RFSD_MASK GENMASK(9, 8)74#define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x)75#define TSA_SIMODE_TDM_DSC BIT(7)76#define TSA_SIMODE_TDM_CRT BIT(6)77#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) /* bit 5: STZ in CPM1 */78#define TSA_QE_SIMODE_TDM_SL BIT(5) /* bit 5: SL in QE */79#define TSA_SIMODE_TDM_CE BIT(4)80#define TSA_SIMODE_TDM_FE BIT(3)81#define TSA_SIMODE_TDM_GM BIT(2)82#define TSA_SIMODE_TDM_TFSD_MASK GENMASK(1, 0)83#define TSA_SIMODE_TDM_TFSD(x) FIELD_PREP(TSA_SIMODE_TDM_TFSD_MASK, x)84 85/* CPM SI global mode register (8 bits) */86#define TSA_CPM1_SIGMR 0x0487#define TSA_CPM1_SIGMR_ENB BIT(3)88#define TSA_CPM1_SIGMR_ENA BIT(2)89#define TSA_CPM1_SIGMR_RDM_MASK GENMASK(1, 0)90#define TSA_CPM1_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x0)91#define TSA_CPM1_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x1)92#define TSA_CPM1_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x2)93#define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3)94 95/* QE SI global mode register high (8 bits) */96#define TSA_QE_SIGLMRH 0x0897#define TSA_QE_SIGLMRH_END BIT(3)98#define TSA_QE_SIGLMRH_ENC BIT(2)99#define TSA_QE_SIGLMRH_ENB BIT(1)100#define TSA_QE_SIGLMRH_ENA BIT(0)101 102/* SI clock route register (32 bits) */103#define TSA_CPM1_SICR 0x0C104#define TSA_CPM1_SICR_SCC2_MASK GENMASK(15, 8)105#define TSA_CPM1_SICR_SCC2(x) FIELD_PREP(TSA_CPM1_SICR_SCC2_MASK, x)106#define TSA_CPM1_SICR_SCC3_MASK GENMASK(23, 16)107#define TSA_CPM1_SICR_SCC3(x) FIELD_PREP(TSA_CPM1_SICR_SCC3_MASK, x)108#define TSA_CPM1_SICR_SCC4_MASK GENMASK(31, 24)109#define TSA_CPM1_SICR_SCC4(x) FIELD_PREP(TSA_CPM1_SICR_SCC4_MASK, x)110#define TSA_CPM1_SICR_SCC_MASK GENMASK(7, 0)111#define TSA_CPM1_SICR_SCC_GRX BIT(7)112#define TSA_CPM1_SICR_SCC_SCX_TSA BIT(6)113#define TSA_CPM1_SICR_SCC_RXCS_MASK GENMASK(5, 3)114#define TSA_CPM1_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x0)115#define TSA_CPM1_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x1)116#define TSA_CPM1_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x2)117#define TSA_CPM1_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x3)118#define TSA_CPM1_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x4)119#define TSA_CPM1_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x5)120#define TSA_CPM1_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x6)121#define TSA_CPM1_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x7)122#define TSA_CPM1_SICR_SCC_TXCS_MASK GENMASK(2, 0)123#define TSA_CPM1_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x0)124#define TSA_CPM1_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x1)125#define TSA_CPM1_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x2)126#define TSA_CPM1_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x3)127#define TSA_CPM1_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x4)128#define TSA_CPM1_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x5)129#define TSA_CPM1_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x6)130#define TSA_CPM1_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x7)131 132struct tsa_entries_area {133 void __iomem *entries_start;134 void __iomem *entries_next;135 void __iomem *last_entry;136};137 138struct tsa_tdm {139 bool is_enable;140 struct clk *l1rclk_clk;141 struct clk *l1rsync_clk;142 struct clk *l1tclk_clk;143 struct clk *l1tsync_clk;144 u32 simode_tdm;145};146 147#define TSA_TDMA 0148#define TSA_TDMB 1149#define TSA_TDMC 2 /* QE implementation only */150#define TSA_TDMD 3 /* QE implementation only */151 152enum tsa_version {153 TSA_CPM1 = 1, /* Avoid 0 value */154 TSA_QE,155};156 157struct tsa {158 struct device *dev;159 void __iomem *si_regs;160 void __iomem *si_ram;161 resource_size_t si_ram_sz;162 spinlock_t lock; /* Lock for read/modify/write sequence */163 enum tsa_version version;164 int tdms; /* TSA_TDMx ORed */165#if IS_ENABLED(CONFIG_QUICC_ENGINE)166 struct tsa_tdm tdm[4]; /* TDMa, TDMb, TDMc and TDMd */167#else168 struct tsa_tdm tdm[2]; /* TDMa and TDMb */169#endif170 /* Same number of serials for CPM1 and QE:171 * CPM1: NU, 3 SCCs and 2 SMCs172 * QE: NU and 5 UCCs173 */174 struct tsa_serial {175 unsigned int id;176 struct tsa_serial_info info;177 } serials[6];178};179 180static inline struct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial)181{182 /* The serials table is indexed by the serial id */183 return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]);184}185 186static inline void tsa_write32(void __iomem *addr, u32 val)187{188 iowrite32be(val, addr);189}190 191static inline void tsa_write16(void __iomem *addr, u16 val)192{193 iowrite16be(val, addr);194}195 196static inline void tsa_write8(void __iomem *addr, u8 val)197{198 iowrite8(val, addr);199}200 201static inline u32 tsa_read32(void __iomem *addr)202{203 return ioread32be(addr);204}205 206static inline u16 tsa_read16(void __iomem *addr)207{208 return ioread16be(addr);209}210 211static inline void tsa_clrbits32(void __iomem *addr, u32 clr)212{213 tsa_write32(addr, tsa_read32(addr) & ~clr);214}215 216static inline void tsa_clrbits16(void __iomem *addr, u16 clr)217{218 tsa_write16(addr, tsa_read16(addr) & ~clr);219}220 221static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set)222{223 tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);224}225 226static bool tsa_is_qe(const struct tsa *tsa)227{228 if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))229 return tsa->version == TSA_QE;230 231 return IS_ENABLED(CONFIG_QUICC_ENGINE);232}233 234static int tsa_qe_serial_get_num(struct tsa_serial *tsa_serial)235{236 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);237 238 switch (tsa_serial->id) {239 case FSL_QE_TSA_UCC1: return 0;240 case FSL_QE_TSA_UCC2: return 1;241 case FSL_QE_TSA_UCC3: return 2;242 case FSL_QE_TSA_UCC4: return 3;243 case FSL_QE_TSA_UCC5: return 4;244 default:245 break;246 }247 248 dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);249 return -EINVAL;250}251 252int tsa_serial_get_num(struct tsa_serial *tsa_serial)253{254 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);255 256 /*257 * There is no need to get the serial num out of the TSA driver in the258 * CPM case.259 * Further more, in CPM, we can have 2 types of serial SCCs and FCCs.260 * What kind of numbering to use that can be global to both SCCs and261 * FCCs ?262 */263 return tsa_is_qe(tsa) ? tsa_qe_serial_get_num(tsa_serial) : -EOPNOTSUPP;264}265EXPORT_SYMBOL(tsa_serial_get_num);266 267static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect)268{269 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);270 unsigned long flags;271 u32 clear;272 u32 set;273 274 switch (tsa_serial->id) {275 case FSL_CPM_TSA_SCC2:276 clear = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_MASK);277 set = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_SCX_TSA);278 break;279 case FSL_CPM_TSA_SCC3:280 clear = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_MASK);281 set = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_SCX_TSA);282 break;283 case FSL_CPM_TSA_SCC4:284 clear = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_MASK);285 set = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_SCX_TSA);286 break;287 default:288 dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);289 return -EINVAL;290 }291 292 spin_lock_irqsave(&tsa->lock, flags);293 tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear,294 connect ? set : 0);295 spin_unlock_irqrestore(&tsa->lock, flags);296 297 return 0;298}299 300static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect)301{302 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);303 unsigned long flags;304 int ucc_num;305 int ret;306 307 ucc_num = tsa_qe_serial_get_num(tsa_serial);308 if (ucc_num < 0)309 return ucc_num;310 311 spin_lock_irqsave(&tsa->lock, flags);312 ret = ucc_set_qe_mux_tsa(ucc_num, connect);313 spin_unlock_irqrestore(&tsa->lock, flags);314 if (ret) {315 dev_err(tsa->dev, "Connect serial id %u to TSA failed (%d)\n",316 tsa_serial->id, ret);317 return ret;318 }319 return 0;320}321 322int tsa_serial_connect(struct tsa_serial *tsa_serial)323{324 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);325 326 return tsa_is_qe(tsa) ?327 tsa_qe_serial_connect(tsa_serial, true) :328 tsa_cpm1_serial_connect(tsa_serial, true);329}330EXPORT_SYMBOL(tsa_serial_connect);331 332int tsa_serial_disconnect(struct tsa_serial *tsa_serial)333{334 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);335 336 return tsa_is_qe(tsa) ?337 tsa_qe_serial_connect(tsa_serial, false) :338 tsa_cpm1_serial_connect(tsa_serial, false);339}340EXPORT_SYMBOL(tsa_serial_disconnect);341 342int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info)343{344 memcpy(info, &tsa_serial->info, sizeof(*info));345 return 0;346}347EXPORT_SYMBOL(tsa_serial_get_info);348 349static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,350 u32 tdms, u32 tdm_id, bool is_rx)351{352 resource_size_t quarter;353 resource_size_t half;354 355 quarter = tsa->si_ram_sz / 4;356 half = tsa->si_ram_sz / 2;357 358 if (tdms == BIT(TSA_TDMA)) {359 /* Only TDMA */360 if (is_rx) {361 /* First half of si_ram */362 area->entries_start = tsa->si_ram;363 area->entries_next = area->entries_start + half;364 area->last_entry = NULL;365 } else {366 /* Second half of si_ram */367 area->entries_start = tsa->si_ram + half;368 area->entries_next = area->entries_start + half;369 area->last_entry = NULL;370 }371 } else {372 /* Only TDMB or both TDMs */373 if (tdm_id == TSA_TDMA) {374 if (is_rx) {375 /* First half of first half of si_ram */376 area->entries_start = tsa->si_ram;377 area->entries_next = area->entries_start + quarter;378 area->last_entry = NULL;379 } else {380 /* First half of second half of si_ram */381 area->entries_start = tsa->si_ram + (2 * quarter);382 area->entries_next = area->entries_start + quarter;383 area->last_entry = NULL;384 }385 } else {386 if (is_rx) {387 /* Second half of first half of si_ram */388 area->entries_start = tsa->si_ram + quarter;389 area->entries_next = area->entries_start + quarter;390 area->last_entry = NULL;391 } else {392 /* Second half of second half of si_ram */393 area->entries_start = tsa->si_ram + (3 * quarter);394 area->entries_next = area->entries_start + quarter;395 area->last_entry = NULL;396 }397 }398 }399}400 401static void tsa_qe_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,402 u32 tdms, u32 tdm_id, bool is_rx)403{404 resource_size_t eighth;405 resource_size_t half;406 407 eighth = tsa->si_ram_sz / 8;408 half = tsa->si_ram_sz / 2;409 410 /*411 * One half of the SI RAM used for Tx, the other one for Rx.412 * In each half, 1/4 of the area is assigned to each TDM.413 */414 if (is_rx) {415 /* Rx: Second half of si_ram */416 area->entries_start = tsa->si_ram + half + (eighth * tdm_id);417 area->entries_next = area->entries_start + eighth;418 area->last_entry = NULL;419 } else {420 /* Tx: First half of si_ram */421 area->entries_start = tsa->si_ram + (eighth * tdm_id);422 area->entries_next = area->entries_start + eighth;423 area->last_entry = NULL;424 }425}426 427static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,428 u32 tdms, u32 tdm_id, bool is_rx)429{430 if (tsa_is_qe(tsa))431 tsa_qe_init_entries_area(tsa, area, tdms, tdm_id, is_rx);432 else433 tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx);434}435 436static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id)437{438 switch (serial_id) {439 case FSL_CPM_TSA_NU: return "Not used";440 case FSL_CPM_TSA_SCC2: return "SCC2";441 case FSL_CPM_TSA_SCC3: return "SCC3";442 case FSL_CPM_TSA_SCC4: return "SCC4";443 case FSL_CPM_TSA_SMC1: return "SMC1";444 case FSL_CPM_TSA_SMC2: return "SMC2";445 default:446 break;447 }448 return NULL;449}450 451static const char *tsa_qe_serial_id2name(struct tsa *tsa, u32 serial_id)452{453 switch (serial_id) {454 case FSL_QE_TSA_NU: return "Not used";455 case FSL_QE_TSA_UCC1: return "UCC1";456 case FSL_QE_TSA_UCC2: return "UCC2";457 case FSL_QE_TSA_UCC3: return "UCC3";458 case FSL_QE_TSA_UCC4: return "UCC4";459 case FSL_QE_TSA_UCC5: return "UCC5";460 default:461 break;462 }463 return NULL;464}465 466static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id)467{468 return tsa_is_qe(tsa) ?469 tsa_qe_serial_id2name(tsa, serial_id) :470 tsa_cpm1_serial_id2name(tsa, serial_id);471}472 473static u32 tsa_cpm1_serial_id2csel(struct tsa *tsa, u32 serial_id)474{475 switch (serial_id) {476 case FSL_CPM_TSA_SCC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2;477 case FSL_CPM_TSA_SCC3: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3;478 case FSL_CPM_TSA_SCC4: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4;479 case FSL_CPM_TSA_SMC1: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1;480 case FSL_CPM_TSA_SMC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2;481 default:482 break;483 }484 return TSA_CPM1_SIRAM_ENTRY_CSEL_NU;485}486 487static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area,488 u32 count, u32 serial_id)489{490 void __iomem *addr;491 u32 left;492 u32 val;493 u32 cnt;494 u32 nb;495 496 addr = area->last_entry ? area->last_entry + 4 : area->entries_start;497 498 nb = DIV_ROUND_UP(count, 8);499 if ((addr + (nb * 4)) > area->entries_next) {500 dev_err(tsa->dev, "si ram area full\n");501 return -ENOSPC;502 }503 504 if (area->last_entry) {505 /* Clear last flag */506 tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST);507 }508 509 left = count;510 while (left) {511 val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id);512 513 if (left > 16) {514 cnt = 16;515 } else {516 cnt = left;517 val |= TSA_CPM1_SIRAM_ENTRY_LAST;518 area->last_entry = addr;519 }520 val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1);521 522 tsa_write32(addr, val);523 addr += 4;524 left -= cnt;525 }526 527 return 0;528}529 530static u32 tsa_qe_serial_id2csel(struct tsa *tsa, u32 serial_id)531{532 switch (serial_id) {533 case FSL_QE_TSA_UCC1: return TSA_QE_SIRAM_ENTRY_CSEL_UCC1;534 case FSL_QE_TSA_UCC2: return TSA_QE_SIRAM_ENTRY_CSEL_UCC2;535 case FSL_QE_TSA_UCC3: return TSA_QE_SIRAM_ENTRY_CSEL_UCC3;536 case FSL_QE_TSA_UCC4: return TSA_QE_SIRAM_ENTRY_CSEL_UCC4;537 case FSL_QE_TSA_UCC5: return TSA_QE_SIRAM_ENTRY_CSEL_UCC5;538 default:539 break;540 }541 return TSA_QE_SIRAM_ENTRY_CSEL_NU;542}543 544static int tsa_qe_add_entry(struct tsa *tsa, struct tsa_entries_area *area,545 u32 count, u32 serial_id)546{547 void __iomem *addr;548 u32 left;549 u32 val;550 u32 cnt;551 u32 nb;552 553 addr = area->last_entry ? area->last_entry + 2 : area->entries_start;554 555 nb = DIV_ROUND_UP(count, 8);556 if ((addr + (nb * 2)) > area->entries_next) {557 dev_err(tsa->dev, "si ram area full\n");558 return -ENOSPC;559 }560 561 if (area->last_entry) {562 /* Clear last flag */563 tsa_clrbits16(area->last_entry, TSA_QE_SIRAM_ENTRY_LAST);564 }565 566 left = count;567 while (left) {568 val = TSA_QE_SIRAM_ENTRY_BYTE | tsa_qe_serial_id2csel(tsa, serial_id);569 570 if (left > 8) {571 cnt = 8;572 } else {573 cnt = left;574 val |= TSA_QE_SIRAM_ENTRY_LAST;575 area->last_entry = addr;576 }577 val |= TSA_QE_SIRAM_ENTRY_CNT(cnt - 1);578 579 tsa_write16(addr, val);580 addr += 2;581 left -= cnt;582 }583 584 return 0;585}586 587static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,588 u32 count, u32 serial_id)589{590 return tsa_is_qe(tsa) ?591 tsa_qe_add_entry(tsa, area, count, serial_id) :592 tsa_cpm1_add_entry(tsa, area, count, serial_id);593}594 595static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,596 u32 tdms, u32 tdm_id, bool is_rx)597{598 struct tsa_entries_area area;599 const char *route_name;600 u32 serial_id;601 int len, i;602 u32 count;603 const char *serial_name;604 struct tsa_serial_info *serial_info;605 struct tsa_tdm *tdm;606 int ret;607 u32 ts;608 609 route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";610 611 len = of_property_count_u32_elems(tdm_np, route_name);612 if (len < 0) {613 dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);614 return len;615 }616 if (len % 2 != 0) {617 dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);618 return -EINVAL;619 }620 621 tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);622 ts = 0;623 for (i = 0; i < len; i += 2) {624 of_property_read_u32_index(tdm_np, route_name, i, &count);625 of_property_read_u32_index(tdm_np, route_name, i + 1, &serial_id);626 627 if (serial_id >= ARRAY_SIZE(tsa->serials)) {628 dev_err(tsa->dev, "%pOF: invalid serial id (%u)\n",629 tdm_np, serial_id);630 return -EINVAL;631 }632 633 serial_name = tsa_serial_id2name(tsa, serial_id);634 if (!serial_name) {635 dev_err(tsa->dev, "%pOF: unsupported serial id (%u)\n",636 tdm_np, serial_id);637 return -EINVAL;638 }639 640 dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",641 tdm_id, route_name, ts, ts + count - 1, serial_name);642 ts += count;643 644 ret = tsa_add_entry(tsa, &area, count, serial_id);645 if (ret)646 return ret;647 648 serial_info = &tsa->serials[serial_id].info;649 tdm = &tsa->tdm[tdm_id];650 if (is_rx) {651 serial_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);652 serial_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);653 serial_info->nb_rx_ts += count;654 } else {655 serial_info->tx_fs_rate = tdm->l1tsync_clk ?656 clk_get_rate(tdm->l1tsync_clk) :657 clk_get_rate(tdm->l1rsync_clk);658 serial_info->tx_bit_rate = tdm->l1tclk_clk ?659 clk_get_rate(tdm->l1tclk_clk) :660 clk_get_rate(tdm->l1rclk_clk);661 serial_info->nb_tx_ts += count;662 }663 }664 return 0;665}666 667static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,668 struct device_node *tdm_np,669 u32 tdms, u32 tdm_id)670{671 return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);672}673 674static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,675 struct device_node *tdm_np,676 u32 tdms, u32 tdm_id)677{678 return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);679}680 681static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)682{683 struct device_node *tdm_np;684 struct tsa_tdm *tdm;685 struct clk *clk;686 u32 tdm_id, val;687 int ret;688 int i;689 690 tsa->tdms = 0;691 for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++)692 tsa->tdm[i].is_enable = false;693 694 for_each_available_child_of_node(np, tdm_np) {695 ret = of_property_read_u32(tdm_np, "reg", &tdm_id);696 if (ret) {697 dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);698 of_node_put(tdm_np);699 return ret;700 }701 switch (tdm_id) {702 case 0:703 tsa->tdms |= BIT(TSA_TDMA);704 break;705 case 1:706 tsa->tdms |= BIT(TSA_TDMB);707 break;708 case 2:709 if (!tsa_is_qe(tsa))710 goto invalid_tdm; /* Not available on CPM1 */711 tsa->tdms |= BIT(TSA_TDMC);712 break;713 case 3:714 if (!tsa_is_qe(tsa))715 goto invalid_tdm; /* Not available on CPM1 */716 tsa->tdms |= BIT(TSA_TDMD);717 break;718 default:719invalid_tdm:720 dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,721 tdm_id);722 of_node_put(tdm_np);723 return -EINVAL;724 }725 }726 727 for_each_available_child_of_node(np, tdm_np) {728 ret = of_property_read_u32(tdm_np, "reg", &tdm_id);729 if (ret) {730 dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);731 of_node_put(tdm_np);732 return ret;733 }734 735 tdm = &tsa->tdm[tdm_id];736 tdm->simode_tdm = TSA_SIMODE_TDM_SDM_NORM;737 738 val = 0;739 ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",740 &val);741 if (ret && ret != -EINVAL) {742 dev_err(tsa->dev,743 "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",744 tdm_np);745 of_node_put(tdm_np);746 return ret;747 }748 if (val > 3) {749 dev_err(tsa->dev,750 "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",751 tdm_np, val);752 of_node_put(tdm_np);753 return -EINVAL;754 }755 tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);756 757 val = 0;758 ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",759 &val);760 if (ret && ret != -EINVAL) {761 dev_err(tsa->dev,762 "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",763 tdm_np);764 of_node_put(tdm_np);765 return ret;766 }767 if (val > 3) {768 dev_err(tsa->dev,769 "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",770 tdm_np, val);771 of_node_put(tdm_np);772 return -EINVAL;773 }774 tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);775 776 if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))777 tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;778 779 if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))780 tdm->simode_tdm |= TSA_SIMODE_TDM_CE;781 782 if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))783 tdm->simode_tdm |= TSA_SIMODE_TDM_FE;784 785 if (tsa_is_qe(tsa) &&786 of_property_read_bool(tdm_np, "fsl,fsync-active-low"))787 tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SL;788 789 if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))790 tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;791 792 clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync");793 if (IS_ERR(clk)) {794 ret = PTR_ERR(clk);795 of_node_put(tdm_np);796 goto err;797 }798 ret = clk_prepare_enable(clk);799 if (ret) {800 clk_put(clk);801 of_node_put(tdm_np);802 goto err;803 }804 tdm->l1rsync_clk = clk;805 806 clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk");807 if (IS_ERR(clk)) {808 ret = PTR_ERR(clk);809 of_node_put(tdm_np);810 goto err;811 }812 ret = clk_prepare_enable(clk);813 if (ret) {814 clk_put(clk);815 of_node_put(tdm_np);816 goto err;817 }818 tdm->l1rclk_clk = clk;819 820 if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {821 clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync");822 if (IS_ERR(clk)) {823 ret = PTR_ERR(clk);824 of_node_put(tdm_np);825 goto err;826 }827 ret = clk_prepare_enable(clk);828 if (ret) {829 clk_put(clk);830 of_node_put(tdm_np);831 goto err;832 }833 tdm->l1tsync_clk = clk;834 835 clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk");836 if (IS_ERR(clk)) {837 ret = PTR_ERR(clk);838 of_node_put(tdm_np);839 goto err;840 }841 ret = clk_prepare_enable(clk);842 if (ret) {843 clk_put(clk);844 of_node_put(tdm_np);845 goto err;846 }847 tdm->l1tclk_clk = clk;848 }849 850 if (tsa_is_qe(tsa)) {851 /*852 * The starting address for TSA table must be set.853 * 512 entries for Tx and 512 entries for Rx are854 * available for 4 TDMs.855 * We assign entries equally -> 128 Rx/Tx entries per856 * TDM. In other words, 4 blocks of 32 entries per TDM.857 */858 tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SAD(4 * tdm_id);859 }860 861 ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);862 if (ret) {863 of_node_put(tdm_np);864 goto err;865 }866 867 ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);868 if (ret) {869 of_node_put(tdm_np);870 goto err;871 }872 873 tdm->is_enable = true;874 }875 return 0;876 877err:878 for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {879 if (tsa->tdm[i].l1rsync_clk) {880 clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);881 clk_put(tsa->tdm[i].l1rsync_clk);882 }883 if (tsa->tdm[i].l1rclk_clk) {884 clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);885 clk_put(tsa->tdm[i].l1rclk_clk);886 }887 if (tsa->tdm[i].l1tsync_clk) {888 clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);889 clk_put(tsa->tdm[i].l1rsync_clk);890 }891 if (tsa->tdm[i].l1tclk_clk) {892 clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);893 clk_put(tsa->tdm[i].l1rclk_clk);894 }895 }896 return ret;897}898 899static void tsa_init_si_ram(struct tsa *tsa)900{901 resource_size_t i;902 903 /* Fill all entries as the last one */904 if (tsa_is_qe(tsa)) {905 for (i = 0; i < tsa->si_ram_sz; i += 2)906 tsa_write16(tsa->si_ram + i, TSA_QE_SIRAM_ENTRY_LAST);907 } else {908 for (i = 0; i < tsa->si_ram_sz; i += 4)909 tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST);910 }911}912 913static int tsa_cpm1_setup(struct tsa *tsa)914{915 u32 val;916 917 /* Set SIMODE */918 val = 0;919 if (tsa->tdm[0].is_enable)920 val |= TSA_CPM1_SIMODE_TDMA(tsa->tdm[0].simode_tdm);921 if (tsa->tdm[1].is_enable)922 val |= TSA_CPM1_SIMODE_TDMB(tsa->tdm[1].simode_tdm);923 924 tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SIMODE,925 TSA_CPM1_SIMODE_TDMA(TSA_CPM1_SIMODE_TDM_MASK) |926 TSA_CPM1_SIMODE_TDMB(TSA_CPM1_SIMODE_TDM_MASK),927 val);928 929 /* Set SIGMR */930 val = (tsa->tdms == BIT(TSA_TDMA)) ?931 TSA_CPM1_SIGMR_RDM_STATIC_TDMA : TSA_CPM1_SIGMR_RDM_STATIC_TDMAB;932 if (tsa->tdms & BIT(TSA_TDMA))933 val |= TSA_CPM1_SIGMR_ENA;934 if (tsa->tdms & BIT(TSA_TDMB))935 val |= TSA_CPM1_SIGMR_ENB;936 tsa_write8(tsa->si_regs + TSA_CPM1_SIGMR, val);937 938 return 0;939}940 941static int tsa_qe_setup(struct tsa *tsa)942{943 unsigned int sixmr;944 u8 siglmrh = 0;945 unsigned int i;946 947 for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {948 if (!tsa->tdm[i].is_enable)949 continue;950 951 switch (i) {952 case 0:953 sixmr = TSA_QE_SIAMR;954 siglmrh |= TSA_QE_SIGLMRH_ENA;955 break;956 case 1:957 sixmr = TSA_QE_SIBMR;958 siglmrh |= TSA_QE_SIGLMRH_ENB;959 break;960 case 2:961 sixmr = TSA_QE_SICMR;962 siglmrh |= TSA_QE_SIGLMRH_ENC;963 break;964 case 3:965 sixmr = TSA_QE_SIDMR;966 siglmrh |= TSA_QE_SIGLMRH_END;967 break;968 default:969 return -EINVAL;970 }971 972 /* Set SI mode register */973 tsa_write16(tsa->si_regs + sixmr, tsa->tdm[i].simode_tdm);974 }975 976 /* Enable TDMs */977 tsa_write8(tsa->si_regs + TSA_QE_SIGLMRH, siglmrh);978 979 return 0;980}981 982static int tsa_setup(struct tsa *tsa)983{984 return tsa_is_qe(tsa) ? tsa_qe_setup(tsa) : tsa_cpm1_setup(tsa);985}986 987static int tsa_probe(struct platform_device *pdev)988{989 struct device_node *np = pdev->dev.of_node;990 struct resource *res;991 struct tsa *tsa;992 unsigned int i;993 int ret;994 995 tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);996 if (!tsa)997 return -ENOMEM;998 999 tsa->dev = &pdev->dev;1000 tsa->version = (enum tsa_version)(uintptr_t)of_device_get_match_data(&pdev->dev);1001 switch (tsa->version) {1002 case TSA_CPM1:1003 dev_info(tsa->dev, "CPM1 version\n");1004 break;1005 case TSA_QE:1006 dev_info(tsa->dev, "QE version\n");1007 break;1008 default:1009 dev_err(tsa->dev, "Unknown version (%d)\n", tsa->version);1010 return -EINVAL;1011 }1012 1013 for (i = 0; i < ARRAY_SIZE(tsa->serials); i++)1014 tsa->serials[i].id = i;1015 1016 spin_lock_init(&tsa->lock);1017 1018 tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");1019 if (IS_ERR(tsa->si_regs))1020 return PTR_ERR(tsa->si_regs);1021 1022 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");1023 if (!res) {1024 dev_err(tsa->dev, "si_ram resource missing\n");1025 return -EINVAL;1026 }1027 tsa->si_ram_sz = resource_size(res);1028 tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);1029 if (IS_ERR(tsa->si_ram))1030 return PTR_ERR(tsa->si_ram);1031 1032 tsa_init_si_ram(tsa);1033 1034 ret = tsa_of_parse_tdms(tsa, np);1035 if (ret)1036 return ret;1037 1038 ret = tsa_setup(tsa);1039 if (ret)1040 return ret;1041 1042 platform_set_drvdata(pdev, tsa);1043 1044 return 0;1045}1046 1047static void tsa_remove(struct platform_device *pdev)1048{1049 struct tsa *tsa = platform_get_drvdata(pdev);1050 int i;1051 1052 for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {1053 if (tsa->tdm[i].l1rsync_clk) {1054 clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);1055 clk_put(tsa->tdm[i].l1rsync_clk);1056 }1057 if (tsa->tdm[i].l1rclk_clk) {1058 clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);1059 clk_put(tsa->tdm[i].l1rclk_clk);1060 }1061 if (tsa->tdm[i].l1tsync_clk) {1062 clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);1063 clk_put(tsa->tdm[i].l1rsync_clk);1064 }1065 if (tsa->tdm[i].l1tclk_clk) {1066 clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);1067 clk_put(tsa->tdm[i].l1rclk_clk);1068 }1069 }1070}1071 1072static const struct of_device_id tsa_id_table[] = {1073#if IS_ENABLED(CONFIG_CPM1)1074 { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 },1075#endif1076#if IS_ENABLED(CONFIG_QUICC_ENGINE)1077 { .compatible = "fsl,qe-tsa", .data = (void *)TSA_QE },1078#endif1079 {} /* sentinel */1080};1081MODULE_DEVICE_TABLE(of, tsa_id_table);1082 1083static struct platform_driver tsa_driver = {1084 .driver = {1085 .name = "fsl-tsa",1086 .of_match_table = of_match_ptr(tsa_id_table),1087 },1088 .probe = tsa_probe,1089 .remove_new = tsa_remove,1090};1091module_platform_driver(tsa_driver);1092 1093struct tsa_serial *tsa_serial_get_byphandle(struct device_node *np,1094 const char *phandle_name)1095{1096 struct of_phandle_args out_args;1097 struct platform_device *pdev;1098 struct tsa_serial *tsa_serial;1099 struct tsa *tsa;1100 int ret;1101 1102 ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, &out_args);1103 if (ret < 0)1104 return ERR_PTR(ret);1105 1106 if (!of_match_node(tsa_driver.driver.of_match_table, out_args.np)) {1107 of_node_put(out_args.np);1108 return ERR_PTR(-EINVAL);1109 }1110 1111 pdev = of_find_device_by_node(out_args.np);1112 of_node_put(out_args.np);1113 if (!pdev)1114 return ERR_PTR(-ENODEV);1115 1116 tsa = platform_get_drvdata(pdev);1117 if (!tsa) {1118 platform_device_put(pdev);1119 return ERR_PTR(-EPROBE_DEFER);1120 }1121 1122 if (out_args.args_count != 1) {1123 platform_device_put(pdev);1124 return ERR_PTR(-EINVAL);1125 }1126 1127 if (out_args.args[0] >= ARRAY_SIZE(tsa->serials)) {1128 platform_device_put(pdev);1129 return ERR_PTR(-EINVAL);1130 }1131 1132 tsa_serial = &tsa->serials[out_args.args[0]];1133 1134 /*1135 * Be sure that the serial id matches the phandle arg.1136 * The tsa_serials table is indexed by serial ids. The serial id is set1137 * during the probe() call and needs to be coherent.1138 */1139 if (WARN_ON(tsa_serial->id != out_args.args[0])) {1140 platform_device_put(pdev);1141 return ERR_PTR(-EINVAL);1142 }1143 1144 return tsa_serial;1145}1146EXPORT_SYMBOL(tsa_serial_get_byphandle);1147 1148void tsa_serial_put(struct tsa_serial *tsa_serial)1149{1150 struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);1151 1152 put_device(tsa->dev);1153}1154EXPORT_SYMBOL(tsa_serial_put);1155 1156static void devm_tsa_serial_release(struct device *dev, void *res)1157{1158 struct tsa_serial **tsa_serial = res;1159 1160 tsa_serial_put(*tsa_serial);1161}1162 1163struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev,1164 struct device_node *np,1165 const char *phandle_name)1166{1167 struct tsa_serial *tsa_serial;1168 struct tsa_serial **dr;1169 1170 dr = devres_alloc(devm_tsa_serial_release, sizeof(*dr), GFP_KERNEL);1171 if (!dr)1172 return ERR_PTR(-ENOMEM);1173 1174 tsa_serial = tsa_serial_get_byphandle(np, phandle_name);1175 if (!IS_ERR(tsa_serial)) {1176 *dr = tsa_serial;1177 devres_add(dev, dr);1178 } else {1179 devres_free(dr);1180 }1181 1182 return tsa_serial;1183}1184EXPORT_SYMBOL(devm_tsa_serial_get_byphandle);1185 1186MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");1187MODULE_DESCRIPTION("CPM/QE TSA driver");1188MODULE_LICENSE("GPL");1189