162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/net/wan/slic_ds26522.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Freescale Semiconductor, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author:Zhao Qiang<qiang.zhao@nxp.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/bitrev.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/sched.h> 1562306a36Sopenharmony_ci#include <linux/kthread.h> 1662306a36Sopenharmony_ci#include <linux/spi/spi.h> 1762306a36Sopenharmony_ci#include <linux/wait.h> 1862306a36Sopenharmony_ci#include <linux/param.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/of_address.h> 2262306a36Sopenharmony_ci#include <linux/io.h> 2362306a36Sopenharmony_ci#include "slic_ds26522.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define SLIC_TRANS_LEN 1 2662306a36Sopenharmony_ci#define SLIC_TWO_LEN 2 2762306a36Sopenharmony_ci#define SLIC_THREE_LEN 3 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic struct spi_device *g_spi; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3262306a36Sopenharmony_ciMODULE_AUTHOR("Zhao Qiang<B45475@freescale.com>"); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* the read/write format of address is 3562306a36Sopenharmony_ci * w/r|A13|A12|A11|A10|A9|A8|A7|A6|A5|A4|A3|A2|A1|A0|x 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic void slic_write(struct spi_device *spi, u16 addr, 3862306a36Sopenharmony_ci u8 data) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci u8 temp[3]; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci addr = bitrev16(addr) >> 1; 4362306a36Sopenharmony_ci data = bitrev8(data); 4462306a36Sopenharmony_ci temp[0] = (u8)((addr >> 8) & 0x7f); 4562306a36Sopenharmony_ci temp[1] = (u8)(addr & 0xfe); 4662306a36Sopenharmony_ci temp[2] = data; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* write spi addr and value */ 4962306a36Sopenharmony_ci spi_write(spi, &temp[0], SLIC_THREE_LEN); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic u8 slic_read(struct spi_device *spi, u16 addr) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci u8 temp[2]; 5562306a36Sopenharmony_ci u8 data; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci addr = bitrev16(addr) >> 1; 5862306a36Sopenharmony_ci temp[0] = (u8)(((addr >> 8) & 0x7f) | 0x80); 5962306a36Sopenharmony_ci temp[1] = (u8)(addr & 0xfe); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci spi_write_then_read(spi, &temp[0], SLIC_TWO_LEN, &data, 6262306a36Sopenharmony_ci SLIC_TRANS_LEN); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci data = bitrev8(data); 6562306a36Sopenharmony_ci return data; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic bool get_slic_product_code(struct spi_device *spi) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci u8 device_id; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci device_id = slic_read(spi, DS26522_IDR_ADDR); 7362306a36Sopenharmony_ci if ((device_id & 0xf8) == 0x68) 7462306a36Sopenharmony_ci return true; 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci return false; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void ds26522_e1_spec_config(struct spi_device *spi) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci /* Receive E1 Mode, Framer Disabled */ 8262306a36Sopenharmony_ci slic_write(spi, DS26522_RMMR_ADDR, DS26522_RMMR_E1); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Transmit E1 Mode, Framer Disable */ 8562306a36Sopenharmony_ci slic_write(spi, DS26522_TMMR_ADDR, DS26522_TMMR_E1); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Receive E1 Mode Framer Enable */ 8862306a36Sopenharmony_ci slic_write(spi, DS26522_RMMR_ADDR, 8962306a36Sopenharmony_ci slic_read(spi, DS26522_RMMR_ADDR) | DS26522_RMMR_FRM_EN); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Transmit E1 Mode Framer Enable */ 9262306a36Sopenharmony_ci slic_write(spi, DS26522_TMMR_ADDR, 9362306a36Sopenharmony_ci slic_read(spi, DS26522_TMMR_ADDR) | DS26522_TMMR_FRM_EN); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* RCR1, receive E1 B8zs & ESF */ 9662306a36Sopenharmony_ci slic_write(spi, DS26522_RCR1_ADDR, 9762306a36Sopenharmony_ci DS26522_RCR1_E1_HDB3 | DS26522_RCR1_E1_CCS); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* RSYSCLK=2.048MHz, RSYNC-Output */ 10062306a36Sopenharmony_ci slic_write(spi, DS26522_RIOCR_ADDR, 10162306a36Sopenharmony_ci DS26522_RIOCR_2048KHZ | DS26522_RIOCR_RSIO_OUT); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* TCR1 Transmit E1 b8zs */ 10462306a36Sopenharmony_ci slic_write(spi, DS26522_TCR1_ADDR, DS26522_TCR1_TB8ZS); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* TSYSCLK=2.048MHz, TSYNC-Output */ 10762306a36Sopenharmony_ci slic_write(spi, DS26522_TIOCR_ADDR, 10862306a36Sopenharmony_ci DS26522_TIOCR_2048KHZ | DS26522_TIOCR_TSIO_OUT); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Set E1TAF */ 11162306a36Sopenharmony_ci slic_write(spi, DS26522_E1TAF_ADDR, DS26522_E1TAF_DEFAULT); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* Set E1TNAF register */ 11462306a36Sopenharmony_ci slic_write(spi, DS26522_E1TNAF_ADDR, DS26522_E1TNAF_DEFAULT); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Receive E1 Mode Framer Enable & init Done */ 11762306a36Sopenharmony_ci slic_write(spi, DS26522_RMMR_ADDR, slic_read(spi, DS26522_RMMR_ADDR) | 11862306a36Sopenharmony_ci DS26522_RMMR_INIT_DONE); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Transmit E1 Mode Framer Enable & init Done */ 12162306a36Sopenharmony_ci slic_write(spi, DS26522_TMMR_ADDR, slic_read(spi, DS26522_TMMR_ADDR) | 12262306a36Sopenharmony_ci DS26522_TMMR_INIT_DONE); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Configure LIU E1 mode */ 12562306a36Sopenharmony_ci slic_write(spi, DS26522_LTRCR_ADDR, DS26522_LTRCR_E1); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* E1 Mode default 75 ohm w/Transmit Impedance Matlinking */ 12862306a36Sopenharmony_ci slic_write(spi, DS26522_LTITSR_ADDR, 12962306a36Sopenharmony_ci DS26522_LTITSR_TLIS_75OHM | DS26522_LTITSR_LBOS_75OHM); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* E1 Mode default 75 ohm Long Haul w/Receive Impedance Matlinking */ 13262306a36Sopenharmony_ci slic_write(spi, DS26522_LRISMR_ADDR, 13362306a36Sopenharmony_ci DS26522_LRISMR_75OHM | DS26522_LRISMR_MAX); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Enable Transmit output */ 13662306a36Sopenharmony_ci slic_write(spi, DS26522_LMCR_ADDR, DS26522_LMCR_TE); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int slic_ds26522_init_configure(struct spi_device *spi) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u16 addr; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* set clock */ 14462306a36Sopenharmony_ci slic_write(spi, DS26522_GTCCR_ADDR, DS26522_GTCCR_BPREFSEL_REFCLKIN | 14562306a36Sopenharmony_ci DS26522_GTCCR_BFREQSEL_2048KHZ | 14662306a36Sopenharmony_ci DS26522_GTCCR_FREQSEL_2048KHZ); 14762306a36Sopenharmony_ci slic_write(spi, DS26522_GTCR2_ADDR, DS26522_GTCR2_TSSYNCOUT); 14862306a36Sopenharmony_ci slic_write(spi, DS26522_GFCR_ADDR, DS26522_GFCR_BPCLK_2048KHZ); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* set gtcr */ 15162306a36Sopenharmony_ci slic_write(spi, DS26522_GTCR1_ADDR, DS26522_GTCR1); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Global LIU Software Reset Register */ 15462306a36Sopenharmony_ci slic_write(spi, DS26522_GLSRR_ADDR, DS26522_GLSRR_RESET); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Global Framer and BERT Software Reset Register */ 15762306a36Sopenharmony_ci slic_write(spi, DS26522_GFSRR_ADDR, DS26522_GFSRR_RESET); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci usleep_range(100, 120); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci slic_write(spi, DS26522_GLSRR_ADDR, DS26522_GLSRR_NORMAL); 16262306a36Sopenharmony_ci slic_write(spi, DS26522_GFSRR_ADDR, DS26522_GFSRR_NORMAL); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Perform RX/TX SRESET,Reset receiver */ 16562306a36Sopenharmony_ci slic_write(spi, DS26522_RMMR_ADDR, DS26522_RMMR_SFTRST); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Reset tranceiver */ 16862306a36Sopenharmony_ci slic_write(spi, DS26522_TMMR_ADDR, DS26522_TMMR_SFTRST); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci usleep_range(100, 120); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Zero all Framer Registers */ 17362306a36Sopenharmony_ci for (addr = DS26522_RF_ADDR_START; addr <= DS26522_RF_ADDR_END; 17462306a36Sopenharmony_ci addr++) 17562306a36Sopenharmony_ci slic_write(spi, addr, 0); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci for (addr = DS26522_TF_ADDR_START; addr <= DS26522_TF_ADDR_END; 17862306a36Sopenharmony_ci addr++) 17962306a36Sopenharmony_ci slic_write(spi, addr, 0); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (addr = DS26522_LIU_ADDR_START; addr <= DS26522_LIU_ADDR_END; 18262306a36Sopenharmony_ci addr++) 18362306a36Sopenharmony_ci slic_write(spi, addr, 0); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for (addr = DS26522_BERT_ADDR_START; addr <= DS26522_BERT_ADDR_END; 18662306a36Sopenharmony_ci addr++) 18762306a36Sopenharmony_ci slic_write(spi, addr, 0); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* setup ds26522 for E1 specification */ 19062306a36Sopenharmony_ci ds26522_e1_spec_config(spi); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci slic_write(spi, DS26522_GTCR1_ADDR, 0x00); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void slic_ds26522_remove(struct spi_device *spi) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci pr_info("DS26522 module uninstalled\n"); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int slic_ds26522_probe(struct spi_device *spi) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci int ret = 0; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci g_spi = spi; 20762306a36Sopenharmony_ci spi->bits_per_word = 8; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!get_slic_product_code(spi)) 21062306a36Sopenharmony_ci return ret; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ret = slic_ds26522_init_configure(spi); 21362306a36Sopenharmony_ci if (ret == 0) 21462306a36Sopenharmony_ci pr_info("DS26522 cs%d configured\n", spi_get_chipselect(spi, 0)); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return ret; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const struct spi_device_id slic_ds26522_id[] = { 22062306a36Sopenharmony_ci { .name = "ds26522" }, 22162306a36Sopenharmony_ci { /* sentinel */ }, 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, slic_ds26522_id); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic const struct of_device_id slic_ds26522_match[] = { 22662306a36Sopenharmony_ci { 22762306a36Sopenharmony_ci .compatible = "maxim,ds26522", 22862306a36Sopenharmony_ci }, 22962306a36Sopenharmony_ci {}, 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, slic_ds26522_match); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic struct spi_driver slic_ds26522_driver = { 23462306a36Sopenharmony_ci .driver = { 23562306a36Sopenharmony_ci .name = "ds26522", 23662306a36Sopenharmony_ci .bus = &spi_bus_type, 23762306a36Sopenharmony_ci .of_match_table = slic_ds26522_match, 23862306a36Sopenharmony_ci }, 23962306a36Sopenharmony_ci .probe = slic_ds26522_probe, 24062306a36Sopenharmony_ci .remove = slic_ds26522_remove, 24162306a36Sopenharmony_ci .id_table = slic_ds26522_id, 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cimodule_spi_driver(slic_ds26522_driver); 245