Newer
Older
/* 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(5, 1, 0) > LINUX_VERSION_CODE
#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
*/
/**
* 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);
}
/**
* @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
*
* 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;
#if KERNEL_VERSION(4, 6, 0) <= LINUX_VERSION_CODE
#define AT24_NUM_PROPERTIES 4
struct property_entry at24_data[AT24_NUM_PROPERTIES];
struct nvmem_device *nvmem;
struct memory_accessor *macc;
struct at24_platform_data at24_data;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
};
/**
* 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);
/**
* struct fmc_carrier_operations - FMC operations for carriers
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
* @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