Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Herve Codina | 3884 | 99.95% | 1 | 50.00% |
Uwe Kleine-König | 2 | 0.05% | 1 | 50.00% |
Total | 3886 | 2 |
// SPDX-License-Identifier: GPL-2.0 /* * PEF2256 also known as FALC56 driver * * Copyright 2023 CS GROUP France * * Author: Herve Codina <herve.codina@bootlin.com> */ #include <linux/framer/pef2256.h> #include <linux/clk.h> #include <linux/framer/framer-provider.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/slab.h> #include "pef2256-regs.h" enum pef2256_frame_type { PEF2256_FRAME_E1_DOUBLEFRAME, PEF2256_FRAME_E1_CRC4_MULTIFRAME, PEF2256_FRAME_E1_AUTO_MULTIFRAME, PEF2256_FRAME_T1J1_4FRAME, PEF2256_FRAME_T1J1_12FRAME, PEF2256_FRAME_T1J1_24FRAME, PEF2256_FRAME_T1J1_72FRAME, }; struct pef2256 { struct device *dev; struct regmap *regmap; enum pef2256_version version; struct clk *mclk; struct clk *sclkr; struct clk *sclkx; struct gpio_desc *reset_gpio; unsigned long sysclk_rate; u32 data_rate; bool is_tx_falling_edge; bool is_subordinate; enum pef2256_frame_type frame_type; u8 channel_phase; atomic_t carrier; struct framer *framer; }; static u8 pef2256_read8(struct pef2256 *pef2256, int offset) { int val; regmap_read(pef2256->regmap, offset, &val); return val; } static void pef2256_write8(struct pef2256 *pef2256, int offset, u8 val) { regmap_write(pef2256->regmap, offset, val); } static void pef2256_clrbits8(struct pef2256 *pef2256, int offset, u8 clr) { regmap_clear_bits(pef2256->regmap, offset, clr); } static void pef2256_setbits8(struct pef2256 *pef2256, int offset, u8 set) { regmap_set_bits(pef2256->regmap, offset, set); } static void pef2256_clrsetbits8(struct pef2256 *pef2256, int offset, u8 clr, u8 set) { regmap_update_bits(pef2256->regmap, offset, clr | set, set); } enum pef2256_version pef2256_get_version(struct pef2256 *pef2256) { enum pef2256_version version = PEF2256_VERSION_UNKNOWN; u8 vstr, wid; vstr = pef2256_read8(pef2256, PEF2256_VSTR); wid = pef2256_read8(pef2256, PEF2256_WID); switch (vstr) { case PEF2256_VSTR_VERSION_12: if ((wid & PEF2256_12_WID_MASK) == PEF2256_12_WID_VERSION_12) version = PEF2256_VERSION_1_2; break; case PEF2256_VSTR_VERSION_2x: switch (wid & PEF2256_2X_WID_MASK) { case PEF2256_2X_WID_VERSION_21: version = PEF2256_VERSION_2_1; break; case PEF2256_2X_WID_VERSION_22: version = PEF2256_VERSION_2_2; break; } break; case PEF2256_VSTR_VERSION_21: version = PEF2256_VERSION_2_1; break; } if (version == PEF2256_VERSION_UNKNOWN) dev_err(pef2256->dev, "Unknown version (0x%02x, 0x%02x)\n", vstr, wid); return version; } EXPORT_SYMBOL_GPL(pef2256_get_version); enum pef2256_gcm_config_item { PEF2256_GCM_CONFIG_1544000 = 0, PEF2256_GCM_CONFIG_2048000, PEF2256_GCM_CONFIG_8192000, PEF2256_GCM_CONFIG_10000000, PEF2256_GCM_CONFIG_12352000, PEF2256_GCM_CONFIG_16384000, }; struct pef2256_gcm_config { u8 gcm_12[6]; u8 gcm_2x[8]; }; static const struct pef2256_gcm_config pef2256_gcm_configs[] = { [PEF2256_GCM_CONFIG_1544000] = { .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x00, 0x15}, .gcm_2x = {0x00, 0x15, 0x00, 0x08, 0x00, 0x3F, 0x9C, 0xDF}, }, [PEF2256_GCM_CONFIG_2048000] = { .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x00, 0x10}, .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x2F, 0xDB, 0xDF}, }, [PEF2256_GCM_CONFIG_8192000] = { .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x03, 0x10}, .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x0B, 0xDB, 0xDF}, }, [PEF2256_GCM_CONFIG_10000000] = { .gcm_12 = {0x90, 0x51, 0x81, 0x8F, 0x04, 0x10}, .gcm_2x = {0x40, 0x1B, 0x3D, 0x0A, 0x00, 0x07, 0xC9, 0xDC}, }, [PEF2256_GCM_CONFIG_12352000] = { .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x07, 0x15}, .gcm_2x = {0x00, 0x19, 0x00, 0x08, 0x01, 0x0A, 0x98, 0xDA}, }, [PEF2256_GCM_CONFIG_16384000] = { .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x07, 0x10}, .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x01, 0x0B, 0xDB, 0xDF}, }, }; static int pef2256_setup_gcm(struct pef2256 *pef2256) { enum pef2256_gcm_config_item item; unsigned long mclk_rate; const u8 *gcm; int i, count; mclk_rate = clk_get_rate(pef2256->mclk); switch (mclk_rate) { case 1544000: item = PEF2256_GCM_CONFIG_1544000; break; case 2048000: item = PEF2256_GCM_CONFIG_2048000; break; case 8192000: item = PEF2256_GCM_CONFIG_8192000; break; case 10000000: item = PEF2256_GCM_CONFIG_10000000; break; case 12352000: item = PEF2256_GCM_CONFIG_12352000; break; case 16384000: item = PEF2256_GCM_CONFIG_16384000; break; default: dev_err(pef2256->dev, "Unsupported v2.x MCLK rate %lu\n", mclk_rate); return -EINVAL; } BUILD_BUG_ON(item >= ARRAY_SIZE(pef2256_gcm_configs)); if (pef2256->version == PEF2256_VERSION_1_2) { gcm = pef2256_gcm_configs[item].gcm_12; count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_12); } else { gcm = pef2256_gcm_configs[item].gcm_2x; count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_2x); } for (i = 0; i < count; i++) pef2256_write8(pef2256, PEF2256_GCM(i + 1), *(gcm + i)); return 0; } static int pef2256_setup_e1_line(struct pef2256 *pef2256) { u8 fmr1, fmr2; /* RCLK output : DPLL clock, DCO-X enabled, DCO-X internal ref clock */ pef2256_write8(pef2256, PEF2256_CMR1, 0x00); /* SCLKR selected, SCLKX selected, * receive synchro pulse sourced by SYPR, * transmit synchro pulse sourced by SYPX, * DCO-X center frequency enabled */ pef2256_write8(pef2256, PEF2256_CMR2, PEF2256_CMR2_DCOXC); if (pef2256->is_subordinate) { /* select RCLK source = 2M, disable switching from RCLK to SYNC */ pef2256_clrsetbits8(pef2256, PEF2256_CMR1, PEF2256_CMR1_RS_MASK, PEF2256_CMR1_RS_DCOR_2048 | PEF2256_CMR1_DCS); } /* slave mode, local loop off, mode short-haul * In v2.x, bit3 is a forced 1 bit in the datasheet -> Need to be set. */ if (pef2256->version == PEF2256_VERSION_1_2) pef2256_write8(pef2256, PEF2256_LIM0, 0x00); else pef2256_write8(pef2256, PEF2256_LIM0, PEF2256_2X_LIM0_BIT3); /* "master" mode */ if (!pef2256->is_subordinate) pef2256_setbits8(pef2256, PEF2256_LIM0, PEF2256_LIM0_MAS); /* analog interface selected, remote loop off */ pef2256_write8(pef2256, PEF2256_LIM1, 0x00); /* receive input threshold = 0,21V */ if (pef2256->version == PEF2256_VERSION_1_2) pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_12_LIM1_RIL_MASK, PEF2256_12_LIM1_RIL_210); else pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_2X_LIM1_RIL_MASK, PEF2256_2X_LIM1_RIL_210); /* transmit pulse mask, default value from datasheet * transmit line in normal operation */ if (pef2256->version == PEF2256_VERSION_1_2) pef2256_write8(pef2256, PEF2256_XPM0, 0x7B); else pef2256_write8(pef2256, PEF2256_XPM0, 0x9C); pef2256_write8(pef2256, PEF2256_XPM1, 0x03); pef2256_write8(pef2256, PEF2256_XPM2, 0x00); /* HDB3 coding, no alarm simulation */ pef2256_write8(pef2256, PEF2256_FMR0, PEF2256_FMR0_XC_HDB3 | PEF2256_FMR0_RC_HDB3); /* E1, frame format, 2 Mbit/s system data rate, no AIS * transmission to remote end or system interface, payload loop * off, transmit remote alarm on */ fmr1 = 0x00; fmr2 = PEF2256_FMR2_AXRA; switch (pef2256->frame_type) { case PEF2256_FRAME_E1_DOUBLEFRAME: fmr2 |= PEF2256_FMR2_RFS_DOUBLEFRAME; break; case PEF2256_FRAME_E1_CRC4_MULTIFRAME: fmr1 |= PEF2256_FMR1_XFS; fmr2 |= PEF2256_FMR2_RFS_CRC4_MULTIFRAME; break; case PEF2256_FRAME_E1_AUTO_MULTIFRAME: fmr1 |= PEF2256_FMR1_XFS; fmr2 |= PEF2256_FMR2_RFS_AUTO_MULTIFRAME; break; default: dev_err(pef2256->dev, "Unsupported frame type %d\n", pef2256->frame_type); return -EINVAL; } pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_XFS, fmr1); pef2256_write8(pef2256, PEF2256_FMR2, fmr2); if (!pef2256->is_subordinate) { /* SEC input, active high */ pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_SEC_IN_HIGH); } else { /* FSC output, active high */ pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_FSC_OUT_HIGH); } /* SCLKR, SCLKX, RCLK configured to inputs, * XFMS active low, CLK1 and CLK2 pin configuration */ pef2256_write8(pef2256, PEF2256_PC5, 0x00); pef2256_write8(pef2256, PEF2256_PC6, 0x00); /* port RCLK is output */ pef2256_setbits8(pef2256, PEF2256_PC5, PEF2256_PC5_CRP); return 0; } static void pef2256_setup_e1_los(struct pef2256 *pef2256) { /* detection of LOS alarm = 176 pulses (ie (10 + 1) * 16) */ pef2256_write8(pef2256, PEF2256_PCD, 10); /* recovery of LOS alarm = 22 pulses (ie 21 + 1) */ pef2256_write8(pef2256, PEF2256_PCR, 21); /* E1 default for the receive slicer threshold */ pef2256_write8(pef2256, PEF2256_LIM2, PEF2256_LIM2_SLT_THR50); if (pef2256->is_subordinate) { /* Loop-timed */ pef2256_setbits8(pef2256, PEF2256_LIM2, PEF2256_LIM2_ELT); } } static int pef2256_setup_e1_system(struct pef2256 *pef2256) { u8 sic1, fmr1; /* 2.048 MHz system clocking rate, receive buffer 2 frames, transmit * buffer bypass, data sampled and transmitted on the falling edge of * SCLKR/X, automatic freeze signaling, data is active in the first * channel phase */ pef2256_write8(pef2256, PEF2256_SIC1, 0x00); pef2256_write8(pef2256, PEF2256_SIC2, 0x00); pef2256_write8(pef2256, PEF2256_SIC3, 0x00); if (pef2256->is_subordinate) { /* transmit buffer size = 2 frames, transparent mode */ pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_XBS_MASK, PEF2256_SIC1_XBS_2FRAMES); } if (pef2256->version != PEF2256_VERSION_1_2) { /* during inactive channel phase switch RDO/RSIG into tri-state */ pef2256_setbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RTRI); } if (pef2256->is_tx_falling_edge) { /* falling edge sync pulse transmit, rising edge sync pulse receive */ pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESX, PEF2256_SIC3_RESR); } else { /* rising edge sync pulse transmit, falling edge sync pulse receive */ pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESR, PEF2256_SIC3_RESX); } /* transmit offset counter (XCO10..0) = 4 */ pef2256_write8(pef2256, PEF2256_XC0, 0); pef2256_write8(pef2256, PEF2256_XC1, 4); /* receive offset counter (RCO10..0) = 4 */ pef2256_write8(pef2256, PEF2256_RC0, 0); pef2256_write8(pef2256, PEF2256_RC1, 4); /* system clock rate */ switch (pef2256->sysclk_rate) { case 2048000: sic1 = PEF2256_SIC1_SSC_2048; break; case 4096000: sic1 = PEF2256_SIC1_SSC_4096; break; case 8192000: sic1 = PEF2256_SIC1_SSC_8192; break; case 16384000: sic1 = PEF2256_SIC1_SSC_16384; break; default: dev_err(pef2256->dev, "Unsupported sysclk rate %lu\n", pef2256->sysclk_rate); return -EINVAL; } pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSC_MASK, sic1); /* data clock rate */ switch (pef2256->data_rate) { case 2048000: fmr1 = PEF2256_FMR1_SSD_2048; sic1 = PEF2256_SIC1_SSD_2048; break; case 4096000: fmr1 = PEF2256_FMR1_SSD_4096; sic1 = PEF2256_SIC1_SSD_4096; break; case 8192000: fmr1 = PEF2256_FMR1_SSD_8192; sic1 = PEF2256_SIC1_SSD_8192; break; case 16384000: fmr1 = PEF2256_FMR1_SSD_16384; sic1 = PEF2256_SIC1_SSD_16384; break; default: dev_err(pef2256->dev, "Unsupported data rate %u\n", pef2256->data_rate); return -EINVAL; } pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_SSD_MASK, fmr1); pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSD_MASK, sic1); /* channel phase */ pef2256_clrsetbits8(pef2256, PEF2256_SIC2, PEF2256_SIC2_SICS_MASK, PEF2256_SIC2_SICS(pef2256->channel_phase)); return 0; } static void pef2256_setup_e1_signaling(struct pef2256 *pef2256) { /* All bits of the transmitted service word are cleared */ pef2256_write8(pef2256, PEF2256_XSW, PEF2256_XSW_XY(0x1F)); /* CAS disabled and clear spare bit values */ pef2256_write8(pef2256, PEF2256_XSP, 0x00); if (pef2256->is_subordinate) { /* transparent mode */ pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XTM); } /* Si-Bit, Spare bit For International, FAS word */ pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XSIS); pef2256_setbits8(pef2256, PEF2256_XSP, PEF2256_XSP_XSIF); /* no transparent mode active */ pef2256_write8(pef2256, PEF2256_TSWM, 0x00); } static void pef2256_setup_e1_errors(struct pef2256 *pef2256) { /* error counter latched every 1s */ pef2256_setbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_ECM); /* error counter mode COFA */ pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_ECMC); /* errors in service words have no influence */ pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_SWD); /* 4 consecutive incorrect FAS causes loss of sync */ pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_ASY4); } static int pef2256_setup_e1(struct pef2256 *pef2256) { int ret; /* Setup, Master clocking mode (GCM8..1) */ ret = pef2256_setup_gcm(pef2256); if (ret) return ret; /* Select E1 mode */ pef2256_write8(pef2256, PEF2256_FMR1, 0x00); /* internal second timer, power on */ pef2256_write8(pef2256, PEF2256_GCR, 0x00); /* Setup line interface */ ret = pef2256_setup_e1_line(pef2256); if (ret) return ret; /* Setup Loss-of-signal detection and recovery */ pef2256_setup_e1_los(pef2256); /* Setup system interface */ ret = pef2256_setup_e1_system(pef2256); if (ret) return ret; /* Setup signaling */ pef2256_setup_e1_signaling(pef2256); /* Setup errors counters and condition */ pef2256_setup_e1_errors(pef2256); /* status changed interrupt at both up and down */ pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_SCI); /* Clear any ISR2 pending interrupts and unmask needed interrupts */ pef2256_read8(pef2256, PEF2256_ISR2); pef2256_clrbits8(pef2256, PEF2256_IMR2, PEF2256_INT2_LOS | PEF2256_INT2_AIS); /* reset lines */ pef2256_write8(pef2256, PEF2256_CMDR, PEF2256_CMDR_RRES | PEF2256_CMDR_XRES); return 0; } static void pef2256_isr_default_handler(struct pef2256 *pef2256, u8 nbr, u8 isr) { dev_warn_ratelimited(pef2256->dev, "ISR%u: 0x%02x not handled\n", nbr, isr); } static bool pef2256_is_carrier_on(struct pef2256 *pef2256) { u8 frs0; frs0 = pef2256_read8(pef2256, PEF2256_FRS0); return !(frs0 & (PEF2256_FRS0_LOS | PEF2256_FRS0_AIS)); } static void pef2256_isr2_handler(struct pef2256 *pef2256, u8 nbr, u8 isr) { bool carrier; if (isr & (PEF2256_INT2_LOS | PEF2256_INT2_AIS)) { carrier = pef2256_is_carrier_on(pef2256); if (atomic_xchg(&pef2256->carrier, carrier) != carrier) framer_notify_status_change(pef2256->framer); } } static irqreturn_t pef2256_irq_handler(int irq, void *priv) { static void (*pef2256_isr_handler[])(struct pef2256 *, u8, u8) = { [0] = pef2256_isr_default_handler, [1] = pef2256_isr_default_handler, [2] = pef2256_isr2_handler, [3] = pef2256_isr_default_handler, [4] = pef2256_isr_default_handler, [5] = pef2256_isr_default_handler }; struct pef2256 *pef2256 = (struct pef2256 *)priv; u8 gis; u8 isr; u8 n; gis = pef2256_read8(pef2256, PEF2256_GIS); for (n = 0; n < ARRAY_SIZE(pef2256_isr_handler); n++) { if (gis & PEF2256_GIS_ISR(n)) { isr = pef2256_read8(pef2256, PEF2256_ISR(n)); pef2256_isr_handler[n](pef2256, n, isr); } } return IRQ_HANDLED; } static int pef2256_check_rates(struct pef2256 *pef2256, unsigned long sysclk_rate, unsigned long data_rate) { unsigned long rate; switch (sysclk_rate) { case 2048000: case 4096000: case 8192000: case 16384000: break; default: dev_err(pef2256->dev, "Unsupported system clock rate %lu\n", sysclk_rate); return -EINVAL; } for (rate = data_rate; rate <= data_rate * 4; rate *= 2) { if (rate == sysclk_rate) return 0; } dev_err(pef2256->dev, "Unsupported data rate %lu with system clock rate %lu\n", data_rate, sysclk_rate); return -EINVAL; } static int pef2556_of_parse(struct pef2256 *pef2256, struct device_node *np) { int ret; pef2256->data_rate = 2048000; ret = of_property_read_u32(np, "lantiq,data-rate-bps", &pef2256->data_rate); if (ret && ret != -EINVAL) { dev_err(pef2256->dev, "%pOF: failed to read lantiq,data-rate-bps\n", np); return ret; } ret = pef2256_check_rates(pef2256, pef2256->sysclk_rate, pef2256->data_rate); if (ret) return ret; pef2256->is_tx_falling_edge = of_property_read_bool(np, "lantiq,clock-falling-edge"); pef2256->channel_phase = 0; ret = of_property_read_u8(np, "lantiq,channel-phase", &pef2256->channel_phase); if (ret && ret != -EINVAL) { dev_err(pef2256->dev, "%pOF: failed to read lantiq,channel-phase\n", np); return ret; } if (pef2256->channel_phase >= pef2256->sysclk_rate / pef2256->data_rate) { dev_err(pef2256->dev, "%pOF: Invalid lantiq,channel-phase %u\n", np, pef2256->channel_phase); return -EINVAL; } return 0; } static const struct regmap_config pef2256_regmap_config = { .reg_bits = 32, .val_bits = 8, .max_register = 0xff, }; static const struct mfd_cell pef2256_devs[] = { { .name = "lantiq-pef2256-pinctrl", }, }; static int pef2256_add_audio_devices(struct pef2256 *pef2256) { const char *compatible = "lantiq,pef2256-codec"; struct mfd_cell *audio_devs; struct device_node *np; unsigned int count = 0; unsigned int i; int ret; for_each_available_child_of_node(pef2256->dev->of_node, np) { if (of_device_is_compatible(np, compatible)) count++; } if (!count) return 0; audio_devs = kcalloc(count, sizeof(*audio_devs), GFP_KERNEL); if (!audio_devs) return -ENOMEM; for (i = 0; i < count; i++) { audio_devs[i].name = "framer-codec"; audio_devs[i].of_compatible = compatible; audio_devs[i].id = i; } ret = mfd_add_devices(pef2256->dev, 0, audio_devs, count, NULL, 0, NULL); kfree(audio_devs); return ret; } static int pef2256_framer_get_status(struct framer *framer, struct framer_status *status) { struct pef2256 *pef2256 = framer_get_drvdata(framer); status->link_is_on = !!atomic_read(&pef2256->carrier); return 0; } static int pef2256_framer_set_config(struct framer *framer, const struct framer_config *config) { struct pef2256 *pef2256 = framer_get_drvdata(framer); if (config->iface != FRAMER_IFACE_E1) { dev_err(pef2256->dev, "Only E1 line is currently supported\n"); return -EOPNOTSUPP; } switch (config->clock_type) { case FRAMER_CLOCK_EXT: pef2256->is_subordinate = true; break; case FRAMER_CLOCK_INT: pef2256->is_subordinate = false; break; default: return -EINVAL; } /* Apply the new settings */ return pef2256_setup_e1(pef2256); } static int pef2256_framer_get_config(struct framer *framer, struct framer_config *config) { struct pef2256 *pef2256 = framer_get_drvdata(framer); config->iface = FRAMER_IFACE_E1; config->clock_type = pef2256->is_subordinate ? FRAMER_CLOCK_EXT : FRAMER_CLOCK_INT; config->line_clock_rate = 2048000; return 0; } static const struct framer_ops pef2256_framer_ops = { .owner = THIS_MODULE, .get_status = pef2256_framer_get_status, .get_config = pef2256_framer_get_config, .set_config = pef2256_framer_set_config, }; static int pef2256_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; unsigned long sclkr_rate, sclkx_rate; struct framer_provider *framer_provider; struct pef2256 *pef2256; const char *version_txt; void __iomem *iomem; int ret; int irq; pef2256 = devm_kzalloc(&pdev->dev, sizeof(*pef2256), GFP_KERNEL); if (!pef2256) return -ENOMEM; pef2256->dev = &pdev->dev; atomic_set(&pef2256->carrier, 0); pef2256->is_subordinate = true; pef2256->frame_type = PEF2256_FRAME_E1_DOUBLEFRAME; iomem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(iomem)) return PTR_ERR(iomem); pef2256->regmap = devm_regmap_init_mmio(&pdev->dev, iomem, &pef2256_regmap_config); if (IS_ERR(pef2256->regmap)) { dev_err(&pdev->dev, "Failed to initialise Regmap (%ld)\n", PTR_ERR(pef2256->regmap)); return PTR_ERR(pef2256->regmap); } pef2256->mclk = devm_clk_get_enabled(&pdev->dev, "mclk"); if (IS_ERR(pef2256->mclk)) return PTR_ERR(pef2256->mclk); pef2256->sclkr = devm_clk_get_enabled(&pdev->dev, "sclkr"); if (IS_ERR(pef2256->sclkr)) return PTR_ERR(pef2256->sclkr); pef2256->sclkx = devm_clk_get_enabled(&pdev->dev, "sclkx"); if (IS_ERR(pef2256->sclkx)) return PTR_ERR(pef2256->sclkx); /* Both SCLKR (receive) and SCLKX (transmit) must have the same rate, * stored as sysclk_rate. * The exact value will be checked at pef2256_check_rates() */ sclkr_rate = clk_get_rate(pef2256->sclkr); sclkx_rate = clk_get_rate(pef2256->sclkx); if (sclkr_rate != sclkx_rate) { dev_err(pef2256->dev, "clk rate mismatch. sclkr %lu Hz, sclkx %lu Hz\n", sclkr_rate, sclkx_rate); return -EINVAL; } pef2256->sysclk_rate = sclkr_rate; /* Reset the component. The MCLK clock must be active during reset */ pef2256->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(pef2256->reset_gpio)) return PTR_ERR(pef2256->reset_gpio); if (pef2256->reset_gpio) { gpiod_set_value_cansleep(pef2256->reset_gpio, 1); usleep_range(10, 20); gpiod_set_value_cansleep(pef2256->reset_gpio, 0); usleep_range(10, 20); } pef2256->version = pef2256_get_version(pef2256); switch (pef2256->version) { case PEF2256_VERSION_1_2: version_txt = "1.2"; break; case PEF2256_VERSION_2_1: version_txt = "2.1"; break; case PEF2256_VERSION_2_2: version_txt = "2.2"; break; default: return -ENODEV; } dev_info(pef2256->dev, "Version %s detected\n", version_txt); ret = pef2556_of_parse(pef2256, np); if (ret) return ret; /* Create the framer. It can be used on interrupts */ pef2256->framer = devm_framer_create(pef2256->dev, NULL, &pef2256_framer_ops); if (IS_ERR(pef2256->framer)) return PTR_ERR(pef2256->framer); framer_set_drvdata(pef2256->framer, pef2256); /* Disable interrupts */ pef2256_write8(pef2256, PEF2256_IMR0, 0xff); pef2256_write8(pef2256, PEF2256_IMR1, 0xff); pef2256_write8(pef2256, PEF2256_IMR2, 0xff); pef2256_write8(pef2256, PEF2256_IMR3, 0xff); pef2256_write8(pef2256, PEF2256_IMR4, 0xff); pef2256_write8(pef2256, PEF2256_IMR5, 0xff); /* Clear any pending interrupts */ pef2256_read8(pef2256, PEF2256_ISR0); pef2256_read8(pef2256, PEF2256_ISR1); pef2256_read8(pef2256, PEF2256_ISR2); pef2256_read8(pef2256, PEF2256_ISR3); pef2256_read8(pef2256, PEF2256_ISR4); pef2256_read8(pef2256, PEF2256_ISR5); irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; ret = devm_request_irq(pef2256->dev, irq, pef2256_irq_handler, 0, "pef2256", pef2256); if (ret < 0) return ret; platform_set_drvdata(pdev, pef2256); ret = mfd_add_devices(pef2256->dev, 0, pef2256_devs, ARRAY_SIZE(pef2256_devs), NULL, 0, NULL); if (ret) { dev_err(pef2256->dev, "add devices failed (%d)\n", ret); return ret; } ret = pef2256_setup_e1(pef2256); if (ret) return ret; framer_provider = devm_framer_provider_of_register(pef2256->dev, framer_provider_simple_of_xlate); if (IS_ERR(framer_provider)) return PTR_ERR(framer_provider); /* Add audio devices */ ret = pef2256_add_audio_devices(pef2256); if (ret < 0) { dev_err(pef2256->dev, "add audio devices failed (%d)\n", ret); return ret; } return 0; } static void pef2256_remove(struct platform_device *pdev) { struct pef2256 *pef2256 = platform_get_drvdata(pdev); /* Disable interrupts */ pef2256_write8(pef2256, PEF2256_IMR0, 0xff); pef2256_write8(pef2256, PEF2256_IMR1, 0xff); pef2256_write8(pef2256, PEF2256_IMR2, 0xff); pef2256_write8(pef2256, PEF2256_IMR3, 0xff); pef2256_write8(pef2256, PEF2256_IMR4, 0xff); pef2256_write8(pef2256, PEF2256_IMR5, 0xff); } static const struct of_device_id pef2256_id_table[] = { { .compatible = "lantiq,pef2256" }, {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, pef2256_id_table); static struct platform_driver pef2256_driver = { .driver = { .name = "lantiq-pef2256", .of_match_table = pef2256_id_table, }, .probe = pef2256_probe, .remove_new = pef2256_remove, }; module_platform_driver(pef2256_driver); struct regmap *pef2256_get_regmap(struct pef2256 *pef2256) { return pef2256->regmap; } EXPORT_SYMBOL_GPL(pef2256_get_regmap); MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); MODULE_DESCRIPTION("PEF2256 driver"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1