fschmd.c

来自「linux 内核源代码」· C语言 代码 · 共 779 行 · 第 1/2 页

C
779
字号
static ssize_t store_pwm_auto_point1_pwm(struct device *dev,	struct device_attribute *devattr, const char *buf, size_t count){	int index = to_sensor_dev_attr(devattr)->index;	struct fschmd_data *data = dev_get_drvdata(dev);	unsigned long v = simple_strtoul(buf, NULL, 10);	/* register: 0 = allow turning off, 1-255 = 50-100% */	if (v) {		v = SENSORS_LIMIT(v, 128, 255);		v = (v - 128) * 2 + 1;	}	mutex_lock(&data->update_lock);	i2c_smbus_write_byte_data(&data->client,		FSCHMD_REG_FAN_MIN[data->kind][index], v);	data->fan_min[index] = v;	mutex_unlock(&data->update_lock);	return count;}/* The FSC hwmon family has the ability to force an attached alert led to flash   from software, we export this as an alert_led sysfs attr */static ssize_t show_alert_led(struct device *dev,	struct device_attribute *devattr, char *buf){	struct fschmd_data *data = fschmd_update_device(dev);	if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)		return sprintf(buf, "1\n");	else		return sprintf(buf, "0\n");}static ssize_t store_alert_led(struct device *dev,	struct device_attribute *devattr, const char *buf, size_t count){	u8 reg;	struct fschmd_data *data = dev_get_drvdata(dev);	unsigned long v = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);	if (v)		reg |= FSCHMD_CONTROL_ALERT_LED_MASK;	else		reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;	i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);	data->global_control = reg;	mutex_unlock(&data->update_lock);	return count;}static struct sensor_device_attribute fschmd_attr[] = {	SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),	SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),	SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),	SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),};static struct sensor_device_attribute fschmd_temp_attr[] = {	SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),	SENSOR_ATTR(temp1_max,   0644, show_temp_max, store_temp_max, 0),	SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),	SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),	SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),	SENSOR_ATTR(temp2_max,   0644, show_temp_max, store_temp_max, 1),	SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),	SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),	SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),	SENSOR_ATTR(temp3_max,   0644, show_temp_max, store_temp_max, 2),	SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),	SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),	SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),	SENSOR_ATTR(temp4_max,   0644, show_temp_max, store_temp_max, 3),	SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),	SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),	SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),	SENSOR_ATTR(temp5_max,   0644, show_temp_max, store_temp_max, 4),	SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),	SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),};static struct sensor_device_attribute fschmd_fan_attr[] = {	SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),	SENSOR_ATTR(fan1_div,   0644, show_fan_div, store_fan_div, 0),	SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),	SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),	SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 0),	SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),	SENSOR_ATTR(fan2_div,   0644, show_fan_div, store_fan_div, 1),	SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),	SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),	SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 1),	SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),	SENSOR_ATTR(fan3_div,   0644, show_fan_div, store_fan_div, 2),	SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),	SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),	SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 2),	SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),	SENSOR_ATTR(fan4_div,   0644, show_fan_div, store_fan_div, 3),	SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),	SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),	SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 3),	SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),	SENSOR_ATTR(fan5_div,   0644, show_fan_div, store_fan_div, 4),	SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),	SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),	SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 4),	SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),	SENSOR_ATTR(fan6_div,   0644, show_fan_div, store_fan_div, 5),	SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),	SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),	SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,		store_pwm_auto_point1_pwm, 5),};/* * Real code */static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *client;	struct fschmd_data *data;	u8 revision;	const char * const names[5] = { "Poseidon", "Hermes", "Scylla",					"Heracles", "Heimdall" };	const char * const client_names[5] = { "fscpos", "fscher", "fscscy",						"fschrc", "fschmd" };	int i, err = 0;	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))		return 0;	/* OK. For now, we presume we have a valid client. We now create the	 * client structure, even though we cannot fill it completely yet.	 * But it allows us to access i2c_smbus_read_byte_data. */	if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))		return -ENOMEM;	client = &data->client;	i2c_set_clientdata(client, data);	client->addr = address;	client->adapter = adapter;	client->driver = &fschmd_driver;	mutex_init(&data->update_lock);	/* Detect & Identify the chip */	if (kind <= 0) {		char id[4];		id[0] = i2c_smbus_read_byte_data(client,				FSCHMD_REG_IDENT_0);		id[1] = i2c_smbus_read_byte_data(client,				FSCHMD_REG_IDENT_1);		id[2] = i2c_smbus_read_byte_data(client,				FSCHMD_REG_IDENT_2);		id[3] = '\0';		if (!strcmp(id, "PEG"))			kind = fscpos;		else if (!strcmp(id, "HER"))			kind = fscher;		else if (!strcmp(id, "SCY"))			kind = fscscy;		else if (!strcmp(id, "HRC"))			kind = fschrc;		else if (!strcmp(id, "HMD"))			kind = fschmd;		else			goto exit_free;	}	if (kind == fscpos) {		/* The Poseidon has hardwired temp limits, fill these		   in for the alarm resetting code */		data->temp_max[0] = 70 + 128;		data->temp_max[1] = 50 + 128;		data->temp_max[2] = 50 + 128;	}	/* i2c kind goes from 1-5, we want from 0-4 to address arrays */	data->kind = kind - 1;	strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(client)))		goto exit_free;	for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {		err = device_create_file(&client->dev,					&fschmd_attr[i].dev_attr);		if (err)			goto exit_detach;	}	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {		/* Poseidon doesn't have TEMP_LIMIT registers */		if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==				show_temp_max)			continue;		err = device_create_file(&client->dev,					&fschmd_temp_attr[i].dev_attr);		if (err)			goto exit_detach;	}	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {		/* Poseidon doesn't have a FAN_MIN register for its 3rd fan */		if (kind == fscpos &&				!strcmp(fschmd_fan_attr[i].dev_attr.attr.name,					"pwm3_auto_point1_pwm"))			continue;		err = device_create_file(&client->dev,					&fschmd_fan_attr[i].dev_attr);		if (err)			goto exit_detach;	}	data->hwmon_dev = hwmon_device_register(&client->dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		data->hwmon_dev = NULL;		goto exit_detach;	}	revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);	printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",		names[data->kind], (int) revision);	return 0;exit_detach:	fschmd_detach_client(client); /* will also free data for us */	return err;exit_free:	kfree(data);	return err;}static int fschmd_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON))		return 0;	return i2c_probe(adapter, &addr_data, fschmd_detect);}static int fschmd_detach_client(struct i2c_client *client){	struct fschmd_data *data = i2c_get_clientdata(client);	int i, err;	/* Check if registered in case we're called from fschmd_detect	   to cleanup after an error */	if (data->hwmon_dev)		hwmon_device_unregister(data->hwmon_dev);	for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)		device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);	for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)		device_remove_file(&client->dev,					&fschmd_temp_attr[i].dev_attr);	for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)		device_remove_file(&client->dev,					&fschmd_fan_attr[i].dev_attr);	if ((err = i2c_detach_client(client)))		return err;	kfree(data);	return 0;}static struct fschmd_data *fschmd_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct fschmd_data *data = i2c_get_clientdata(client);	int i;	mutex_lock(&data->update_lock);	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {		for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {			data->temp_act[i] = i2c_smbus_read_byte_data(client,					FSCHMD_REG_TEMP_ACT[data->kind][i]);			data->temp_status[i] = i2c_smbus_read_byte_data(client,					FSCHMD_REG_TEMP_STATE[data->kind][i]);			/* The fscpos doesn't have TEMP_LIMIT registers */			if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])				data->temp_max[i] = i2c_smbus_read_byte_data(					client,					FSCHMD_REG_TEMP_LIMIT[data->kind][i]);			/* reset alarm if the alarm condition is gone,			   the chip doesn't do this itself */			if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==					FSCHMD_TEMP_ALARM_MASK &&					data->temp_act[i] < data->temp_max[i])				i2c_smbus_write_byte_data(client,					FSCHMD_REG_TEMP_STATE[data->kind][i],					FSCHMD_TEMP_ALERT_MASK);		}		for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {			data->fan_act[i] = i2c_smbus_read_byte_data(client,					FSCHMD_REG_FAN_ACT[data->kind][i]);			data->fan_status[i] = i2c_smbus_read_byte_data(client,					FSCHMD_REG_FAN_STATE[data->kind][i]);			data->fan_ripple[i] = i2c_smbus_read_byte_data(client,					FSCHMD_REG_FAN_RIPPLE[data->kind][i]);			/* The fscpos third fan doesn't have a fan_min */			if (FSCHMD_REG_FAN_MIN[data->kind][i])				data->fan_min[i] = i2c_smbus_read_byte_data(					client,					FSCHMD_REG_FAN_MIN[data->kind][i]);			/* reset fan status if speed is back to > 0 */			if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&					data->fan_act[i])				i2c_smbus_write_byte_data(client,					FSCHMD_REG_FAN_STATE[data->kind][i],					FSCHMD_FAN_ALARM_MASK);		}		for (i = 0; i < 3; i++)			data->volt[i] = i2c_smbus_read_byte_data(client,						FSCHMD_REG_VOLT[i]);		data->global_control = i2c_smbus_read_byte_data(client,						FSCHMD_REG_CONTROL);		/* To be implemented in the future		data->watchdog[0] = i2c_smbus_read_byte_data(client,						FSCHMD_REG_WDOG_PRESET);		data->watchdog[1] = i2c_smbus_read_byte_data(client,						FSCHMD_REG_WDOG_STATE);		data->watchdog[2] = i2c_smbus_read_byte_data(client,						FSCHMD_REG_WDOG_CONTROL); */		data->last_updated = jiffies;		data->valid = 1;	}	mutex_unlock(&data->update_lock);	return data;}static int __init fschmd_init(void){	return i2c_add_driver(&fschmd_driver);}static void __exit fschmd_exit(void){	i2c_del_driver(&fschmd_driver);}MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "			"Heimdall driver");MODULE_LICENSE("GPL");module_init(fschmd_init);module_exit(fschmd_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?