162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic polynomial calculation using integer coefficients. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: 862306a36Sopenharmony_ci * Maxim Kaurkin <maxim.kaurkin@baikalelectronics.ru> 962306a36Sopenharmony_ci * Serge Semin <Sergey.Semin@baikalelectronics.ru> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/polynomial.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Originally this was part of drivers/hwmon/bt1-pvt.c. 1962306a36Sopenharmony_ci * There the following conversion is used and should serve as an example here: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The original translation formulae of the temperature (in degrees of Celsius) 2262306a36Sopenharmony_ci * to PVT data and vice-versa are following: 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * N = 1.8322e-8*(T^4) + 2.343e-5*(T^3) + 8.7018e-3*(T^2) + 3.9269*(T^1) + 2562306a36Sopenharmony_ci * 1.7204e2 2662306a36Sopenharmony_ci * T = -1.6743e-11*(N^4) + 8.1542e-8*(N^3) + -1.8201e-4*(N^2) + 2762306a36Sopenharmony_ci * 3.1020e-1*(N^1) - 4.838e1 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * where T = [-48.380, 147.438]C and N = [0, 1023]. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * They must be accordingly altered to be suitable for the integer arithmetics. 3262306a36Sopenharmony_ci * The technique is called 'factor redistribution', which just makes sure the 3362306a36Sopenharmony_ci * multiplications and divisions are made so to have a result of the operations 3462306a36Sopenharmony_ci * within the integer numbers limit. In addition we need to translate the 3562306a36Sopenharmony_ci * formulae to accept millidegrees of Celsius. Here what they look like after 3662306a36Sopenharmony_ci * the alterations: 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * N = (18322e-20*(T^4) + 2343e-13*(T^3) + 87018e-9*(T^2) + 39269e-3*T + 3962306a36Sopenharmony_ci * 17204e2) / 1e4 4062306a36Sopenharmony_ci * T = -16743e-12*(D^4) + 81542e-9*(D^3) - 182010e-6*(D^2) + 310200e-3*D - 4162306a36Sopenharmony_ci * 48380 4262306a36Sopenharmony_ci * where T = [-48380, 147438] mC and N = [0, 1023]. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * static const struct polynomial poly_temp_to_N = { 4562306a36Sopenharmony_ci * .total_divider = 10000, 4662306a36Sopenharmony_ci * .terms = { 4762306a36Sopenharmony_ci * {4, 18322, 10000, 10000}, 4862306a36Sopenharmony_ci * {3, 2343, 10000, 10}, 4962306a36Sopenharmony_ci * {2, 87018, 10000, 10}, 5062306a36Sopenharmony_ci * {1, 39269, 1000, 1}, 5162306a36Sopenharmony_ci * {0, 1720400, 1, 1} 5262306a36Sopenharmony_ci * } 5362306a36Sopenharmony_ci * }; 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * static const struct polynomial poly_N_to_temp = { 5662306a36Sopenharmony_ci * .total_divider = 1, 5762306a36Sopenharmony_ci * .terms = { 5862306a36Sopenharmony_ci * {4, -16743, 1000, 1}, 5962306a36Sopenharmony_ci * {3, 81542, 1000, 1}, 6062306a36Sopenharmony_ci * {2, -182010, 1000, 1}, 6162306a36Sopenharmony_ci * {1, 310200, 1000, 1}, 6262306a36Sopenharmony_ci * {0, -48380, 1, 1} 6362306a36Sopenharmony_ci * } 6462306a36Sopenharmony_ci * }; 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/** 6862306a36Sopenharmony_ci * polynomial_calc - calculate a polynomial using integer arithmetic 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * @poly: pointer to the descriptor of the polynomial 7162306a36Sopenharmony_ci * @data: input value of the polynimal 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Calculate the result of a polynomial using only integer arithmetic. For 7462306a36Sopenharmony_ci * this to work without too much loss of precision the coefficients has to 7562306a36Sopenharmony_ci * be altered. This is called factor redistribution. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Returns the result of the polynomial calculation. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cilong polynomial_calc(const struct polynomial *poly, long data) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci const struct polynomial_term *term = poly->terms; 8262306a36Sopenharmony_ci long total_divider = poly->total_divider ?: 1; 8362306a36Sopenharmony_ci long tmp, ret = 0; 8462306a36Sopenharmony_ci int deg; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Here is the polynomial calculation function, which performs the 8862306a36Sopenharmony_ci * redistributed terms calculations. It's pretty straightforward. 8962306a36Sopenharmony_ci * We walk over each degree term up to the free one, and perform 9062306a36Sopenharmony_ci * the redistributed multiplication of the term coefficient, its 9162306a36Sopenharmony_ci * divider (as for the rationale fraction representation), data 9262306a36Sopenharmony_ci * power and the rational fraction divider leftover. Then all of 9362306a36Sopenharmony_ci * this is collected in a total sum variable, which value is 9462306a36Sopenharmony_ci * normalized by the total divider before being returned. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci do { 9762306a36Sopenharmony_ci tmp = term->coef; 9862306a36Sopenharmony_ci for (deg = 0; deg < term->deg; ++deg) 9962306a36Sopenharmony_ci tmp = mult_frac(tmp, data, term->divider); 10062306a36Sopenharmony_ci ret += tmp / term->divider_leftover; 10162306a36Sopenharmony_ci } while ((term++)->deg); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return ret / total_divider; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(polynomial_calc); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciMODULE_DESCRIPTION("Generic polynomial calculations"); 10862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 109