18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Microchip KSZ8795 series register access through SPI 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Microchip Technology Inc. 68c2ecf20Sopenharmony_ci * Tristram Ha <Tristram.Ha@microchip.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "ksz_common.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define SPI_ADDR_SHIFT 12 208c2ecf20Sopenharmony_ci#define SPI_ADDR_ALIGN 3 218c2ecf20Sopenharmony_ci#define SPI_TURNAROUND_SHIFT 1 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciKSZ_REGMAP_TABLE(ksz8795, 16, SPI_ADDR_SHIFT, 248c2ecf20Sopenharmony_ci SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int ksz8795_spi_probe(struct spi_device *spi) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct regmap_config rc; 298c2ecf20Sopenharmony_ci struct ksz_device *dev; 308c2ecf20Sopenharmony_ci int i, ret; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci dev = ksz_switch_alloc(&spi->dev, spi); 338c2ecf20Sopenharmony_ci if (!dev) 348c2ecf20Sopenharmony_ci return -ENOMEM; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { 378c2ecf20Sopenharmony_ci rc = ksz8795_regmap_config[i]; 388c2ecf20Sopenharmony_ci rc.lock_arg = &dev->regmap_mutex; 398c2ecf20Sopenharmony_ci dev->regmap[i] = devm_regmap_init_spi(spi, &rc); 408c2ecf20Sopenharmony_ci if (IS_ERR(dev->regmap[i])) { 418c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->regmap[i]); 428c2ecf20Sopenharmony_ci dev_err(&spi->dev, 438c2ecf20Sopenharmony_ci "Failed to initialize regmap%i: %d\n", 448c2ecf20Sopenharmony_ci ksz8795_regmap_config[i].val_bits, ret); 458c2ecf20Sopenharmony_ci return ret; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (spi->dev.platform_data) 508c2ecf20Sopenharmony_ci dev->pdata = spi->dev.platform_data; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci ret = ksz8795_switch_register(dev); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Main DSA driver may not be started yet. */ 558c2ecf20Sopenharmony_ci if (ret) 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci spi_set_drvdata(spi, dev); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int ksz8795_spi_remove(struct spi_device *spi) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct ksz_device *dev = spi_get_drvdata(spi); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (dev) 688c2ecf20Sopenharmony_ci ksz_switch_remove(dev); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void ksz8795_spi_shutdown(struct spi_device *spi) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct ksz_device *dev = spi_get_drvdata(spi); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (dev && dev->dev_ops->shutdown) 788c2ecf20Sopenharmony_ci dev->dev_ops->shutdown(dev); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const struct of_device_id ksz8795_dt_ids[] = { 828c2ecf20Sopenharmony_ci { .compatible = "microchip,ksz8765" }, 838c2ecf20Sopenharmony_ci { .compatible = "microchip,ksz8794" }, 848c2ecf20Sopenharmony_ci { .compatible = "microchip,ksz8795" }, 858c2ecf20Sopenharmony_ci {}, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ksz8795_dt_ids); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct spi_device_id ksz8795_spi_ids[] = { 908c2ecf20Sopenharmony_ci { "ksz8765" }, 918c2ecf20Sopenharmony_ci { "ksz8794" }, 928c2ecf20Sopenharmony_ci { "ksz8795" }, 938c2ecf20Sopenharmony_ci { "ksz8863" }, 948c2ecf20Sopenharmony_ci { "ksz8873" }, 958c2ecf20Sopenharmony_ci { }, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic struct spi_driver ksz8795_spi_driver = { 1008c2ecf20Sopenharmony_ci .driver = { 1018c2ecf20Sopenharmony_ci .name = "ksz8795-switch", 1028c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1038c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(ksz8795_dt_ids), 1048c2ecf20Sopenharmony_ci }, 1058c2ecf20Sopenharmony_ci .id_table = ksz8795_spi_ids, 1068c2ecf20Sopenharmony_ci .probe = ksz8795_spi_probe, 1078c2ecf20Sopenharmony_ci .remove = ksz8795_spi_remove, 1088c2ecf20Sopenharmony_ci .shutdown = ksz8795_spi_shutdown, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cimodule_spi_driver(ksz8795_spi_driver); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>"); 1148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microchip KSZ8795 Series Switch SPI Driver"); 1158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 116