Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212// SPDX-License-Identifier: GPL-2.0+/* * Airoha Ethernet PHY common library * * Copyright (C) 2026 Airoha Technology Corp. * Copyright (C) 2026 Collabora Ltd. * Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com> */
#include <linux/export.h>#include <linux/module.h>#include <linux/phy.h>#include <linux/wordpart.h>
#include "air_phy_lib.h"
static int __air_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, u32 *pbus_data){ int pbus_data_low, pbus_data_high; int ret;
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, upper_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, lower_16_bits(pbus_address)); if (ret < 0) return ret;
pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); if (pbus_data_high < 0) return pbus_data_high;
pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); if (pbus_data_low < 0) return pbus_data_low;
*pbus_data = pbus_data_low | (pbus_data_high << 16); return 0;}
static int __air_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, u32 pbus_data){ int ret;
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, upper_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, lower_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, upper_16_bits(pbus_data)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, lower_16_bits(pbus_data)); if (ret < 0) return ret;
return 0;}
static int __air_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, u32 mask, u32 set){ int pbus_data_low, pbus_data_high; u32 pbus_data_old, pbus_data_new; int ret;
ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH, upper_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW, lower_16_bits(pbus_address)); if (ret < 0) return ret;
pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH); if (pbus_data_high < 0) return pbus_data_high;
pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW); if (pbus_data_low < 0) return pbus_data_low;
pbus_data_old = pbus_data_low | (pbus_data_high << 16); pbus_data_new = (pbus_data_old & ~mask) | set; if (pbus_data_new == pbus_data_old) return 0;
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH, upper_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW, lower_16_bits(pbus_address)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH, upper_16_bits(pbus_data_new)); if (ret < 0) return ret;
ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW, lower_16_bits(pbus_data_new)); if (ret < 0) return ret;
return 0;}
int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, u32 *pbus_data){ int saved_page; int ret = 0;
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
if (saved_page >= 0) { ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); }
return phy_restore_page(phydev, saved_page, ret);}EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_read);
int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, u32 pbus_data){ int saved_page; int ret = 0;
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
if (saved_page >= 0) { ret = __air_buckpbus_reg_write(phydev, pbus_address, pbus_data); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); }
return phy_restore_page(phydev, saved_page, ret);}EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_write);
int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, u32 mask, u32 set){ int saved_page; int ret = 0;
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
if (saved_page >= 0) { ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, set); if (ret < 0) phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__, pbus_address, ret); }
return phy_restore_page(phydev, saved_page, ret);}EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_modify);
int air_phy_read_page(struct phy_device *phydev){ return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);}EXPORT_SYMBOL_GPL(air_phy_read_page);
int air_phy_write_page(struct phy_device *phydev, int page){ return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);}EXPORT_SYMBOL_GPL(air_phy_write_page);
MODULE_DESCRIPTION("Airoha PHY Library");MODULE_LICENSE("GPL");MODULE_AUTHOR("Louis-Alexis Eyraud");