/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019 CERN * Author: Federico Vaga <federico.vaga@cern.ch> */ #include <linux/device.h> #include <linux/i2c.h> #include <linux/idr.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/version.h> #if KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE #include <linux/platform_data/at24.h> #else #include <linux/i2c/at24.h> #endif #ifndef _LINUX_FMC_H #define _LINUX_FMC_H struct fmc_carrier; struct fmc_slot; #define FMC_SLOT_MAX_I2C 4 /* * According to the standard, the EEPROM form a mezzanine must be * at address 0x50 to 0x53 */ #define FMC_EEPROM_ADDR_SPACE 0x50 /** * Convert a Geographical Address suffix into an I2C address * @ga: geographical address * * Return: an I2C address suffix * * Geographical address must be translated into a proper address * * Observation 5.22 * GA[0] -> Address[1] * GA[1] -> Address[0] */ static inline uint8_t fmc_ga_to_i2c_addr(uint8_t ga) { return ((((ga >> 1) & 0x1) | ((ga & 0x1) << 1)) & 0x3); } /** * Fix given address with the FMC geographical address * @addr: an address * @ga: geographical address to apply * * Return: a fixed address */ static inline uint8_t fmc_slot_i2c_address(uint8_t addr, uint8_t ga) { return (addr & ~0x3) | fmc_ga_to_i2c_addr(ga); } /** * struct fmc_slot - FMC slot instance. * * @dev: FMC slot device * @adapter: I2C bus adapter used to communicate with the slot * @ga: Geographical Address according to FMC standard * @lun: slot logical unit number * @eeprom: I2C adapter used to talk with the mezzanine eeprom * @macc: operations to access the mezzanine EEPROM * @at24_data: data for the EEPROM driver * * The FMC standard does not say that all the FMC slots are on the same * I2C bus. So, we must foresee that this is not the case and each FMC * slot has a dedicated I2C bus (but using different I2C address for * each slot in theory). */ struct fmc_slot { struct device dev; struct i2c_adapter *adapter; uint8_t ga; uint8_t lun; struct i2c_client *eeprom; struct memory_accessor *macc; struct at24_platform_data at24_data; }; /** * struct fmc_flot_info - information for adding new slots * @i2c_bus_nr: I2C bus number * @ga: Geographical Address according to FMC standard * @lun: slot logical unit number */ struct fmc_slot_info { int i2c_bus_nr; uint8_t ga; uint8_t lun; }; /** * Get an FMC slot from its Linux device * @dev_ptr: pointer to device structure * * Return: correspondent fmc_carrier structure */ static inline struct fmc_slot *to_fmc_slot(struct device *dev_ptr) { return container_of(dev_ptr, struct fmc_slot, dev); } struct fmc_slot *fmc_slot_get(struct device *parent, unsigned int lun); void fmc_slot_put(struct fmc_slot *slot); int fmc_slot_present(struct fmc_slot *slot); int fmc_slot_fru_valid(struct fmc_slot *slot); ssize_t fmc_slot_eeprom_read(struct fmc_slot *slot, void *buf, off_t offset, size_t count); /** * sturct fmc_carrier_operations - FMC operations for carriers * @owner: the module that will execute the operations * @is_present: check if an FMC slot is present or not in the slot * (present: 1, not present or error: 0). The carrier * must check PRSNT_M2C_L (VITA 57.1 Rule 5.76) */ struct fmc_carrier_operations { struct module *owner; int (*is_present)(struct fmc_carrier *carrier, struct fmc_slot *slot); }; /** * struct fmc_carrier - FMC carrier instance * @dev: FMC carrier device instance * @ops: list of operations for FMC * @slot_nr: number of maximum slots available * @slot: list of slot's pointers. * @priv: private data */ struct fmc_carrier { struct device dev; const struct fmc_carrier_operations *ops; unsigned int slot_nr; struct fmc_slot **slot; void *priv; }; /** * Get an FMC carrier from its Linux device * @dev_ptr: pointer to device structure * * Return: correspondent fmc_carrier structure */ static inline struct fmc_carrier *to_fmc_carrier(struct device *dev_ptr) { return container_of(dev_ptr, struct fmc_carrier, dev); } struct fmc_carrier *fmc_carrier_get(struct device *parent); void fmc_carrier_put(struct fmc_carrier *carrier); int fmc_carrier_register(struct device *parent, const struct fmc_carrier_operations *ops, unsigned int nr_slot, struct fmc_slot_info *slot_info, void *priv); int fmc_carrier_unregister(struct device *parent); int fmc_slot_eeprom_type_set(struct fmc_slot *slot, const char *type); const char *fmc_slot_eeprom_type_get(struct fmc_slot *slot); #endif